问题描述
我们有以下C++代码:
#include <iostream>
class B {
public:
B() {
test();
}
virtual void test() {
std::cout << "B\n" << std::endl;
}
private:
};
class D : public B {
public:
D() = default;
virtual void test() override {
std::cout << "D\n" << std::endl;
}
private:
};
int main() {
D d;
return 0;
}
运行这段代码时,输出的是 B
而不是 D
。这是为什么?
初步观察
首先,我们有一个基类 B
和一个派生类 D
。B
的构造函数中调用了虚函数 test()
,而 D
重写了这个虚函数。当我们创建一个 D
的对象时,B
的构造函数会被调用,然后在 B
的构造函数中调用了 test()
。然而,输出的是 B
的 test()
实现,而不是 D
的。
理解对象构造过程
在C++中,对象的构造是从基类到派生类的顺序进行的。具体到这段代码:
- 当创建
D
的对象d
时,首先调用B
的构造函数。 - 在
B
的构造函数中,调用了test()
。 - 之后,
D
的构造函数被调用(这里D
的构造函数是默认的,没有额外操作)。
虚函数在构造函数中的行为
关键在于:在构造函数中调用虚函数时,虚函数的动态绑定(多态)行为不会发生。也就是说,在 B
的构造函数中调用 test()
时,它调用的是 B
的 test()
,而不是 D
的 test()
。
这是因为:
- 当
B
的构造函数正在执行时,D
的部分还没有被构造。此时对象的D
部分还不完整,因此不能安全地调用D
的重写函数。 - C++ 的设计决定了在基类的构造函数中,虚函数调用被解析为当前类(即基类)的实现,而不是派生类的实现。这是为了避免在对象未完全构造时调用未初始化的