在类中初始化字段的原因是什么?

yan*_*pas 4 c++ initialization class c++11

在C++中,可以在类中初始化类的字段的值,如:

class X
{
  int a = 5;
}
Run Code Online (Sandbox Code Playgroud)

它是什么原因?它有用吗?默认的ctor完全相同.似乎我无法使用位掩码(int a : 3)初始化值.

Seb*_*ach 9

权威(这看起来非常类似于早期的标准提案N2756):

类内成员初始化程序

在C++ 98中,只能在类中初始化整数类型的静态const成员,并且初始化程序必须是常量表达式.这些限制确保我们可以在编译时进行初始化.例如:

int var = 7;

class X {
    static const int m1 = 7;        // ok
    const int m2 = 7;                   // error: not static
    static int m3 = 7;              // error: not const
    static const int m4 = var;          // error: initializer not constant expression
    static const string m5 = "odd"; // error: not integral type
    // ...
};
Run Code Online (Sandbox Code Playgroud)

C++ 11的基本思想是允许在声明它(在其类中)的地方初始化非静态数据成员.然后,构造函数可以在需要运行时初始化时使用初始化程序.考虑:

class A {
public:
    int a = 7;
};
Run Code Online (Sandbox Code Playgroud)

这相当于:

class A {
public:
    int a;
    A() : a(7) {}
};
Run Code Online (Sandbox Code Playgroud)

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

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
};
Run Code Online (Sandbox Code Playgroud)

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
};
Run Code Online (Sandbox Code Playgroud)

如果成员由类内初始化程序和构造函数初始化,则只完成构造函数的初始化(它"覆盖"默认值).所以我们可以进一步简化:

class A {
public:
    A() {}
    A(int a_val) : a(a_val) {}
    A(D d) : b(g(d)) {}
    int a = 7;
    int b = 5;  
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
};
Run Code Online (Sandbox Code Playgroud)


abe*_*nky 5

通常,您的类定义位于头文件 ( .h) 中,而您的构造函数位于实现文件 ( .cpp) 中。

有几次我看到一个错误,头文件有一长串成员变量,而实现文件初始化它们......但不小心跳过了一个成员,导致了错误。

目视检查,代码看起来是正确的。大量成员宣布;许多成员已初始化。单一值的缺失并不明显。

通过将所有初始化放在与声明相同的位置,可以更容易地查看是否忘记初始化一个成员。


class MySample
{

private:
    int m_CountSamples       { 0 };
    int m_SampleWidth        { sizeof(int) };
    double m_SamplePrecision { 3.14 };
    bool m_fieldIsSorted;                       // It is obvious which field got skipped!
    enumMeaning fieldMeaning { eProductionSample };
};    
Run Code Online (Sandbox Code Playgroud)

  • 我正在研究一个已有近 30 年历史的代码库……它有很多代码味道。但这就是现实。并非所有代码都是干净的。 (5认同)
  • 如此多的字段以至于您可能会忘记初始化某些内容,这听起来像是代码味道。这个班级可能有太多的责任。 (2认同)
  • @phresnel,这是一种可能性,但类的定义中有五个以上的成员变量并不罕见。 (2认同)