8

在以下代码中:

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. 为什么我需要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,为什么?
4

2 回答 2

8

为什么我需要在 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 中的声明顺序进行初始化 (无论mem-initializers的顺序如何)。

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

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

于 2013-06-15T16:25:58.490 回答
2

虚拟基类仅由派生最多的类初始化。也就是说,如果D在您的示例中创建一个实例,A则只会通过它在 的 mem-initialiser 列表中的出现来初始化D。它在 和 的 mem-initializer 列表中的出现BC简单地忽略了。

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

于 2013-06-15T16:25:36.837 回答