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