在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':由于未标记为“virtual”,“abstract”或“override”,因此无法覆盖继承的成员'function2'

如果你不使用覆盖你会得到CS0108的警告'desc.Method()'隐藏了继承的成员'base.Method()'如果隐藏的目的是使用新的关键字。

为了解决这个问题,将new关键字放在您隐藏的方法前面。

例如

  new public double Area() 
  {
     return 2*pi*x*x + 2*pi*x*y; 
  }

..是否必须重写派生类中的虚方法?
不,如果你不覆盖该方法,后代类将使用它继承的方法。


理解虚拟函数的实际用法的关键是要记住,某个类的对象可以被赋予来自第一个对象的类的另一个类的对象。

例如:

class Animal {
   public void eat() {...}
}

class FlyingAnimal : Animal {
   public void eat() {...}
}

Animal a = new FlyingAnimal();

Animal类有一个函数eat() ,它通常描述动物应该如何吃(例如将物体放入口中并吞下)。

然而, FlyingAnimal类应该定义一个新的eat()方法,因为飞行动物有特定的饮食方式。

这样说到这里想到的问题是:当我声明的变量a类的Animal和asigned这类型的新对象FlyingAnimal ,你会a.eat()吗? 这两种方法中的哪一种被称为?

这里的答案是:因为aAnimal类型,它会调用Animal的方法。 编译器是愚蠢的,不知道你打算将另一个类的对象分配给a变量。

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

因此,只有在代码执行时,系统会看a内容在其声明的类型不是类型和执行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();
}

正如你所看到的,每只动物都有自己的吃法。 只有使用虚拟功能,才能实现此功能。 否则,每个人都会被迫以完全相同的方式“吃”,正如Animal类中最常用的eat功能所描述的那样。

编辑:这种行为实际上是默认的普通的高级语言,如Java。


像其他语言一样..当你想要多态。 这有很多的用法。 例如,您想要抽象从控制台或文件或其他设备读取输入的方式。 你可以有一个通用的阅读器接口,然后是使用虚拟函数的多个具体实现。

链接地址: http://www.djcxy.com/p/38117.html

上一篇: Practical usage of virtual functions in c#

下一篇: How to have a default method while still be able to override it?