作者:倒转流年1990 | 来源:互联网 | 2023-10-15 10:48
大家好,小弟正在学习C#,现在学的是蒙蒙呼呼的,觉得:虚函数(Virtual),抽象函数(abstract)和接口他们不都是只提供函数名称,然后再类中去实现代码吗?为什么要有这么多呢?请大家帮忙分
大家好,小弟正在学习C#,现在学的是蒙蒙呼呼的,觉得:虚函数(Virtual),抽象函数(abstract)和接口他们不都是只提供函数名称,然后再类中去实现代码吗?为什么要有这么多呢?
请大家帮忙分析它们之间的不同,最好有个例子,或者是能说明白,这三个东西分别在什么时候用。
31 个解决方案
sf自己坐,我在C#怎么也有五个星?没在这儿回答过问题啊。
唉!惭愧啊!
1.虚函数(Virtual),可以写方法的实现,不一定要被继承。抽象函数(abstract)不能写方法的实现,必须被继承
接口与纯抽象函数类似。它只能包含抽象方法,而不能包含任何实现方法,不能创建接口的实例。
虛函數:由virtual聲明,它允許在派生類中被重寫,要重寫方法,必須先聲名為virtual
public class myclass
{
public virtual int myint()
{
函數体;
}
}
class myclass1:myclass
{
public override int myint()
{
函數体1;
}
}
抽象類、抽象函數:由abstract聲明,在抽象類中可以定義抽象方法,抽象方法基本沒有執行代碼,派生類必須重寫它,提供其執行代碼
public abstract class myclass
{
public abstract int myint();
}
public class myclass1:myclass
{
public override int myint()
{
函數体;
}
}
接口類:由interface聲明,是特殊的抽象類,是方法、屬性、事件和索引符的組合,沒有字段,其成員無執行方式,無構造函數,不允許進行運算符重載,接口和它的成員沒有任何訪問修飾符,它總是公共的,不能聲明為虛擬或靜態,繼承自接口的派生類必須實現接口中的所有方法
interface Imyinterface
{
void myfunction();
string name
{
get;
set;
}
}
class myclass:Imyinterface
{
void myfunction()
{
函數体;
}
string name
{
get
{
return name;
}
set
{
name=value;
}
}
}
http://www.0531s.com/www/9/2008-01/76841.html
看看有沒有能幫到你的
虛函式其實和抽象函式沒有什麽大的區別,只是虛函式可以像普通函式一樣可以在裏面寫程式碼.
編譯器會在編譯的時候適當的調用虛函式的複寫.
還有 要是你寫一個抽象函式,那麽這個抽象函式所在的類就必須是抽象類,抽象類沒有實體.
接口其實就是一個"樣板",那裏面寫著如果按照我這個"樣板"做自己的類,那麽你那個類裏就必須有什麽什麽函式,什麽什麽屬性等等.
而他自己本身只能有定義,有約定,就是不准有函式体.
接口中定義的各個函式根屬性都不能寫訪問修飾符.
接口本身不能不能實例化.
1.virtual:允许被重写,但不强制要求。声明时提供其自身实现;
2.abstract:强制要求其继承者重写。声明时不提供其自身的实现,抽象类不能被实例化;
3.interface:接口就是协议,其声明的成员(属性,方法,事件和索引器)必须由其继承的类实现。接口不能直接被实例化。
虚方法与抽象方法的区别在于,虚方法提供自身的实现,并且强制要求子类重写;而抽象方法不提供自身的实现,并且强制子类重写。
抽象类与接口很相似,但是思路不一样。接口是公开类的成员,而抽象类则是抽象类成员以要求子类继承并实现。
虚方法与抽象方法的区别在于,虚方法提供自身的实现,并且强制要求子类重写;而抽象方法不提供自身的实现,并且强制子类重写。
===============
虚方法 好象不要求子类必须重写吧?
虚方法 好象不要求子类必须重写吧?
------------------------------
呵呵,笔误。
virtual 关键字用于修改方法或属性的声明,在这种情况下,方法或属性被称作虚拟成员。虚拟成员的实现可由派生类中的重写成员更改。
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/csref/html/vclrfVirtualPG.htm
abstract 修饰符用于表示所修饰的类是不完整的,并且它只能用作基类。
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/csspec/html/vclrfcsharpspec_10_1_1_1.htm
interface
一个接口定义一个协定。实现接口的类或结构必须遵守其协定。
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/csref/html/vcrefTheInterfaceType.htm
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpguide/html/cpconInterfaces.htm
抽象类和接口
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/csspec/html/vclrfcsharpspec_13_4_5.htm
virtual(C# 参考)
virtual 关键字用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象。例如,此方法可被任何继承它的类重写。
public virtual double Area()
{
return x * y;
}
虚拟成员的实现可由派生类中的重写成员更改。有关使用 virtual 关键字的更多信息,请参见使用 Override 和 New 关键字控制版本(C# 编程指南)和了解何时使用 Override 和 New 关键字(C# 编程指南)。
调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。
默认情况下,方法是非虚拟的。不能重写非虚方法。
virtual 修饰符不能与 static、abstract 和 override 修饰符一起使用。
除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。
在静态属性上使用 virtual 修饰符是错误的。
通过包括使用 override 修饰符的属性声明,可在派生类中重写虚拟继承属性。
在该示例中,Dimensions 类包含 x 和 y 两个坐标和 Area() 虚方法。不同的形状类,如 Circle、Cylinder 和 Sphere 继承 Dimensions 类,并为每个图形计算表面积。每个派生类都有各自的 Area() 重写实现。根据与此方法关联的对象,通过调用正确的 Area() 实现,该程序为每个图形计算并显示正确的面积。
在前面的示例中,注意继承的类 Circle、Sphere 和 Cylinder 都使用了初始化基类的构造函数,例如:
public Cylinder(double r, double h): base(r, h) {}
// cs_virtual_keyword.cs
using System;
class TestClass
{
public class Dimensions
{
public const double PI = Math.PI;
protected double x, y;
public Dimensions()
{
}
public Dimensions(double x, double y)
{
this.x = x;
this.y = y;
}
public virtual double Area()
{
return x * y;
}
}
public class Circle : Dimensions
{
public Circle(double r) : base(r, 0)
{
}
public override double Area()
{
return PI * x * x;
}
}
class Sphere : Dimensions
{
public Sphere(double r) : base(r, 0)
{
}
public override double Area()
{
return 4 * PI * x * x;
}
}
class Cylinder : Dimensions
{
public Cylinder(double r, double h) : base(r, h)
{
}
public override double Area()
{
return 2 * PI * x * x + 2 * PI * x * y;
}
}
static void Main()
{
double r = 3.0, h = 5.0;
Dimensions c = new Circle(r);
Dimensions s = new Sphere(r);
Dimensions l = new Cylinder(r, h);
// Display results:
Console.WriteLine("Area of Circle = {0:F2}", c.Area());
Console.WriteLine("Area of Sphere = {0:F2}", s.Area());
Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
}
}
输出
Area of Circle = 28.27
Area of Sphere = 113.10
Area of Cylinder = 150.80
abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。
在此例中,类 Square 必须提供 Area 的实现,因为它派生自 ShapesClass:
abstract class ShapesClass
{
abstract public int Area();
}
class Square : ShapesClass
{
int x, y;
// Not providing an Area method results
// in a compile-time error.
public override int Area()
{
return x * y;
}
}
有关抽象类的更多信息,请参见抽象类、密封类及类成员(C# 编程指南)。
抽象类具有以下特性:
抽象类不能实例化。
抽象类可以包含抽象方法和抽象访问器。
不能用 sealed(C# 参考)修饰符修改抽象类,这意味着抽象类不能被继承。
从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。
在方法或属性声明中使用 abstract 修饰符以指示方法或属性不包含实现。
抽象方法具有以下特性:
抽象方法是隐式的虚方法。
只允许在抽象类中使用抽象方法声明。
因为抽象方法声明不提供实际的实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号 ({ })。例如:
public abstract void MyMethod();
实现由一个重写方法提供,此重写方法是非抽象类的成员。
在抽象方法声明中使用 static 或 virtual 修饰符是错误的。
除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。
在静态属性上使用 abstract 修饰符是错误的。
在派生类中,通过包括使用 override 修饰符的属性声明,可以重写抽象的继承属性。
抽象类必须为所有接口成员提供实现。
实现接口的抽象类可以将接口方法映射到抽象方法上。例如:
interface I
{
void M();
}
abstract class C: I
{
public abstract void M();
}
在本例中,DerivedClass 类是从抽象类 BaseClass 派生的。抽象类包含一个抽象方法 AbstractMethod 和两个抽象属性 X 和 Y。
// abstract_keyword.cs
// Abstract Classes
using System;
abstract class BaseClass // Abstract class
{
protected int _x = 100;
protected int _y = 150;
public abstract void AbstractMethod(); // Abstract method
public abstract int X { get; }
public abstract int Y { get; }
}
class DerivedClass : BaseClass
{
public override void AbstractMethod()
{
_x++;
_y++;
}
public override int X // overriding property
{
get
{
return _x + 10;
}
}
public override int Y // overriding property
{
get
{
return _y + 10;
}
}
static void Main()
{
DerivedClass o = new DerivedClass();
o.AbstractMethod();
Console.WriteLine("x = {0}, y = {1}", o.X, o.Y);
}
}
输出
x = 111, y = 161
在上面的示例中,如果试图通过使用下面的语句将抽象类实例化:
BaseClass bc = new BaseClass(); // Error
将出现错误,指出编译器无法创建抽象类“BaseClass”的实例。
看看这个帖子:http://topic.csdn.net/u/20080220/16/fedb74cd-95e1-4ab5-a2bb-934c3e9f017c.html
简单来说虚函数(Virtual)已经包含了也必须包含默认的实现,所以在派生类中可以重新实现也可以不实现这些虚函数。
抽象函数(abstract)没有提供默认实现,所以在派生类中
必须实现这些抽象函数。
接口中的函数类似于抽象函数,也不提供默认实现,实现接口的类也
必须实现这些函数。
但接口可用于多继承,即,类只能从一个类继承,但可同时实现多个接口。
抽象方法必须由派生的子类来实现
而虚方法派生的子类不一定会重写
虚方法在基类中可以有实现,但抽象方法不能。
虚方法可以在子类中不实现,但抽象方法必须在子类中全部实现。
虚方法提供了满足基本需要的代码,一般情况下不需要客户端重新写,如果满足不了,客户端可以覆盖。
抽象方法在抽象类中,通常抽象类提供模板方法的实现,模板方法需要一些接口,但是必须由客户端提供,抽象方法就是定义这些接口。
当觉得一个方法要实现什么功能,并且知道怎么实现功能的时候,用虚方法.
当知道方法要实现的功能,但对怎么实现不清楚的时候,用抽象方法
抽象方法是需要子类去实现的
虚方法,是已经实现了,子类可以去覆盖,也可以不覆盖