在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()方法,因为飞行动物有特定的饮食方式。

所以这里想到的问题是:在我声明了Animaltypes的variablesa并将其赋值a FlyingAnimaltypes的新对象FlyingAnimala.eat()做什么? 哪两种方法被称为?

这里的答案是:因为aAnimal的types,所以它会调用Animal的方法。 编译器是愚蠢的,不知道你是否将另一个类的对象分配给avariables。

这里是virtual关键字的作用:如果你声明方法为virtual void eat() {...} ,你基本上是告诉编译器“小心我在这里做了一些聪明的事情,你不能处理,因为你不那么聪明“。 所以编译器不会尝试将调用a.eat()链接到两个方法中的任一个,而是告诉系统在运行时执行它!

所以只有当代码执行的时候,系统才会查看a 内容types,而不是它的声明types,并执行FlyingAnimal的方法。

你可能会想:为什么我要这样做? 为什么不从头FlyingAnimal a = new FlyingAnimal()

其原因是,例如,你可能有许多来自Animal派生类: FlyingAnimalSwimmingAnimalBigAnimalWhiteDog等等。一旦你想要定义一个包含许多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类中最常用的eatfunction所描述的那样。

编辑:这种行为实际上是默认的普通的高级语言,如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调用的函数。