C++11中,构造函数和默认值哪个先执行?

3
在C++11中,您可以这样做:
class Foo
{
    public:
        Foo();
        bool test = false;
};

Foo::Foo()
{
    // is test guaranteed to be false now? and is it surely not overriden later?
    this->test = true;
}

我想知道的基本上在注释中已经描述了,我可以通过我的编译器来验证,但这是否在标准中提到?它在所有平台和所有编译器上是否都是相同的?


2
就好像你写了 Foo(): test(false) { this->test = true; } 一样。 - Adam
那么,您的意思是默认值是首先设置的,然后在构造函数中被覆盖为最终值? - Petr
没错。如果你想用另一个值来初始化 test,而不是将其初始化为 false 然后再赋值为 true,那么可以像往常一样使用初始化列表:Foo(string s) : test{true} {}Foo(bool b) : test{b} {},等等。 - peppe
3个回答

2

现在测试是否保证为假?是的。

它是否确定以后不会被覆盖?它不会被覆盖。默认值作为构造函数开头的初始化列表的一部分进行设置。

如果测试未包含在初始化列表中,编译器将使用默认值添加它。对于您的构造函数,编译器实际上会为此生成代码:

Foo::Foo()
    : test(false)
{
    // is test guaranteed to be false now?
    this->test = true;
    // is it surely not overriden later?
}

使用这个构造函数,test首先会被初始化为false,然后在后面的代码中设置为true。

如果你写成了:

Foo::Foo()
    : test(true)
{
}

测试将已经在初始化列表中,编译器不会把它放在那里,测试将直接初始化为true。


编译器肯定可以优化初始化,避免进行两次赋值操作... - peppe
1
是的,但我们还应该考虑在更复杂的代码中会发生什么情况,例如 this->test = true; 可能在 if 语句中。 - Eelke

2

来自 [class.base.init] 12.6.2 - 初始化基类和成员

9 如果一个非静态数据成员既有一个大括号或等号初始化器,又有一个成员初始化器,则执行由成员初始化器指定的初始化,并忽略非静态数据成员的大括号或等号初始化器

示例

struct A
{
  int i = /∗ some integer expression with side effects ∗/ ;
  A(int arg) : i(arg) { } // ...
};

A(int)构造函数将简单地将i初始化为arg的值,并且i大括号或等于初始化器中的副作用不会发生。

10 在非委托构造函数中,初始化按以下顺序进行:

  • 首先,仅对于最派生类(1.8)的构造函数,虚基类按深度优先从左到右遍历基类的有向无环图的顺序进行初始化,其中“从左到右”是基类在派生类base-specifier-list中出现的顺序。
  • 然后,直接基类按它们在base-specifier-list中出现的声明顺序进行初始化(不考虑mem-initializers的顺序)。
  • 然后,非静态数据成员按它们在类定义中声明的顺序进行初始化(同样不考虑mem-initializers的顺序)。
  • 最后,执行构造函数体的复合语句。

所以

class Foo
{
public:
  Foo();
  bool test = false;
};

Foo::Foo()
{
  // is test guaranteed to be false now? and is it surely not overriden later?
  this->test = true;
}

test被保证为false且不会被覆盖("最后,构造函数主体的复合语句将会执行"


2

C++11中,非静态数据成员可以在以下三个位置进行初始化:

  • 在类的定义体中(使用“花括号或等号初始化项”)
  • 在构造函数体之前的成员初始化列表中(使用“成员初始化器”)
  • 在构造函数体中。

如果一个非静态数据成员同时具有“花括号或等号初始化项”和“成员初始化器”,那么“成员初始化器”将覆盖“花括号或等号初始化项”;这在12.6.2.p9中指定。

无论哪种情况,非静态数据成员的初始化都发生在进入构造函数体之前,此后构造函数可以更改成员的值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接