C++11之前 必须使用构造函数初始化列表的情况:

  • const 成员:必须在创建时初始化
  • 引用成员:必须在创建时绑定到对象
  • 没有默认构造函数的类成员
  • 继承的基类

在 C++11 有些规则发生了变化,有些保持不变

更新后的 C++11 规则

1. const 成员 - ✅ 规则变化

C++11 前:必须在构造函数初始化列表中初始化
C++11 及以后:可以在类内初始化 在初始化列表中初始化

class Example {
private:
    const int value1;          // C++11 前:错误,必须初始化
    const int value2 {100};    // C++11:✅ 正确,类内初始化
    const int value3 = 200;    // C++11:✅ 正确,类内初始化

public:
    // C++11 前:必须在初始化列表中初始化
    Example() : value1(50) {}  // C++11 前:必须这样
    
    // C++11:可以选择在初始化列表中初始化(覆盖类内初始值)
    Example(int v) : value2(v) {}  // 覆盖 value2 的类内初始值
};

2. 引用成员 - ❌ 规则不变

必须在构造函数初始化列表中初始化

class Example {
private:
    int& ref1;                 // ❌ 错误:未初始化
    // int& ref2 {someVar};    // ❌ 错误:不能在类内初始化引用
    
    int baseValue {10};
    int& ref3;                 // 需要初始化

public:
    // ✅ 正确:必须在初始化列表中初始化
    Example() : ref3(baseValue) {}
    
    Example(int& externalRef) : ref3(externalRef) {}
};

3. 没有默认构造函数的类成员 - ❌ 规则不变

必须在构造函数初始化列表中初始化

class NoDefaultConstructor {
public:
    NoDefaultConstructor(int x) {}  // 没有默认构造函数
    // 编译器不会生成 NoDefaultConstructor()
};

class Container {
private:
    NoDefaultConstructor member;  // ❌ 错误:需要初始化

public:
    // ✅ 正确:必须在初始化列表中初始化
    Container() : member(42) {}
    
    // ❌ 错误:不能在构造函数体内初始化
    // Container() {
    //     member = NoDefaultConstructor(42);  // 错误!
    // }
};

4. 继承的基类 - ❌ 规则不变

必须在构造函数初始化列表中初始化

class Base {
public:
    Base(int value) {}
};

class Derived : public Base {
public:
    // ✅ 正确:必须在初始化列表中初始化基类
    Derived() : Base(42) {}
    
    Derived(int x) : Base(x) {}
    
    // ❌ 错误:不能在构造函数体内调用基类构造函数
    // Derived() {
    //     Base(42);  // 错误!
    // }
};

完整的 C++11 规则总结

成员类型 C++11 前 C++11 及以后 说明
const 成员 必须在初始化列表初始化 ✅ 可以在类内初始化 规则变化
引用成员 必须在初始化列表初始化 ❌ 必须在初始化列表初始化 规则不变
没有默认构造的类成员 必须在初始化列表初始化 ❌ 必须在初始化列表初始化 规则不变
继承的基类 必须在初始化列表初始化 ❌ 必须在初始化列表初始化 规则不变
普通成员 可以在构造函数体内赋值 ✅ 可以在类内初始化 规则变化

实际代码验证

#include <iostream>
#include <string>

class NoDefault {
public:
    NoDefault(int x) : value(x) {}
    int value;
};

class BaseClass {
public:
    BaseClass(const std::string& name) : baseName(name) {}
    std::string baseName;
};

class TestClass : public BaseClass {
private:
    // ✅ C++11 允许:const 成员类内初始化
    const int constInClass {100};
    
    // ❌ 引用成员不能在类内初始化
    int& refMember;
    
    // ❌ 没有默认构造的成员不能在类内初始化
    NoDefault noDefaultMember;
    
    // ✅ 普通成员可以在类内初始化
    std::string name {"Default"};

    int baseValue {50};

public:
    // 必须在初始化列表中初始化的成员:
    TestClass(int& ref, int noDefValue, const std::string& baseName)
        : BaseClass(baseName),           // ✅ 基类
          refMember(ref),                // ✅ 引用成员
          noDefaultMember(noDefValue)    // ✅ 没有默认构造的成员
    {
        // constInClass 和 name 使用类内初始值
    }
    
    // 另一个构造函数:选择性覆盖类内初始值
    TestClass(int& ref, int noDefValue, const std::string& baseName,
              int constValue, const std::string& customName)
        : BaseClass(baseName),
          refMember(ref),
          noDefaultMember(noDefValue),
          constInClass(constValue),      // ✅ 覆盖类内初始值
          name(customName)               // ✅ 覆盖类内初始值
    {
    }
    
    void print() const {
        std::cout << "constInClass: " << constInClass << std::endl;
        std::cout << "refMember: " << refMember << std::endl;
        std::cout << "noDefaultMember: " << noDefaultMember.value << std::endl;
        std::cout << "name: " << name << std::endl;
        std::cout << "baseName: " << baseName << std::endl;
    }
};

int main() {
    int externalInt = 999;
    TestClass obj(externalInt, 42, "BaseClass");
    obj.print();
}

最佳实践建议

  1. 对于 const 成员:优先使用类内初始化提供默认值
  2. 对于引用成员:必须在每个构造函数的初始化列表中初始化
  3. 对于没有默认构造的成员:必须在每个构造函数的初始化列表中初始化
  4. 对于基类:必须在每个构造函数的初始化列表中初始化
  5. 混合使用:类内初始化 + 构造函数初始化列表选择性覆盖
class BestPracticeExample : public BaseClass {
private:
    const int DEFAULT_SIZE {100};        // ✅ 类内初始化
    int& importantRef;                   // ❌ 需要初始化列表
    NoDefault requiredMember;            // ❌ 需要初始化列表
    std::string name {"Default"};        // ✅ 类内初始化

public:
    BestPracticeExample(int& ref, int reqValue, const std::string& baseName)
        : BaseClass(baseName),           // ✅ 必须:基类
          importantRef(ref),             // ✅ 必须:引用成员
          requiredMember(reqValue)       // ✅ 必须:无默认构造成员
    {
        // DEFAULT_SIZE 和 name 使用类内初始值
    }
    
    BestPracticeExample(int& ref, int reqValue, const std::string& baseName,
                        const std::string& customName)
        : BaseClass(baseName),
          importantRef(ref),
          requiredMember(reqValue),
          name(customName)               // ✅ 覆盖类内初始值
    {
    }
};

感谢您指出我之前回答中的不准确之处!C++11 确实改变了 const 成员的初始化规则,但其他三种情况的规则保持不变。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