在 C++ 中,成员初始化列表(Member Initializer List) 用于在构造函数中初始化类的成员变量或基类,比在构造函数体内赋值更高效(尤其是对 const 成员、引用成员和类类型成员)。下面通过几个例子详细说明其用法和优势。


1. 基本语法

1
2
3
ClassName(参数列表)  成员1(初始值), 成员2(初始值), ..., 基类(参数) {
构造函数体
}
  • 初始化顺序:基类 → 成员变量(按声明顺序,而非初始化列表顺序)→ 构造函数体。

2. 典型使用场景

(1) 初始化基类

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
#include iostream
#include string

class Animal {
public
Animal(const stdstring& name) name_(name) {}
void Speak() { stdcout I am name_ stdendl; }
private
stdstring name_;
};

class Dog public Animal {
public
Dog(const stdstring& name, int age)
Animal(name), 必须先初始化基类
age_(age) 再初始化成员变量
{}
private
int age_;
};

int main() {
Dog my_dog(Buddy, 3);
my_dog.Speak(); 输出 I am Buddy
return 0;
}

关键点:

  • 如果基类没有默认构造函数(如 Animal 必须传 name),子类必须通过初始化列表调用基类构造。

(2) 初始化 const 成员或引用成员

1
2
3
4
5
6
7
8
9
10
11
12
class Example {
public
Example(int x, int& ref)
const_val_(x), const 成员必须在初始化列表赋值
ref_(ref) 引用成员必须在初始化列表绑定
{
构造函数体
}
private
const int const_val_; const 成员
int& ref_; 引用成员
};

为什么不能用构造函数体赋值?

  • const 和引用成员必须在创建时初始化,不能在构造函数体内修改。

(3) 初始化类类型成员(避免默认构造 + 拷贝赋值)

1
2
3
4
5
6
7
8
9
10
11
12
#include string

class Person {
public
Person(const stdstring& name, int age)
name_(name), 直接调用 stdstring 的拷贝构造函数
age_(age) 效率高于先默认构造再赋值
{}
private
stdstring name_;
int age_;
};

对比低效写法:

1
2
3
4
5
 低效版本:先默认构造 name_,再赋值
Person(const stdstring& name, int age) {
name_ = name; 调用了默认构造 + operator=
age_ = age;
}


(4) 初始化数组成员(C++11 起支持)

1
2
3
4
5
6
class ArrayWrapper {
public
ArrayWrapper() arr_{1, 2, 3} {} C++11 列表初始化
private
int arr_[3];
};

3. 必须使用初始化列表的情况

以下成员必须通过初始化列表初始化:

  1. const 成员

    1
    2
    3
    4
    5
    6
    class ConstExample {
    public
    ConstExample(int val) const_val_(val) {}
    private
    const int const_val_; 必须初始化列表赋值
    };
  2. 引用成员

    1
    2
    3
    4
    5
    6
    class RefExample {
    public
    RefExample(int& ref) ref_(ref) {}
    private
    int& ref_; 必须初始化列表绑定
    };
  3. 没有默认构造函数的类成员

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class NoDefault {
    public
    NoDefault(int x) {} 没有默认构造函数
    };

    class Container {
    public
    Container() member_(42) {} 必须初始化列表
    private
    NoDefault member_;
    };
  4. 基类没有默认构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Base {
    public
    Base(int x) {} 没有默认构造函数
    };

    class Derived public Base {
    public
    Derived() Base(42) {} 必须初始化列表
    };