在c++中,当组合对象构造函数有依赖关系时,如何在初始化列表中强制它们的顺序
in C++, how should I enforce the order of composited object constructors in an initializer list when they have dependencies
如果我有一个类,它由具有相互依赖关系的其他对象组成,(如何)我应该强制它们的构造顺序?
。
class Parent
{
Child1 c1;
Child2 c2;
};
想象Child2的构造函数需要一个Child1&我想把c1传递给c2构造函数。
如果我只是做下面的…
Parent::Parent()
: c2(c1)
{
}
…这可能不是一件好事,因为c1可能不会在运行c2的初始化式时被构造。或者在类声明中,c1在c2之前是否足够好?
或者我应该显式地引用c1构造函数(如果没有必要,那么这样做以使其显式是一个好的实践吗?)例如
class Parent
{
Child1 c1;
Child2 c2;
};
Parent::Parent()
: c1()
: c2(c1)
{
}
成员总是按照声明的顺序构造的。所以如果你有:
class Parent
{
Child1 c1;
Child2 c2;
};
您可以保证c1
将在c2
之前构建。因此,如果c2
需要Child1&
,那么这是完美定义的:
Parent::Parent()
: c2(c1)
{
}
c1
将被默认构造,然后c2
将用一个明确已经构造的c1
来构造。
这些都不起作用。成员变量是按照声明的顺序构造的。句号。
以下是cppreference的完整解释:
成员初始化式在列表中的顺序无关紧要:初始化的实际顺序如下:
- 列表项如果构造函数是用于派生最多的类,则虚拟基类将按照它们在基类声明的深度优先从左到右遍历中出现的顺序进行初始化(从左到右指基类说明符列表中的出现顺序)
- 然后,直接基类按从左到右的顺序初始化,因为它们出现在该类的基说明符列表
然后,非静态数据成员按照类定义中的声明顺序初始化。- 最后,执行构造函数体
类中的声明顺序是唯一相关的事情。编译器不遵守初始化列表中的构造顺序,实际上你可以启用一个警告来警告你这个事实(初始化列表中的顺序!=有效构造的顺序)。
在c++中,初始化列表中的成员不是按照你放入列表的顺序初始化的,而是按照你声明的顺序初始化的。事实上,如果您没有按照声明的顺序初始化成员,g++将输出警告。因此,您应该注意按照成员的逻辑顺序声明——从低级对象到高级对象。
成员数据按照声明的顺序构造。如果c1
在c2
之前声明(就像在你的例子中一样),那么它将首先被构造。
然而,你的两个例子有一点不同:
Parent::Parent()
// c1 is implicitly default-initialized
: c2(c1)
{
}
Parent::Parent()
: c1(), //c1 is value-initialized
c2(c1)
{
}
如果Child1
是非pod类类型,则两者是等效的,否则您将获得c1
的不确定值。
如果这对您很重要,您可以阅读默认初始化和值初始化之间的区别。
相关文章:
- 复制列表初始化的隐式转换的等级是多少
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- 我使用向量来创建类对象列表.初始化向量时如何使用参数调用构造函数?
- C++11 中的混合列表初始化
- 我可以列表初始化 std::vector 并完美转发元素吗?
- 无法在声明时使用初始值设定项列表初始化常量字符*/字符串数组的向量
- C++20 从括号中的值列表初始化聚合,不支持内部数组
- 如何在向量列表初始化时避免对象复制以及如何延长临时的生存期
- 默认参数和空列表初始化
- 如何在列表初始化中放置额外的语句?
- C++列表初始化允许多个用户定义的转换
- 列表初始化是否将原子初始化为零
- 使用可变模板列表初始化数组,并放置new
- 使用整数初始化列表初始化长双精度的向量
- 直接列表初始化的自动规则
- 使用初始化列表初始化unique_ptr的容器,继续
- 如何修复"非聚合无法使用初始值设定项列表初始化" <map>
- 直接列表初始化和复制列表初始化之间的差异
- 为什么我可以在不使用赋值运算符的情况下使用列表初始化普通数组
- C++ - 使用类中的初始值设定项列表初始化动态集