c#中虚函数的实际用法

时间:2021-03-01 22:33:09

What 's the practical usage of virtual functions in c#?

c#中虚函数的实际用法是什么?

9 个解决方案

#1


So basically if in your ancestor class you want a certain behaviour for a method. If your descendent uses the same method but has a different implementation you can override it, If it has a virtual keyword.

所以基本上如果在你的祖先类中你想要一个方法的特定行为。如果您的后代使用相同的方法但具有不同的实现,则可以覆盖它,如果它具有虚拟关键字。

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());
   }
}

Edit: Questions in comment
If I don't use virtual keyword in base class, will it work?

编辑:注释中的问题如果我不在基类中使用虚拟关键字,它会起作用吗?

If you use the override keyword in your descendent classes it will not work. You will generate compiler error CS0506 'function1' : cannot override inherited member 'function2' because it is not marked "virtual", "abstract", or "override"

如果在后代类中使用override关键字,则无效。您将生成编译器错误CS0506'function1':无法覆盖继承的成员'function2',因为它未标记为“虚拟”,“抽象”或“覆盖”

If you don't use the override You'll get the CS0108 warning 'desc.Method()' hides inherited member 'base.Method()' Use the new keyword if hiding was intended.

如果你不使用覆盖你会得到CS0108警告'desc.Method()'隐藏继承成员'base.Method()'如果想要隐藏,使用new关键字。

To get around this put the new keyword in front of the method you are hiding.

要解决此问题,请将新关键字放在您隐藏的方法之前。

e.g.

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

..and is it compulsory to override a virtual method in derived class?
No, if you don't override the method, the descendent class will use method it is inheriting from.

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

#2


The key to understanding the practical usage of virtual functions is to keep in mind that an object of a certain class can be assigned another object of a class derived from the first object's class.

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

E.g.:

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

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

Animal a = new FlyingAnimal();

The Animal class has a function eat() that generally describes how an animal should eat (e.g. put the object in mouth and swallow).

Animal类具有函数eat(),其通常描述动物应该如何进食(例如将物体放入口中并吞咽)。

However, the FlyingAnimal class should define a new eat() method, because flying animals have a particular way of eating.

但是,FlyingAnimal类应该定义一个新的eat()方法,因为飞行动物有一种特殊的吃法。

So the question that comes to mind here is: after I declared the variable a of type Animal and asigned it a new object of type FlyingAnimal, what will a.eat() do? Which of the two methods is called?

所以这里想到的问题是:在我声明变量类型为Animal并将其赋予一个类型为FlyingAnimal的新对象之后,a.eat()会做什么?这两种方法中的哪一种被称为?

The answer here is: because a is of type Animal, it will call Animal's method. The compiler is dumb and doesn't know that you are going to assign an object of another class to the a variable.

这里的答案是:因为a是Animal类型,它将调用Animal的方法。编译器很笨,并且不知道您要将另一个类的对象分配给变量。

Here is where the virtual keyword comes in action: if you declare the method as virtual void eat() {...}, you are basically telling the compiler "be careful that I am doing some clever stuff here that you cannot handle because you're not as smart". So the compiler will not attempt to link the call a.eat() to either of the two methods, but instead it tells the system to do it at runtime!

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

So only when the code executes, the system will look at a's content type not at its declared type and executes FlyingAnimal's method.

因此,只有在代码执行时,系统才会查看不是声明类型的内容类型,并执行FlyingAnimal的方法。

You may wonder: why the hell would I want to do that? Why not say right from the start FlyingAnimal a = new FlyingAnimal() ?

你可能想知道:为什么我要这么做呢?为什么不从一开始就说FlyingAnimal a = new FlyingAnimal()?

The reason for that is that, for example, you may have many derived classes from Animal: FlyingAnimal, SwimmingAnimal, BigAnimal, WhiteDog etc. And at one point you want to define a world containing many Animals, so you say:

