c++虚继承初始化列表
C++ virtual inheritance initializer list
在以下代码中:
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++){}
};
两个问题:
- 为什么我需要在D的初始化列表中添加
A(...)
? -
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
子对象,并指定您希望使用哪个参数来构造它。
当B
和C
基子对象的构造函数被执行时,它们不会有一个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初始化列表中出现时被初始化。如果它出现在B
和C
的mem初始化列表中,则直接忽略。
这也是为什么你必须在D
中初始化A
: A
没有默认的ctor,所以D
必须知道如何初始化它。
- 复制列表初始化的隐式转换的等级是多少
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- 我使用向量来创建类对象列表.初始化向量时如何使用参数调用构造函数?
- C++11 中的混合列表初始化
- 我可以列表初始化 std::vector 并完美转发元素吗?
- 无法在声明时使用初始值设定项列表初始化常量字符*/字符串数组的向量
- C++20 从括号中的值列表初始化聚合,不支持内部数组
- 如何在向量列表初始化时避免对象复制以及如何延长临时的生存期
- 默认参数和空列表初始化
- 如何在列表初始化中放置额外的语句?
- C++列表初始化允许多个用户定义的转换
- 列表初始化是否将原子初始化为零
- 使用可变模板列表初始化数组,并放置new
- 使用整数初始化列表初始化长双精度的向量
- 直接列表初始化的自动规则
- 使用初始化列表初始化unique_ptr的容器,继续
- 如何修复"非聚合无法使用初始值设定项列表初始化" <map>
- 直接列表初始化和复制列表初始化之间的差异
- 为什么我可以在不使用赋值运算符的情况下使用列表初始化普通数组
- C++ - 使用类中的初始值设定项列表初始化动态集