C++虚继承下构造函数的初始化顺序疑问
为什么虚基类AA1会比AA2先构造?
我猜你的代码应该是类似这样的典型菱形虚继承场景:
#include <iostream> using namespace std; class AA1 { public: AA1() { cout << "AA1 constructed\n"; } }; class AA2 { public: AA2() { cout << "AA2 constructed\n"; } }; // A 按左到右顺序虚继承AA1、AA2 class A : virtual public AA1, virtual public AA2 { public: A() { cout << "A constructed\n"; } }; // B 按左到右顺序虚继承AA2、AA1 class B : virtual public AA2, virtual public AA1 { public: B() { cout << "B constructed\n"; } }; // 最派生类C继承A和B class C : public A, public B { public: C() { cout << "C constructed\n"; } }; int main() { C c; return 0; }
输出结果应该是:
AA1 constructed AA2 constructed A constructed B constructed C constructed
你疑惑的点在于:按照“基类图深度优先左遍历”的规则,类B的基类顺序是AA2在前、AA1在后,为什么实际构造顺序不是先AA2?
核心误解:遍历的起点是最派生类的整个继承体系,而非单个基类
你提到的“深度优先左遍历”规则,是针对最终被实例化的最派生类(这里是C)的完整继承层次图来执行的,不是单独遍历某个基类(比如B)的继承链。我们一步步拆解这个遍历过程:
- 从最派生类C开始,先遍历它的第一个基类A(遵循左到右的继承顺序)
- 进入A的继承链,第一个遇到的是虚基类AA1——这是整个体系中首次出现的虚基类,标记为待构造
- 继续遍历A的下一个基类虚基类AA2——这是第二个首次出现的虚基类,标记为待构造
- 回到C,遍历它的第二个基类B
- 进入B的继承链,第一个基类是AA2,但它已经被标记为虚基类(待构造),跳过;第二个基类是AA1,同样已标记,跳过
所以整个继承体系的虚基类构造顺序是AA1 → AA2,这是遍历最派生类C的继承图时,首次遇到虚基类的顺序。
另外还要记住两个关键规则:
- 所有虚基类的构造函数,会在任何非虚基类的构造函数之前执行
- 同一个虚基类只会被构造一次,无论它被多少个类继承
验证:如果最派生类的继承顺序改变会怎样?
如果把C的继承顺序改成class C : public B, public A,那遍历顺序就变成C→B→AA2→AA1→A,此时虚基类的构造顺序就会变成AA2 → AA1,输出也会对应变化。
总结来说:你之前误解了遍历的起点——不是从B开始,而是从最终实例化的最派生类出发,遍历它的完整继承层次,虚基类的构造顺序由这次全局遍历中首次出现的顺序决定,单个基类的继承顺序不会覆盖这个全局规则。
内容的提问来源于stack exchange,提问作者George Lazu
相关产品推荐
相关产品推荐