这样做的原因是,例如,你可能有许多来自Animal的派生类:FlyingAnimal,SwimmingAnimal,BigAnimal,WhiteDog等。有一点你想要定义一个包含许多动物的世界,所以你说:

Animal[] happy_friends = new Animal[100];

We have a world with 100 happy animals. You initialize them at some point:

我们拥有100个快乐动物的世界。你在某个时候初始化它们:

...
happy_friends[2] = new AngryFish();
...
happy_friends[10] = new LoudSnake();
...

And at the end of the day, you want everybody to eat before they go to sleep. So you want to say:

在一天结束时,你希望每个人在睡觉前都能吃。所以你想说:

for (int i=0; i<100; i++) {
   happy_friends[i].eat();
}

So as you can see, each animal has its own method of eating. Only by using virtual functions can you achieve this functionality. Otherwise, everyone would be forced to "eat" in the exact same way: as described in the most general eat function inside the Animal class.

如你所见,每只动物都有自己的进食方法。只有使用虚拟功能才能实现此功能。否则,每个人都会*以完全相同的方式“吃”:如Animal类中最常用的eat函数所述。

EDIT: This behavior is actually default in common high-level languages like Java.

编辑:这种行为实际上是Java等常见高级语言的默认行为。

#3


Like any other language..when you want polymorphism. There are tons of usage for this. For example you want to abstract the way input is read from a console or a file or some other device. You can have a generic reader interface followed by multiple concrete implementations using virtual functions.

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

#4


e.g. proxying methods. i.e. overwriting methods at runtime. For example, NHibernate uses this to support lazy loading.

例如代理方法。即在运行时覆盖方法。例如,NHibernate使用它来支持延迟加载。

#5


Basically virtual members allow you to express polymorphism, a derived class can have a method with the same signature as the method in its base class, and the base class will call the derived class's method.

基本上虚拟成员允许您表达多态性,派生类可以具有与其基类中的方法具有相同签名的方法,并且基类将调用派生类的方法。

A basic example:

一个基本的例子:

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();
    }
}

#6


This allows to achieve late binding, meaning to determine at runtime rather than at compile-time which object's member will be invoked. See Wikipedia.

这允许实现后期绑定,这意味着在运行时而不是在编译时确定将调用哪个对象的成员。见*。

#7


From here:

In object-oriented programming, a virtual function or virtual method is a function or method whose behavior can be overridden within an inheriting class by a function with the same signature.

在面向对象的编程中,虚函数或虚方法是一种函数或方法,其行为可以通过具有相同签名的函数在继承类中重写。

#8


For example you have a base class Params and a set of derived classes. You want to be able to perform the same operation on an array that stores all possible classes derived from params.

例如,您有一个基类Params和一组派生类。您希望能够在存储从params派生的所有可能类的数组上执行相同的操作。

No problem - declare the method virtual, add some basic implementation to Params class and override it in derived classes. Now you can just traverse the array and call the method through the reference - the correct method will be called.

没问题 - 声明方法virtual,向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();
    }
 }

#9


Use of virtual functions in c#

在c#中使用虚函数

Virtual functions are mostly used to override the base class method in the derived class with the same signature.

虚函数主要用于覆盖具有相同签名的派生类中的基类方法。

When a derived class inherits the base class, the object of derived class is a reference to either the derived class or the base class.

当派生类继承基类时,派生类的对象是对派生类或基类的引用。

Virtual functions are resolved late by the compiler(i.e run-time binding)

虚函数由编译器解决(即运行时绑定)

virtual in the base class, the most-derived class's implementation of the function is called according to the actual type of the object referred to, regardless of the declared type of the pointer or reference. If it is not virtual, the method is resolved early and the function called is selected according to the declared type of the pointer or reference.

在基类中,根据引用的对象的实际类型调用函数的最派生类的实现,而不管指针或引用的声明类型。如果它不是虚拟的,则提前解析该方法,并根据指定的指针或引用类型选择调用的函数。

