c++虚继承初始化列表

C++ virtual inheritance initializer list

本文关键字:列表 初始化 继承 c++      更新时间:2023-10-16

在以下代码中:

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++){}
};

两个问题:

  1. 为什么我需要在D的初始化列表中添加A(...) ?
  2. D(int x):B(x++), C(x++), A(x++){}D(int x):A(x++), B(x++), C(x++){}都与cout<<D(10).x给出相同的结果,为什么?

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

这是因为虚基子对象必须在所有其他子对象之前初始化。由于A没有默认构造函数,您需要显式地初始化D中的虚拟A子对象,并指定您希望使用哪个参数来构造它。

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)的构造函数初始化虚基类它们在基类的有向无环图的深度优先的从左到右遍历中出现的顺序,其中"从左到右"是派生类基-指定符列表中基类的出现顺序。

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

——然后,非静态数据成员按照在类定义中声明的顺序初始化。(还是不管初始化式的顺序)。

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

虚基类只能由派生最多的类初始化。也就是说,如果在示例中创建D的实例,A只会在D的mem初始化列表中出现时被初始化。如果它出现在BC的mem初始化列表中,则直接忽略。

这也是为什么你必须在D中初始化A: A没有默认的ctor,所以D必须知道如何初始化它。