我有一个使用继承的非常简单的代码,并且我的基类和派生类中有相同的函数原型。我不理解最后的结果(pB->bar()
(,因为我认为由于pB
指向派生类型对象(在delete
之后(,它应该调用D::bar()
。
#include <iostream>
class B {
public:
virtual void foo() { std::cout << "B:foo" << std::endl; }
void bar() { std::cout << "B:bar" << std::endl; }
};
class D : public B {
public:
virtual void foo() override { std::cout << "D:foo" << std::endl; }
void bar(){ std::cout << "D:bar" << std::endl;}
};
int main() {
B* pB = new B;
pB->foo();
pB->bar();
delete pB;
pB = new D;
pB->foo();
pB->bar();
delete pB;
}
结果是:
B:foo
B:bar
D:foo
B:bar
您已将virtual
用于foo
,但未使用bar
。这个程序演示了这个关键字的效果:它发出信号,考虑对象的动态或运行时类型。如果没有它,编译器只使用静态或编译时类型信息生成直接函数调用。
关键字virtual
为类函数创建一个虚拟表,然后当您使用指向类的指针时,程序会检查类的类型,并尝试在虚拟表中查找函数foo。
当你调用bar时,程序会检查bar实现的类指针,因为指针是B类型的,所以会调用B的函数栏。
你可以编写
D* pD = new D;
pD->bar();
bar()
不是virtual
,因此对它的调用在编译时使用它所调用的类型静态解析。它在运行时不会像您所期望的那样动态解析,类似于foo()
,即virtual
。
通过B*
指针调用bar()
将调用B::bar()
,而通过D*
指针调用它将改为调用D::bar()
。pB
是B*
,这就是为什么pB->bar()
调用B::bar()
,而不管pB
指向B
还是D
对象。这是一个静态调用。