C#中虚函数的实际使用
C#中虚函数的实际用途是什么?
What 's the practical usage of virtual functions in c#?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
C#中虚函数的实际用途是什么?
What 's the practical usage of virtual functions in c#?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(10)
所以基本上,如果在您的祖先类中您想要某个方法具有某种行为。 如果您的后代使用相同的方法但具有不同的实现,您可以覆盖它,如果它具有virtual关键字。
编辑:评论中的问题
如果我不在基类中使用 virtual 关键字,它会起作用吗?
如果您在后代类中使用
override
关键字,它将不起作用。 您将生成编译器错误 CS0506 'function1 ' : 无法覆盖继承的成员 'function2',因为它没有标记为“虚拟”、“抽象”或“覆盖”如果您不使用覆盖,您将得到 CS0108 警告 'desc.Method()' 隐藏继承成员 'base.Method()' 使用new 关键字(如果有意隐藏)。
要解决此问题,请将
new
关键字放在您要隐藏的方法前面。例如
..是否必须重写派生类中的虚拟方法?
不,如果您不重写该方法,后代类将使用它继承的方法。
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.
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"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.
To get around this put the
new
keyword in front of the method you are hiding.e.g.
..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.
理解虚函数实际用法的关键是要记住,可以将某个类的对象分配给从第一个对象的类派生的类的另一个对象。
例如:
Animal
类有一个函数eat()
,它通常描述动物应该如何进食(例如将物体放入口中并吞咽)。但是,
FlyingAnimal
类应该定义一个新的eat()
方法,因为飞行动物有特定的进食方式。所以这里想到的问题是:在我声明了
Animal
类型的变量a
并为其分配了一个FlyingAnimal
类型的新对象之后,a.eat()
会做什么? 调用这两个方法中的哪一个?这里的答案是:因为
a
是Animal
类型,所以它会调用Animal
的方法。 编译器是愚蠢的,不知道您要将另一个类的对象分配给a
变量。这是
virtual
关键字发挥作用的地方:如果您将该方法声明为virtual void eat() {...}
,那么您基本上是在告诉编译器“小心”我在这里做了一些你无法处理的聪明的事情,因为你不那么聪明”。 因此,编译器不会尝试将调用a.eat()
链接到这两个方法中的任何一个,而是告诉系统在运行时执行此操作!因此,只有当代码执行时,系统才会查看
a
的内容类型而不是其声明的类型,并执行FlyingAnimal
的方法。你可能想知道:我到底为什么要这么做? 为什么不从一开始就说
FlyingAnimal a = new FlyingAnimal()
呢?原因是,例如,您可能有许多来自
Animal
的派生类:FlyingAnimal
、SwimmingAnimal
、BigAnimal
code>、WhiteDog
等。在某一时刻,您想要定义一个包含许多Animal
的世界,所以您会说:我们有一个有 100 只快乐动物的世界。
您在某个时刻初始化它们:
在一天结束时,您希望每个人在睡觉前吃东西。 所以你想说:
正如你所看到的,每种动物都有自己的饮食方法。 只有使用虚拟函数才能实现此功能。 否则,每个人都将被迫以完全相同的方式“吃”:如
Animal
类中最通用的eat
函数中所述。编辑:
这种行为实际上是 Java 等常见高级语言中的默认。
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.:
The
Animal
class has a functioneat()
that generally describes how an animal should eat (e.g. put the object in mouth and swallow).However, the
FlyingAnimal
class should define a neweat()
method, because flying animals have a particular way of eating.So the question that comes to mind here is: after I declared the variable
a
of typeAnimal
and asigned it a new object of typeFlyingAnimal
, what willa.eat()
do? Which of the two methods is called?The answer here is: because
a
is of typeAnimal
, it will callAnimal
's method. The compiler is dumb and doesn't know that you are going to assign an object of another class to thea
variable.Here is where the
virtual
keyword comes in action: if you declare the method asvirtual 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 calla.eat()
to either of the two methods, but instead it tells the system to do it at runtime!So only when the code executes, the system will look at
a
's content type not at its declared type and executesFlyingAnimal
's method.You may wonder: why the hell would I want to do that? Why not say right from the start
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 manyAnimal
s, so you say:We have a world with 100 happy animals.
You initialize them at some point:
And at the end of the day, you want everybody to eat before they go to sleep. So you want to say:
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 theAnimal
class.EDIT:
This behavior is actually default in common high-level languages like Java.
就像任何其他语言一样......当你想要多态性时。 这有很多用途。 例如,您想要抽象从控制台、文件或其他设备读取输入的方式。 您可以拥有一个通用阅读器接口,然后使用虚函数进行多个具体实现。
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.
例如代理方法。 即在运行时覆盖方法。 例如,NHibernate 使用它来支持延迟加载。
e.g. proxying methods. i.e. overwriting methods at runtime. For example, NHibernate uses this to support lazy loading.
这允许实现后期绑定,意味着在运行时而不是在编译时确定将调用哪个对象的成员。 请参阅维基百科。
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.
基本上,虚拟成员允许您表达多态性,派生类可以具有与其基类中的方法具有相同签名的方法,并且基类将调用派生类的方法。
一个基本的例子:
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:
来自此处:
From here:
例如,您有一个基类 Params 和一组派生类。 您希望能够对存储从参数派生的所有可能的类的数组执行相同的操作。
没问题 - 将方法声明为虚拟,向 Params 类添加一些基本实现并在派生类中重写它。 现在您可以遍历数组并通过引用调用方法 - 将调用正确的方法。
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.
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.
C#中虚函数的使用
虚函数大多用于在派生类中用相同的签名重写基类的方法。
当派生类继承基类时,派生类的对象是对派生类或基类的引用。
虚函数在基类中由编译器后期解析(即运行时绑定)
virtual
,根据所引用对象的实际类型调用最派生类的函数实现,无论指针或引用的声明类型如何。 如果它不是虚拟
,则该方法会早期
解析,并根据指针或引用的声明类型选择调用的函数。Use of virtual functions in 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 notvirtual
, the method is resolvedearly
and the function called is selected according to the declared type of the pointer or reference.示例
让我们考虑一下System.Object 中的ToString() 方法。 因为此方法是 System.Object 的成员,所以它在所有类中继承,并将为所有类提供 ToString() 方法。
前面代码的输出是:
让我们考虑一下,我们想要更改从 Company 类中的 System.Object 继承的 ToString() 方法的标准行为。 为了实现这个目标,使用 override 关键字来声明该方法的另一个实现就足够了。
现在,当调用虚拟方法时,运行时将检查其派生类中是否有重写成员,如果存在则调用它。 我们的应用程序的输出将是:
事实上,如果您检查 System.Object 类,您会发现该方法被标记为虚拟。
Example
Let's consider the ToString() method in System.Object. Because this method is a member of System.Object it's inherited in all classes and will provide the ToString() methods to all of them.
The output of the previous code is:
Let's consider that we want to change the standard behavior of the ToString() methods inherited from System.Object in our Company class. To achieve this goal it's enough to use the override keyword to declare another implementation of that method.
Now, when a virtual method is invoked, the run-time will check for an overriding member in its derived class and will call it if present. The output of our application will then be:
In fact, if you check the System.Object class you will find that the method is marked as virtual.