C++学习笔记-成员初始化列表

成员初始化列表是C++中初始化类成员变量的一种更高效的方式。它在构造函数体执行之前就完成了成员变量的初始化,避免了先构造再赋值的性能开销。

传统初始化方式 vs 成员初始化列表

传统方式(不推荐)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Example
{
public:
    Example()
    {
        std::cout << "Create Example" << std::endl;
    }

    Example(int x)
    {
        std::cout << "Create Example with " << x << std::endl;
    }
};

class Entity
{
private:
    std::string m_Name;
    Example m_Example;
public:
    // 传统初始化方式 - 先构造,再赋值
    Entity() 
    { 
        m_Name = "Unknown";        // 这是赋值,不是初始化
        m_Example = Example(8);    // 这会创建临时对象,然后赋值
    }
};

成员初始化列表(推荐)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Entity
{
private:
    std::string m_Name;
    Example m_Example;
public:
    // 使用成员初始化列表 - 直接初始化
    Entity() : m_Name("Unknown"), m_Example(Example(8)) {}

    Entity(const std::string& name, const Example& example)
        : m_Name(name), m_Example(example) {}

    const std::string& GetName() const { return m_Name; }
};

性能对比示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class PerformanceTest
{
private:
    std::string m_Data;
public:
    // 方式1:构造函数体内赋值
    PerformanceTest(const std::string& data)
    {
        m_Data = data;  // 先调用默认构造函数,再调用赋值操作符
    }
    
    // 方式2:成员初始化列表
    PerformanceTest(const std::string& data) : m_Data(data)
    {
        // 直接调用拷贝构造函数,更高效
    }
};

必须使用成员初始化列表的情况

1. const成员变量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class ConstMember
{
private:
    const int m_Value;
public:
    // const成员必须在初始化列表中初始化
    ConstMember(int value) : m_Value(value) {}
    
    // 错误:const成员不能在构造函数体内赋值
    // ConstMember(int value) { m_Value = value; }  // 编译错误
};

2. 引用成员变量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class ReferenceMember
{
private:
    int& m_Ref;
public:
    // 引用成员必须在初始化列表中初始化
    ReferenceMember(int& ref) : m_Ref(ref) {}
    
    // 错误:引用不能在构造函数体内赋值
    // ReferenceMember(int& ref) { m_Ref = ref; }  // 编译错误
};

3. 没有默认构造函数的成员对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class NoDefaultConstructor
{
public:
    NoDefaultConstructor(int value) {}  // 只有带参构造函数
    // 没有默认构造函数
};

class Container
{
private:
    NoDefaultConstructor m_Member;
public:
    // 必须使用初始化列表
    Container() : m_Member(42) {}
    
    // 错误:m_Member没有默认构造函数
    // Container() { m_Member = NoDefaultConstructor(42); }  // 编译错误
};

初始化顺序

成员变量的初始化顺序由它们在类中的声明顺序决定,而不是初始化列表中的顺序:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class InitOrder
{
private:
    int m_First;   // 第一个被初始化
    int m_Second;  // 第二个被初始化
public:
    // 即使初始化列表的顺序不同,仍按声明顺序初始化
    InitOrder() : m_Second(2), m_First(1) {}
    
    // 建议:保持初始化列表顺序与声明顺序一致
    InitOrder(int a, int b) : m_First(a), m_Second(b) {}
};

总结

  1. 成员初始化列表要比在构造函数体内赋值更高效,应该优先使用成员初始化列表
  2. 初始化顺序:成员变量按照在类中的声明顺序进行初始化,而不是初始化列表中的顺序
  3. 必须使用场景:const成员、引用成员、没有默认构造函数的成员对象
  4. 最佳实践:总是使用成员初始化列表,保持列表顺序与声明顺序一致
updatedupdated2025-09-202025-09-20