文章
C++ 构造函数初始化列表(Constructor Initialization List)
目录
- 以下是对 C++ 构造函数初始化列表(Constructor Initialization List) 的全面整理和详细说明,涵盖历史、语法、作用、推荐使用方式及与构造体内赋值的对比。
- ✅ 一、什么是构造函数初始化列表?
- 🔹 语法形式:
- 📌 举例:
- ✅ 二、初始化列表的历史背景与标准支持
- ✅ 三、为什么要使用初始化列表?
- ✅ 与构造体内赋值的对比:
- 🔍 举例对比:
- ✅ 初始化列表(推荐):
- ❌ 构造体内赋值(不推荐):
- ✅ 四、初始化列表的必要性:哪些情况必须使用?
- ✅ 以下情况必须使用初始化列表:
- 📌 示例:const 和引用成员
- ✅ 五、初始化顺序注意点
- 建议: 按成员声明顺序书写初始化列表,避免潜在 bug。
- ✅ 六、默认构造器与初始化列表结合使用
- ✅ 七、总结
- 📘 附:统一初始化语法示意图
以下是对 C++ 构造函数初始化列表(Constructor Initialization List) 的全面整理和详细说明,涵盖历史、语法、作用、推荐使用方式及与构造体内赋值的对比。#
✅ 一、什么是构造函数初始化列表?#
在 C++ 中,当类有成员变量时,我们通常希望在对象构造时对这些成员进行初始化。构造函数初始化列表是一种专门用于在对象构造时初始化成员的语法。
🔹 语法形式:#
ClassName::ClassName(args) : member1(val1), member2(val2) {
// 构造函数体(可为空)
}
📌 举例:#
class Book {
private:
std::string title;
int page;
public:
Book() : title{"Default Book Title"}, page{0} { }
};
✅ 二、初始化列表的历史背景与标准支持#
| 语法特性 | 所属标准 | 示例 |
|---|---|---|
初始化列表语法 : member(...) | ✅ C++98 | : title("Default") |
统一初始化语法 {}(花括号) | ✅ C++11 | : title{"Default"} |
默认构造器 = default | ✅ C++11 | Book() = default; |
删除构造器 = delete | ✅ C++11 | Book(const Book&) = delete; |
| 委托构造函数 | ✅ C++11 | Book() : Book("X", 0) {} |
✅ 三、为什么要使用初始化列表?#
✅ 与构造体内赋值的对比:#
| 项目 | 初始化列表 | 构造体内赋值 |
|---|---|---|
| 执行时机 | 对象构造前(直接初始化) | 对象构造后(先默认构造再赋值) |
| 效率 | ✅ 高 | ❌ 低(多一次构造) |
| const 成员支持 | ✅ 支持 | ❌ 不支持(编译报错) |
| 引用成员支持 | ✅ 支持 | ❌ 不支持 |
| 推荐 | ✅ 是 | ❌ 否(不推荐用于类成员) |
🔍 举例对比:#
✅ 初始化列表(推荐):#
Book::Book() : title("C++ Primer"), page(500) { }
title在构造时直接用"C++ Primer"构造。page在构造时直接被初始化为500。- 效率更高、语义更明确。
❌ 构造体内赋值(不推荐):#
Book::Book() {
title = "C++ Primer"; // 默认构造后又赋值,效率低
page = 500;
}
title先用默认构造创建空字符串,再执行赋值操作。- 等于做了两件事,不必要。
✅ 四、初始化列表的必要性:哪些情况必须使用?#
✅ 以下情况必须使用初始化列表:#
| 类型 | 示例 | 说明 |
|---|---|---|
const 成员 | const int id; | 必须在初始化列表中初始化 |
| 引用成员 | std::string& ref; | 必须在初始化列表中绑定引用对象 |
| 没有默认构造函数的类成员 | SomeClass member; | 只能通过初始化列表传参构造 |
| 成员是父类 | class Derived : public Base | 必须在初始化列表中构造父类 |
📌 示例:const 和引用成员#
class A {
const int id;
std::string& ref;
public:
A(int i, std::string& r) : id(i), ref(r) { }
};
如果尝试在构造函数体中赋值,会报错:
A(int i, std::string& r) {
id = i; // ❌ 错误:const 成员不能赋值
ref = r; // ❌ 错误:引用成员必须在初始化列表中绑定
}
✅ 五、初始化顺序注意点#
⚠️ 初始化顺序 = 成员在类中声明的顺序,而不是初始化列表中的顺序!
class Example {
int a;
int b;
public:
Example() : b(2), a(1) { } // ⚠️ 实际先初始化 a,再 b
};
建议: 按成员声明顺序书写初始化列表,避免潜在 bug。#
✅ 六、默认构造器与初始化列表结合使用#
如果成员变量在类中有默认值,也可以使用 = default 来自动生成构造函数:
class Book {
std::string title = "Default";
int page = 0;
public:
Book() = default; // 会使用上述默认值
};
也可以和初始化列表结合使用更灵活构造:
Book::Book(std::string t, int p) : title(std::move(t)), page(p) { }
✅ 七、总结#
| 特性 | 初始化列表 |
|---|---|
| 最早支持 | C++98 |
| 推荐使用 | ✅ 是,尤其成员是类对象、const、引用 |
| 更高效 | ✅ 是(直接初始化) |
| 安全 | ✅ 更安全(支持 {} 花括号) |
| 适用场景 | 类成员初始化、父类初始化、常量/引用成员、复杂构造 |
📘 附:统一初始化语法示意图#
| 语法 | 标准 | 说明 |
|---|---|---|
int x = 1; | C++98 | 拷贝初始化 |
int x(1); | C++98 | 直接初始化 |
int x{1}; | ✅ C++11 | 列表初始化 |
MyClass obj{arg1, arg2}; | ✅ C++11 | 更安全的构造方式 |