这种行为是否定义明确?
class Foo
{
int A, B;
public:
Foo(int Bar): B(Bar), A(B + 123)
{
}
};
int main()
{
Foo MyFoo(0);
return 0;
}
答案 0 :(得分:17)
不,它未定义。 A
将首先被初始化(它是类定义中的第一个),它使用未初始化的B
。
类成员按照它们在类定义中出现的顺序进行初始化,而不管它们在初始化列表中的顺序如何。实际上,将成员定义顺序与初始化列表顺序不匹配是不好的做法。
如果您的Foo
实例碰巧有静态持续时间,例如Foo f(0); int main(){}
,则行为定义明确。具有静态持续时间的对象在进行任何其他初始化之前被初始化为零;在这种情况下,A
和B
在运行构造函数时将为0。然而,在此之后,行为是相同的:首先A
然后B
,给A
一个值123,B
一个值Bar
(仍然难看)。
答案 1 :(得分:11)
不,初始化顺序由类本身的声明顺序定义。
来自C ++标准12.6.2 [class.base.init] p5
:
初始化应按以下顺序进行:
- 首先,仅对于如下所述的派生类最多的构造函数,虚拟基类应按它们出现在基类有向无环图的深度优先从左到右遍历的顺序进行初始化,其中“ “从左到右”是派生类base-specifier-list中基类名称的出现顺序 - 然后,直接基类应按声明顺序初始化,因为它们出现在base-specifier-list中(无论mem-initializers的顺序如何)。
- 然后,非静态数据成员应按照在类定义中声明的顺序进行初始化(同样不管mem-initializers的顺序如何)。
- 最后,执行构造函数的主体 [注意:声明顺序的作用是确保以初始化的相反顺序销毁基础和成员子对象。 ]
答案 2 :(得分:2)
初始化按声明中的出现顺序进行,而不是在构造函数中将其写入的顺序。
看看这个问题,它有点类似: Initializer list *argument* evaluation order