C++虚拟继承初始化列表

pro*_*ngs 8 c++ inheritance constructor multiple-inheritance virtual-inheritance

在以下代码中:

class A
{
public:
    int x;
    A(int x):x(x){}
};

class B: public virtual A
{
public:
    B(int x):A(x){}
};
class C: public virtual A
{
public:
    C(int x):A(x){}
};
class D: public B, public C
{
public:
    D(int x):B(x++), C(x++), A(x++){}
};
Run Code Online (Sandbox Code Playgroud)

两个问题:

  1. 为什么我需要添加A(...)D的初始化列表?
  2. D(int x):B(x++), C(x++), A(x++){}并且D(int x):A(x++), B(x++), C(x++){}均可以得到同样的结果cout<<D(10).x,为什么呢?

And*_*owl 7

为什么我需要在D的初始化列表中添加A(...)?

这是因为必须在所有其他子对象之前初始化虚拟基础子对象.由于A没有默认构造函数,因此需要显式初始化虚拟A子对象,D并指定要构造它的哪个参数.

当执行BC基础子对象的构造函数时,它们将没有A要初始化的基础子对象(已经在之前完成).因此,它们传递给A构造函数的参数是无关紧要的.

D(int x):B(x++), C(x++), A(x++){}并且D(int x):A(x++), B(x++), C(x++){}均可以得到同样的结果cout<<D(10).x,为什么呢?

如上所述,这是因为无论如何首先初始化虚拟基础子对象.

通常,类的子对象的初始化顺序决不会取决于它们在构造函数的初始化列表中出现的顺序.根据C++ 11标准的第12.6.2/10段:

在非委托构造函数中,初始化按以下顺序进行:

- 首先,仅对于派生程度最高的类(1.8)的构造函数,虚拟基类按照它们出现在基类的有向无环图的深度优先从左到右遍历的顺序进行初始化,其中"左" -to-right"是派生类base-specifier-list中基类出现的顺序.

- 然后,直接基类按声明顺序初始化,因为它们出现在base-specifier-list中 (无论mem-initializers的顺序如何).

- 然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化 (同样不管mem-initializers的顺序如何).

- 最后,执行构造函数体的复合语句.