在类派生自三个基类的"diamond problem"中,构造顺序是什么?



下面是我所询问的示例代码。输出将是XXbBACY,但我不明白为什么。

#include <iostream>
using namespace std;
class X {
public:
X() { cout << 'X'; }
X(char c) { cout << 'X' << c; }
};
class A : virtual X {
public:
A() : X('a') { cout << 'A'; }
};
class B : X {
public:
B() : X('b') { cout << 'B'; }
};
class C : virtual X {
public:
C() : X('c') { cout << 'C'; }
};
class Y : A, virtual B, C {
public:
Y() { cout << 'Y'; }
~Y() {}
};
int main() {
Y y;
return 0;
}

根据我的理解,当我们创建类y的对象y时,因为不是所有的基类都是从类X(特别是B(派生的,所以y中会有3个类X的实例。

构造对象y时调用的第一个构造函数将是类B的构造函数,因为它实际上是从类y派生的,但在构造类B之前,必须创建类X的实例,因为B() : X('b') { cout << 'B'; }是类B的默认构造函数,X(char c) { cout << 'X' << c; }将在类X中调用。它将打印Xb。现在我们返回到类B,默认构造函数将打印B,然后返回到类Y

现在,类A和类C的一个实例将以类似的方式构建,留下一个输出:XbBXaAXcCY

我的理解似乎完全错误,因为输出是XXbBACY,这怎么可能呢?

施工顺序总是这样:

  1. 首先是所有(直接或间接(虚拟基,顺序为深度优先声明顺序。显然,任何一种类型中最多只能有一种
  2. 接下来,按声明顺序排列非虚拟基
  3. 按申报顺序排列的所有其他成员
  4. 最后,ctor主体。现在,您可以安全地直接或间接调用虚拟函数,它们将根据当前运行的ctor进行解析

在您的情况下,这意味着:

  1. CCD_ 3与CCD_
  2. virtual B来自Y::B
    (第一步:X来自Y::B::X。(
  3. CCD_ 9从CCD_。X虚拟基地已经完成
  4. CCD_ 12从CCD_。X虚拟基地已经完成

销毁顺序颠倒了这一点。

最新更新