重新定义和使用虚拟功能有什么区别?他们不是为了同一个目的吗?您允许派生类的对象在两种情况下都使用相同的名称调用自己的函数版本。那么区别在哪里?
答案 0 :(得分:5)
一个例子说得最好:
#include <iostream>
using namespace std;
class A {
public:
virtual void f1() { cout << "Class A" << endl; }
void f2() { cout << "Class A" << endl; }
virtual ~A(){}
};
class B : public A {
public:
virtual void f1() { cout << "Class B" << endl; }
void f2() { cout << "Class B" << endl; }
virtual ~B(){}
};
int main()
{
A *a = new B;
a->f1();
a->f2();
}
...
$ ./override
Class B
Class A
您可以看到,当我们引用B的实例时,f1()
仍会调用B
的版本,但f2()
会调用A
。
当你声明一个虚拟函数时,你会说当我们调用它时我们应该使用vtable来查找要调用的函数的正确版本,这样你总能获得函数的最大派生版本,甚至如果您将其作为祖先类型引用。如果没有虚拟,它将只使用您引用它的类型中的定义。
答案 1 :(得分:3)
区别在于您有一个引用或指向基类的指针。对虚函数的调用将调用派生最多的版本,而对普通函数的调用将调用基类版本。
如果您直接使用变量或者使用最大派生类的引用或指针,则没有实际区别。
答案 2 :(得分:2)
<强> TL; DR 强>
利用C ++中的多态性的唯一方法是通过虚函数和指针(和引用)。 virtual关键字将告诉编译器在处理指向具有子类的动态类型的基类的指针时,在决定要调用的虚拟函数的版本时,分配虚拟函数表。
多态性如何在C ++中起作用
我们举一个简单的例子:
class A { public: virtual void eat() { std::cout << "Class A" << std::endl; }
class B : public A {};
class C : public B { virtual void eat() { std::cout << "Class C" << std::endl; }
注意:在第一个函数/方法定义之后,可以省略virtual关键字。
以下内容:
A a; B b; C c;
A* ptrA = &a; A* ptrB = &b; A* ptrC = &c;
ptrA->eat();
ptrB->eat();
ptrC->eat();
将打印:
Class A
Class A
Class C
如果我们不会将函数eat
声明为虚拟,那么输出就是:
Class A
Class A
Class A