C++ 虚拟继承和构造函数

C++ Virtual inheritance and constructors

我有以下 C++ 代码(如果重要的话是 VS2013):

#include <iostream>
using namespace std;

struct  A{
    A() { cout << "A()" << endl; }
    A(int i) { cout << "A(" << i << ")" << endl; }
};

struct B : /*virtual*/ public A{
    B(int i) : A(i){ cout << "B(" << i << ")" << endl; }
};

struct C : /*virtual*/ public A{
    C(int i) : A(i){ cout << "C(" << i << ")" << endl; }
};

struct D : /*virtual*/ public B, /*virtual*/ public C{
    D() : B(2), C(3){ cout << "D()" << endl; }
};

void main() {
    D d;
    system("pause");
}

代码实现了菱形继承,一共有4个继承: B:A、C:A、D:B、D:C

将这些继承中的 none 设置为 virtual,我得到以下输出:

A(2) B(2) A(3) C(3) D()

有道理。 D()先调用B(int x),B(int x)先调用A(int x),再调用C(int x),C(int x)先调用A(int x),最后D()自己运行。

但是就虚拟继承而言,我有4个继承,也就是说我总共有16种virtual\not-virtual继承组合。

摆弄不同的选项会产生一些非常意想不到的结果,而且我对虚拟继承的了解越多,我就越感到困惑。

这里有一些例子:

  1. 仅将 B:A 设置为 virtual 时,我得到:

A() B(2) A(3) C(3) D()

这是有道理的 - B 几乎继承了 A,因此,除非特别说明,否则 B(int x) 调用 A 的默认构造函数。

  1. 仅将 C:A 设置为 virtual 时,我得到:

A() A(2) B(2) C(3) D()

为什么 A 的构造函数都在 B 和 C 之前?这种行为对我来说毫无意义。

  1. 仅将 D:C 设置为 virtual 时,我得到:

A(3) C(3) A(2) B(2) D()

为什么 C 的构造函数先于 B 的构造函数?

我可以继续下去。 其中一些组合会导致非常意外的结果(至少对我而言)。

我了解虚拟继承的基础知识并通过简单的示例理解它们,并且我已经看到很多关于它的问题。但是其中一些行为仍然让我感到困惑。

这些多重虚拟继承是否有任何特定的规则集?

编辑: 我被重定向到这个问题: 虽然这很有帮助,但我仍然对在任何特定情况下调用 A 的哪些构造函数感到困惑。 我还需要一些帮助。

这里有两个大键:

  1. 虚拟基 classes 由最派生的 class 构造函数直接初始化,而不是由其他基 classes 间接初始化。

  2. 虚拟基 classes 在任何非虚拟基 classes 之前初始化。

让我们看看你的例子。

When setting only B:A to virtual I get:

A() B(2) A(3) C(3) D()

That makes some sense - B inherits A virtually, and therefore, unless specifically stated otherwise, B(int x) calls A's default constructor.

B 根本不调用 A 的构造函数。 D 直接为 A 的虚拟实例调用 A。但是由于 D 的构造函数没有指定如何初始化 A,所以你得到 A 的默认构造函数。

B(int i) : A(i) 中的 A 被忽略不是因为 A 是虚拟基础,而是因为 B 不是最衍生的 class 等等无法构建其 A.

When setting only C:A to virtual I get:

A() A(2) B(2) C(3) D()

Why do A's constructors both precede B's and C's? That behavior makes no sense to me.

这里C::A是唯一的虚拟基class,所以先初始化。同样,由于 D 的构造函数没有为 A 指定初始化程序,该虚拟子对象使用默认构造函数。

然后非虚拟基地classes按顺序进行。 B 出现在 C 之前,但 B 首先需要初始化其非虚拟 A(与 2)。

When setting only D:C to virtual I get:

A(3) C(3) A(2) B(2) D()

Why would C's constructor precede B's?

唯一的虚拟基地 class 是 C,因此它是在 B 之前建造的。但是这次C的构造函数必须先初始化它的非虚基子对象C::A。然后是B,它必须首先初始化它的非虚拟子对象B::A

最后是“正常”模式,它使两个 A 继承都是虚拟的,结果只有一个 A 子对象,这是虚拟继承的全部要点。将 BC 虚拟化是没有意义的,除非您希望 D 以更复杂的方式被重用为基础 class。

#include <iostream>
using namespace std;

struct  A{
    A() { cout << "A()" << endl; }
    A(int i) { cout << "A(" << i << ")" << endl; }
};

struct B : virtual public A{
    B(int i) : A(i){ cout << "B(" << i << ")" << endl; }
};

struct C : virtual public A{
    C(int i) : A(i){ cout << "C(" << i << ")" << endl; }
};

struct D : public B, public C{
    D() : A(1), B(2), C(3){ cout << "D()" << endl; }
};

void main() {
    D d;
    system("pause");
}

输出:

A(1) B(2) C(3) D()

注意我在 D 中添加了一个初始化器 A(1) 以表明虚拟子对象不一定需要使用默认构造函数。您可以在至少一个 A 继承是虚拟的任何示例中完成此操作。