#1


So basically if in your ancestor class you want a certain behaviour for a method. If your descendent uses the same method but has a different implementation you can override it, If it has a virtual keyword.

所以基本上如果在你的祖先类中你想要一个方法的特定行为。如果您的后代使用相同的方法但具有不同的实现,则可以覆盖它,如果它具有虚拟关键字。

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());
   }
}

Edit: Questions in comment
If I don't use virtual keyword in base class, will it work?

编辑:注释中的问题如果我不在基类中使用虚拟关键字,它会起作用吗?

If you use the override keyword in your descendent classes it will not work. You will generate compiler error CS0506 'function1' : cannot override inherited member 'function2' because it is not marked "virtual", "abstract", or "override"

如果在后代类中使用override关键字,则无效。您将生成编译器错误CS0506'function1':无法覆盖继承的成员'function2',因为它未标记为“虚拟”,“抽象”或“覆盖”

If you don't use the override You'll get the CS0108 warning 'desc.Method()' hides inherited member 'base.Method()' Use the new keyword if hiding was intended.

如果你不使用覆盖你会得到CS0108警告'desc.Method()'隐藏继承成员'base.Method()'如果想要隐藏,使用new关键字。

To get around this put the new keyword in front of the method you are hiding.

要解决此问题,请将新关键字放在您隐藏的方法之前。

e.g.

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

..and is it compulsory to override a virtual method in derived class?
No, if you don't override the method, the descendent class will use method it is inheriting from.

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

#2


The key to understanding the practical usage of virtual functions is to keep in mind that an object of a certain class can be assigned another object of a class derived from the first object's class.

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

E.g.:

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

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

Animal a = new FlyingAnimal();

The Animal class has a function eat() that generally describes how an animal should eat (e.g. put the object in mouth and swallow).

Animal类具有函数eat(),其通常描述动物应该如何进食(例如将物体放入口中并吞咽)。

However, the FlyingAnimal class should define a new eat() method, because flying animals have a particular way of eating.

但是,FlyingAnimal类应该定义一个新的eat()方法,因为飞行动物有一种特殊的吃法。

So the question that comes to mind here is: after I declared the variable a of type Animal and asigned it a new object of type FlyingAnimal, what will a.eat() do? Which of the two methods is called?

所以这里想到的问题是:在我声明变量类型为Animal并将其赋予一个类型为FlyingAnimal的新对象之后,a.eat()会做什么?这两种方法中的哪一种被称为?

The answer here is: because a is of type Animal, it will call Animal's method. The compiler is dumb and doesn't know that you are going to assign an object of another class to the a variable.

这里的答案是:因为a是Animal类型,它将调用Animal的方法。编译器很笨,并且不知道您要将另一个类的对象分配给变量。

Here is where the virtual keyword comes in action: if you declare the method as virtual void eat() {...}, you are basically telling the compiler "be careful that I am doing some clever stuff here that you cannot handle because you're not as smart". So the compiler will not attempt to link the call a.eat() to either of the two methods, but instead it tells the system to do it at runtime!

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

So only when the code executes, the system will look at a's content type not at its declared type and executes FlyingAnimal's method.

因此,只有在代码执行时,系统才会查看不是声明类型的内容类型,并执行FlyingAnimal的方法。

You may wonder: why the hell would I want to do that? Why not say right from the start FlyingAnimal a = new FlyingAnimal() ?

你可能想知道:为什么我要这么做呢?为什么不从一开始就说FlyingAnimal a = new FlyingAnimal()?

The reason for that is that, for example, you may have many derived classes from Animal: FlyingAnimal, SwimmingAnimal, BigAnimal, WhiteDog etc. And at one point you want to define a world containing many Animals, so you say:

