考虑以下(简化)情况:
class Foo
{
private:
int evenA;
int evenB;
int evenSum;
public:
Foo(int a, int b) : evenA(a-(a%2)), evenB(b-(b%2)), evenSum(evenA+evenB)
{
}
};
当我像这样实现Foo时:
Foo foo(1,3);
然后evenA为0,evenB为2,但是将sumSum初始化为2?
我在我当前的平台(iOS)上尝试了这个并且它似乎可行,但我不确定这段代码是否可移植。
感谢您的帮助!
答案 0 :(得分:28)
这个 定义良好且可移植, 1 但它可能容易出错。
成员按照它们在类主体中声明的顺序进行初始化,而不是它们在初始化列表中列出的顺序。因此,如果您更改类主体,此代码可能会无声地失败(尽管许多编译器会发现这一点并发出警告)。
<小时/> <子> 1。来自C ++标准中的[class.base.init]:
在非委托构造函数中,初始化按以下顺序进行:
- 首先,仅针对派生程度最高的类(1.8)的构造函数,初始化虚拟基类 它们出现在基类的有向无环图的深度优先从左到右遍历中的顺序, 其中“从左到右”是派生类base-specifier-list中基类出现的顺序。
- 然后,直接基类按声明顺序初始化,因为它们出现在base-specifier-list中 (无论mem-initializers的顺序如何)。
- 然后,按照在类定义中声明的顺序初始化非静态数据成员 (再次无论mem-initializers的顺序如何)。
- 最后,执行构造函数体的复合语句。
(突出显示是我的。)
然后,标准的这一部分继续举例说明如何使用成员变量来初始化其他成员变量。
子>答案 1 :(得分:8)
是的,提供他们已经建成。只是不要忘记
构造的顺序是声明的顺序
类定义,不中的初始值设定项的顺序
构造函数。并且编译器通常不会告诉您是否使用
在构造之前的变量。在你的情况下,例如,
如果将evenSum
移到课程顶部,则表示未定义
行为(因为它的初始化程序使用未初始化的成员),甚至
虽然在您的构造函数中,您可以通过词法初始化evenA
和evenB
在evenSum
之前。
答案 2 :(得分:6)
成员按照在类定义中声明的顺序进行初始化。只要您的初始化程序列表遵循此顺序,就应该没问题。
答案 3 :(得分:0)
这也在g ++ 4.0.3(现在6岁)上编译时没有错误。
我确信这可以在任何合理的最新编译器上正常编译。