在c#中实际使用虚函数
c#中虚函数的实际用法是什么?
所以基本上,如果在你的祖先类,你想要一个方法的某种行为。 如果你的后代使用相同的方法,但有不同的实现,你可以覆盖它,如果它有一个虚拟的关键字。
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; } } public 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()); } }
编辑:评论中的问题
如果我不在基类中使用虚拟关键字,它会工作吗?
如果你在派生类中使用override
关键字,它将不起作用。 您将生成编译器错误CS0506 “function1”:由于未标记为“虚拟”,“抽象”或“覆盖”,因此无法覆盖inheritance的成员“function2”
如果你不使用覆盖你会得到CS0108警告'desc.Method()'隐藏inheritance成员'base.Method()'如果隐藏的目的是使用新的关键字。
为了解决这个问题,把new
关键字放在你隐藏的方法的前面。
例如
new public double Area() { return 2*pi*x*x + 2*pi*x*y; }
..是否必须重写派生类中的虚拟方法?
不,如果你不重写方法,后代类将使用它inheritance的方法。
理解虚拟函数的实际用法的关键是要记住,某个类的对象可以被赋予从第一个对象的类派生的类的另一个对象。
例如:
class Animal { public void eat() {...} } class FlyingAnimal : Animal { public void eat() {...} } Animal a = new FlyingAnimal();
Animal
类有一个函数eat()
,通常描述动物应该如何吃(例如把物体放在嘴里,吞下)。
然而, FlyingAnimal
类应该定义一个新的eat()
方法,因为飞行动物有特定的饮食方式。
所以这里想到的问题是:在我声明了Animal
types的variablesa
并将其赋值a
FlyingAnimaltypes的新对象FlyingAnimal
, a.eat()
做什么? 哪两种方法被称为?
这里的答案是:因为a
是Animal
的types,所以它会调用Animal
的方法。 编译器是愚蠢的,不知道你是否将另一个类的对象分配给a
variables。
这里是virtual
关键字的作用:如果你声明方法为virtual void eat() {...}
,你基本上是告诉编译器“小心我在这里做了一些聪明的事情,你不能处理,因为你不那么聪明“。 所以编译器不会尝试将调用a.eat()
链接到两个方法中的任一个,而是告诉系统在运行时执行它!
所以只有当代码执行的时候,系统才会查看a
内容types,而不是它的声明types,并执行FlyingAnimal
的方法。
你可能会想:为什么我要这样做? 为什么不从头FlyingAnimal a = new FlyingAnimal()
?
其原因是,例如,你可能有许多来自Animal
派生类: FlyingAnimal
, SwimmingAnimal
, BigAnimal
, WhiteDog
等等。一旦你想要定义一个包含许多Animal
的世界,所以你说:
Animal[] happy_friends = new Animal[100];
我们有一个有100个快乐动物的世界。 你在某个时候初始化它们:
... happy_friends[2] = new AngryFish(); ... happy_friends[10] = new LoudSnake(); ...
而在一天结束的时候,你希望大家在睡觉之前吃东西。 所以你想说:
for (int i=0; i<100; i++) { happy_friends[i].eat(); }
正如你所看到的,每只动物都有自己的吃法。 只有使用虚函数才能实现这个function。 否则,每个人都会被迫以同样的方式“吃”,正如Animal
类中最常用的eat
function所描述的那样。
编辑:这种行为实际上是默认的普通的高级语言,如Java。
像任何其他语言..当你想多态。 这有很多的用法。 例如,您要抽象从控制台或文件或其他设备读取input的方式。 你可以有一个通用的阅读器接口,然后是使用虚函数的多个具体实现。
例如代理方法。 即在运行时覆盖方法。 例如,NHibernate使用它来支持延迟加载。
它用来告诉派生类可以覆盖该函数。
MSDN 在这里有一个很好的例子。
基本上虚拟成员允许你表示多态,一个派生类可以有一个和它的基类中的方法具有相同签名的方法,基类将调用派生类的方法。
一个基本的例子:
public class Shape { // A few example members public int X { get; private set; } public int Y { get; private set; } public int Height { get; set; } public int Width { get; set; } // Virtual method public virtual void Draw() { Console.WriteLine("Performing base class drawing tasks"); } } class Circle : Shape { public override void Draw() { // Code to draw a circle... Console.WriteLine("Drawing a circle"); base.Draw(); } } class Rectangle : Shape { public override void Draw() { // Code to draw a rectangle... Console.WriteLine("Drawing a rectangle"); base.Draw(); } } class Triangle : Shape { public override void Draw() { // Code to draw a triangle... Console.WriteLine("Drawing a triangle"); base.Draw(); } }
这允许实现后期绑定,这意味着在运行时而不是在编译时确定哪个对象的成员将被调用。 参见维基百科 。
从这里 :
在面向对象编程中,虚拟函数或虚拟方法是一个函数或方法,其行为可以通过具有相同签名的函数在inheritance类中重写。
例如,你有一个基类Params和一组派生类。 您希望能够对存储从params派生的所有可能的类的数组执行相同的操作。
没问题 – 声明虚方法,向Params类添加一些基本的实现,并在派生类中覆盖它。 现在,您可以遍历数组并通过引用调用方法 – 将调用正确的方法。
class Params { public: virtual void Manipulate() { //basic impl here } } class DerivedParams1 : public Params { public: override void Manipulate() { base.Manipulate(); // other statements here } }; // more derived classes can do the same void ManipulateAll( Params[] params ) { for( int i = 0; i < params.Length; i++ ) { params[i].Manipulate(); } }
在c#中使用虚函数
虚拟函数主要用于覆盖具有相同签名的派生类中的基类方法。
当派生类inheritance基类时,派生类的对象是对派生类或基类的引用。
虚拟function由编译器延迟解决(即运行时绑定)
在基类中virtual
,根据引用的对象的实际types调用派生类最多的类的实现,而不pipe指针或引用的声明types如何。 如果不是virtual
,则方法early
解决,并根据声明的指针或引用typesselect调用的函数。