You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)的继承链。我们一步步拆解这个遍历过程:

  1. 从最派生类C开始,先遍历它的第一个基类A(遵循左到右的继承顺序)
  2. 进入A的继承链,第一个遇到的是虚基类AA1——这是整个体系中首次出现的虚基类,标记为待构造
  3. 继续遍历A的下一个基类虚基类AA2——这是第二个首次出现的虚基类,标记为待构造
  4. 回到C,遍历它的第二个基类B
  5. 进入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:04:38