声明中的新C ++ 11成员初始化功能是否使初始化列表过时了?

时间:2014-06-10 20:04:31

标签: c++ c++11 constructor initialization declaration

使用C ++ 11,我们现在能够在头声明中初始化类成员:

class aClass
{
    private:
        int mInt{100};
    public:
         aClass();
        ~aClass();
};

所以我有点困惑。传统上,构造函数中的初始化列表已用于成员初始化:

aClass::aClass()
: mInt(100)
{
    ...
}

声明中的新C ++ 11成员初始化功能是否使初始化列表过时了?如果没有,一个优于另一个的优势是什么?什么情况会使声明初始化有利,或初始化列表有利?应该何时使用另一个?

3 个答案:

答案 0 :(得分:67)

不,它们并没有过时,因为本文Get to Know the New C++11 Initialization Forms类成员初始化部分(强调我的)中说过:

  

请记住,如果相同的数据成员在构造函数中同时具有类成员初始值设定项和mem-init,则后者优先。实际上,您可以通过以类成员初始值设定项的形式为成员指定默认值来利用此行为,如果构造函数没有明确的mem-该成员的init。否则,构造函数的mem-init将生效,覆盖类成员初始值设定项。 此技术在具有多个构造函数的类中非常有用

因此,虽然在类成员初始化是一个很好的方便,它不会删除对初始化列表的需要,但两个功能相反,它们为您提供了一种指定默认值并在需要时覆盖它们的好方法。这似乎也是Bjarne Stroustrup看到它的方式,他说:

  

这节省了一些输入,但真正的好处来自具有多个构造函数的类。通常,所有构造函数都为成员使用公共初始值设定项:

并提供了一个具有公共初始化程序的成员示例:

class A {
  public:
    A(): a(7), b(5), hash_algorithm("MD5"), s("Constructor run") {}
    A(int a_val) : a(a_val), b(5), hash_algorithm("MD5"), s("Constructor run") {}
    A(D d) : a(7), b(g(d)), hash_algorithm("MD5"), s("Constructor run") {}
    int a, b;
  private:
    HashingFunction hash_algorithm;  // Cryptographic hash to be applied to all A instances
    std::string s;                   // String indicating state in object lifecycle
};

并说:

  

hash_algorithm和s每个都有一个默认值的事实在代码混乱中丢失,并且在维护期间很容易成为问题。相反,我们可以将数据成员的初始化分解出来:

class A {
  public:
    A(): a(7), b(5) {}
    A(int a_val) : a(a_val), b(5) {}
    A(D d) : a(7), b(g(d)) {}
    int a, b;
  private:
    HashingFunction hash_algorithm{"MD5"};  // Cryptographic hash to be applied to all A instances
    std::string s{"Constructor run"};       // String indicating state in object lifecycle
};

注意:C ++ 11中的缺点

在C ++ 11中使用类成员初始化有一个缺点,因为它使类成为非聚合,我们不能再使用aggregate initialization,这可能相当令人惊讶。在C ++ 14中不是这种限制被删除的情况。有关详细信息,请参阅:C++11 aggregate initialization for classes with non-static member initializers

答案 1 :(得分:7)

不,它们不会过时。

如果需要构造函数参数来初始化类成员,初始化列表仍然是唯一的方法。

class A
{
 int a=7; //fine, give a default value
public:
 A();
};

class B
{
 int b; 
public:
 B(int arg) : b(arg) {}

 B(int arg, bool b) : b(arg) { ... }
};

请注意,如果两者都存在,构造函数的init将生效,覆盖类成员初始化,这对于指定类成员的默认值很有用。

答案 2 :(得分:5)

我看待它的方式,类内初始化是mem-initializer-lists的增强。在C ++ 03中,未在mem-initializer-list中列出的成员始终默认初始化。这意味着类的默认构造函数,并且没有对基本类型进行初始化。

类内初始化只允许您指定自己的默认值。有两种方法可以看待它。

一:如果您的类的大多数/所有构造函数想要为成员提供相同的初始值,请为该成员使用类内初始值设定项。对于其他成员,请使用mem-initializer-lists。当初始值取决于构造函数参数时,您当然必须使用它们。

另一个:为所有成员提供一个类内初始化程序,确切地说,类的默认构造函数将如何初始化它们。然后,非默认构造函数中的mem-initializer-lists获得"它与默认构造对象的区别。"