C++ 覆盖与虚拟
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2932909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Overriding vs Virtual
提问by anonymous
What is the purpose of using the reserved word virtual in front of functions? If I want a child class to override a parent function, I just declare the same function such as void draw(){}
.
在函数前使用保留字 virtual 的目的是什么?如果我希望子类覆盖父函数,我只需声明相同的函数,例如void draw(){}
.
class Parent {
public:
void say() {
std::cout << "1";
}
};
class Child : public Parent {
public:
void say()
{
std::cout << "2";
}
};
int main()
{
Child* a = new Child();
a->say();
return 0;
}
The output is 2.
输出为 2。
So again, why would the reserved word virtual
be necessary in the header of say()
?
那么,为什么virtual
在 的标题中需要保留字say()
?
Thanks a bunch.
谢谢一堆。
采纳答案by krolth
This is the classic question of how polymorphism works I think. The main idea is that you want to abstract the specific type for each object. In other words: You want to be able to call the Child instances without knowing it's a child!
这是我认为多态如何工作的经典问题。主要思想是您要抽象每个对象的特定类型。换句话说:您希望能够在不知道它是孩子的情况下调用 Child 实例!
Here is an example: Assuming you have class "Child" and class "Child2" and "Child3" you want to be able to refer to them through their base class (Parent).
这是一个示例:假设您有类“Child”和类“Child2”和“Child3”,您希望能够通过它们的基类(Parent)来引用它们。
Parent* parents[3];
parents[0] = new Child();
parents[1] = new Child2();
parents[2] = new Child3();
for (int i=0; i<3; ++i)
parents[i]->say();
As you can imagine, this is very powerful. It lets you extend the Parent as many times as you want and functions that take a Parent pointer will still work. For this to work as others mention you need to declare the method as virtual.
可以想象,这是非常强大的。它允许您根据需要多次扩展 Parent,并且采用 Parent 指针的函数仍然可以工作。为了像其他人提到的那样工作,您需要将该方法声明为虚拟方法。
回答by Donnie
If the function were virtual, then you could do this and still get the output "2":
如果函数是虚拟的,那么你可以这样做并且仍然得到输出“2”:
Parent* a = new Child();
a->say();
This works because a virtual
function uses the actualtype whereas a non-virtual function uses the declaredtype. Read up on polymorphismfor a better discussion of why you'd want to do this.
这是有效的,因为virtual
函数使用实际类型,而非虚拟函数使用声明的类型。阅读多态性以更好地讨论为什么要这样做。
回答by Jerry Coffin
Try it with:
试试看:
Parent *a = new Child();
Parent *b = new Parent();
a->say();
b->say();
Without virtual
, both with print '1'. Add virtual, and the child will act like a Child, even though it's being referred to via a pointer to a Parent
.
没有virtual
,两者都打印“1”。添加 virtual,即使它是通过指向Parent
.
回答by David Rodríguez - dribeas
If you do not use the virtual
keyword you are not overriding, but rahter defining an unrelated method in the derived class that will hide the base class method. That is, without the virtual
, Base::say
and Derived::say
are unrelated --besides the name coincidence.
如果您不使用virtual
关键字,您就不会覆盖,而是在派生类中定义一个不相关的方法,该方法将隐藏基类方法。也就是说,没有virtual
,Base::say
和Derived::say
是不相关的——除了名字巧合。
When you use the virtual keyword (required in the base, optional in the derived class), you are telling the compiler that classes that derive from this base will be able to overridethe method. In that case, Base::say
and Derived::say
are considered overrides of the same method.
当您使用 virtual 关键字(在基类中是必需的,在派生类中是可选的)时,您是在告诉编译器从该基类派生的类将能够覆盖该方法。在这种情况下,Base::say
和Derived::say
被视为相同方法的覆盖。
When you use a reference or pointer to a base class to call a virtual method, the compiler will add the appropriate code so that the final overrideris called (the override in the most derived class that defines the method in the hierarchy of the concrete instance in use). Note that if you do not use references/pointer but local variables, the compiler can resolve the call and it does not need to use the virtual dispatch mechanism.
当您使用基类的引用或指针来调用虚方法时,编译器会添加适当的代码,以便调用最终的覆盖(最派生类中的覆盖,在具体实例的层次结构中定义方法)正在使用)。请注意,如果您不使用引用/指针而是使用局部变量,则编译器可以解析调用并且不需要使用虚拟分派机制。
回答by jokoon
Well I tested it for myself, because there are a lot of things we can think about:
好吧,我亲自测试了它,因为我们可以考虑很多事情:
#include <iostream>
using namespace std;
class A
{
public:
virtual void v() { cout << "A virtual" << endl; }
void f() { cout << "A plain" << endl; }
};
class B : public A
{
public:
virtual void v() { cout << "B virtual" << endl; }
void f() { cout << "B plain" << endl; }
};
class C : public B
{
public:
virtual void v() { cout << "C virtual" << endl; }
void f() { cout << "C plain" << endl; }
};
int main()
{
A * a = new C;
a->f();
a->v();
((B*)a)->f();
((B*)a)->v();
}
output:
输出:
A plain
C virtual
B plain
C virtual
I think that a good, simple and short answer might look like this (because I think people who can understand more can memorize less thus needing for short and simple explanation):
我认为一个好的、简单和简短的答案可能看起来像这样(因为我认为理解得更多的人可以记住的更少,因此需要简短的解释):
Virtual methods checks for the DATA of the instance the pointer points to, while classic methods don't thus calling the method correponding to the specified type.
虚拟方法检查指针指向的实例的 DATA,而经典方法不会因此调用对应于指定类型的方法。
The point of that feature is the following: suppose you have an array of A's. The array can contain B's, C's, (or even derived types.). if you want to sequentially call the same method of all those instances, you would call each one you overloaded.
该功能的要点如下:假设您有一个 A 数组。数组可以包含 B、C(甚至派生类型)。如果你想顺序调用所有这些实例的相同方法,你会调用你重载的每一个。
I find this quite tricky to understand, and obviously any C++ course should explained how this is achieved, because most of the time you are just teached about virtual functions, you use them, but until you understand how the compiler understand them and how the executable will handle the calls, you are in the dark.
我发现这很难理解,显然任何 C++ 课程都应该解释这是如何实现的,因为大多数时候你只是学习虚函数,你会使用它们,但直到你了解编译器如何理解它们以及可执行文件如何将处理电话,你在黑暗中。
The thing about VFtables is that I have never been explained what kind of code it adds, and that's obviously here where C++ requires much more experience than C, and this might be the main reason C++ was labelled as "slow" in its early days: in fact, it's powerful, but just like everything, it's powerful if you know how to use it, or else you just "blow your whole leg off".
关于 VFtables 的事情是,我从来没有被解释过它添加了什么样的代码,这显然是 C++ 比 C 需要更多经验的地方,这可能是 C++ 在早期被标记为“慢”的主要原因:事实上,它很强大,但就像所有东西一样,如果你知道如何使用它,它就会很强大,否则你只是“炸掉你的整条腿”。
回答by Amardeep AC9MF
When you use the keyword virtual, a virtual function table is created to locate the correct methods in an instance. Then, even if the derived instance is pointed to by a base class pointer, it will still find the correct implementation of the method.
当您使用关键字 virtual 时,会创建一个虚拟函数表来定位实例中的正确方法。然后,即使派生实例被基类指针指向,它仍然会找到方法的正确实现。
回答by user353306
This is a very important aspect of c++ programming-- almost every interview I've been to, I get asked this question.
这是 C++ 编程的一个非常重要的方面——几乎我参加过的每一次面试,我都会被问到这个问题。
What happens if you change your main to:
如果您将 main 更改为:
int main() { Parent* a = new Child(); a->say(); return 0; }
Also, it's worth understanding what a vtable is.
此外,值得了解什么是 vtable。