这样做的原因是,例如,你可能有许多来自Animal的派生类:FlyingAnimal,SwimmingAnimal,BigAnimal,WhiteDog等。有一点你想要定义一个包含许多动物的世界,所以你说:

Animal[] happy_friends = new Animal[100];

We have a world with 100 happy animals. You initialize them at some point:

我们拥有100个快乐动物的世界。你在某个时候初始化它们:

...
happy_friends[2] = new AngryFish();
...
happy_friends[10] = new LoudSnake();
...

And at the end of the day, you want everybody to eat before they go to sleep. So you want to say:

在一天结束时,你希望每个人在睡觉前都能吃。所以你想说:

for (int i=0; i<100; i++) {
   happy_friends[i].eat();
}

So as you can see, each animal has its own method of eating. Only by using virtual functions can you achieve this functionality. Otherwise, everyone would be forced to "eat" in the exact same way: as described in the most general eat function inside the Animal class.

如你所见,每只动物都有自己的进食方法。只有使用虚拟功能才能实现此功能。否则,每个人都会*以完全相同的方式“吃”:如Animal类中最常用的eat函数所述。

EDIT: This behavior is actually default in common high-level languages like Java.

编辑:这种行为实际上是Java等常见高级语言的默认行为。

#3


Like any other language..when you want polymorphism. There are tons of usage for this. For example you want to abstract the way input is read from a console or a file or some other device. You can have a generic reader interface followed by multiple concrete implementations using virtual functions.

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

#4


e.g. proxying methods. i.e. overwriting methods at runtime. For example, NHibernate uses this to support lazy loading.

例如代理方法。即在运行时覆盖方法。例如,NHibernate使用它来支持延迟加载。

#5


Basically virtual members allow you to express polymorphism, a derived class can have a method with the same signature as the method in its base class, and the base class will call the derived class's method.

基本上虚拟成员允许您表达多态性,派生类可以具有与其基类中的方法具有相同签名的方法,并且基类将调用派生类的方法。

A basic example:

一个基本的例子:

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();
    }
}

#6


This allows to achieve late binding, meaning to determine at runtime rather than at compile-time which object's member will be invoked. See Wikipedia.

这允许实现后期绑定,这意味着在运行时而不是在编译时确定将调用哪个对象的成员。见*。

#7


From here:

In object-oriented programming, a virtual function or virtual method is a function or method whose behavior can be overridden within an inheriting class by a function with the same signature.

在面向对象的编程中,虚函数或虚方法是一种函数或方法,其行为可以通过具有相同签名的函数在继承类中重写。

#8


For example you have a base class Params and a set of derived classes. You want to be able to perform the same operation on an array that stores all possible classes derived from params.

例如,您有一个基类Params和一组派生类。您希望能够在存储从params派生的所有可能类的数组上执行相同的操作。

No problem - declare the method virtual, add some basic implementation to Params class and override it in derived classes. Now you can just traverse the array and call the method through the reference - the correct method will be called.

没问题 - 声明方法virtual,向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();
    }
 }

#9


Use of virtual functions in c#

在c#中使用虚函数

Virtual functions are mostly used to override the base class method in the derived class with the same signature.

虚函数主要用于覆盖具有相同签名的派生类中的基类方法。

When a derived class inherits the base class, the object of derived class is a reference to either the derived class or the base class.

当派生类继承基类时,派生类的对象是对派生类或基类的引用。

Virtual functions are resolved late by the compiler(i.e run-time binding)

虚函数由编译器解决(即运行时绑定)

virtual in the base class, the most-derived class's implementation of the function is called according to the actual type of the object referred to, regardless of the declared type of the pointer or reference. If it is not virtual, the method is resolved early and the function called is selected according to the declared type of the pointer or reference.

在基类中,根据引用的对象的实际类型调用函数的最派生类的实现,而不管指针或引用的声明类型。如果它不是虚拟的,则提前解析该方法,并根据指定的指针或引用类型选择调用的函数。