成员初始化列表

本文介绍了在C++中如何使用成员初始化列表来简化构造函数中的变量初始化过程,并通过示例说明了成员变量初始化顺序的重要性。

任一个对象的创建都要调用构造函数,而在构造函数中一般要给对象属性赋值。成员初始化列表(member initialize list)是构造函数中特有的语法,用以简化对对象属性的赋值。其用法如下:

class MyClass {
	int m_a, m_b, m_c;
public:
	MyClass(int a = 0, int b = 0, int c = 0) :
		m_a(a), m_b(b), m_c(c) {
	}
};
以上代码相当于:

class MyClass {
	int m_a, m_b, m_c;
public:
	MyClass(int a = 0, int b = 0, int c = 0) {
		m_a = a, m_b = b, m_c = c;
	}
};
用成员初始化列表的语法来表述很显然代码更简洁,并且其允许形参名和属性名相同而不会造成混淆,如以下代码片段也是正确的语法:

class MyClass {
	int a, b, c;
public:
	MyClass(int a = 0, int b = 0, int c = 0) :
		a(a), b(b), c(c) {
	}
};
成员初始化列表虽然好用但也要注意一点,就是列表中语句执行的顺序。请看如下代码:

class MyClass {
public:
	int m_b, m_a;
	MyClass(int a, int b) :
		m_a(a), m_b(m_a + b) {
	}
};

void tmyclass() {
	MyClass first(1, 2);
	cout << first.m_a << " " first.m_b << endl;
}
初步一看,你可能觉得输出结果为1和3,事实上m_b的值是不确定的,因为成员初始化列表中对属性赋值的顺序是和类属性声明的顺序一致的,和列表中初始化语句表达式的顺序无关,也就是说,在列表中虽然m_a初始化语句写在前面,但因为属性声明中m_b先于m_a声明,所以m_b先被初始化,而m_a这个时候是不确定的,所以输出结果中m_b的值是不确定的。

<think>我们被要求讲解成员初始化列表成员初始化列表C++中构造函数的一种特性,用于在构造函数体执行之前初始化类的成员变量。 接下来,我们将详细讲解成员初始化列表的用途、语法、优点以及注意事项。 </think>### 成员初始化列表详解 在 C++ 中,**成员初始化列表Member Initializer List)** 是构造函数的重要组成部分,用于直接在对象内存分配阶段初始化成员变量,而非在构造函数体内赋值。以下是其核心要点: --- #### 一、基本语法 ```cpp class MyClass { public: // 构造函数:成员初始化列表语法 MyClass(int a, double b) : m_a(a), m_b(b) { // 构造函数体(此时成员初始化) } private: int m_a; // 成员变量 double m_b; }; ``` - **位置**:位于构造函数参数列表后,函数体前,以冒号 `:` 开头 - **格式**:`成员名(初始值)` 或 `成员名{初始值}`,多成员用逗号分隔 - **执行时机**:**先于**构造函数体执行(内存分配后立即初始化) --- #### 二、核心优势 1. **效率提升** 对类类型成员直接调用**拷贝构造函数**而非"默认构造+赋值操作": ```cpp // 低效方式(在构造函数体内赋值) MyClass() { m_str = std::string("Hello"); // 先默认构造,再operator= } // 高效方式(初始化列表) MyClass() : m_str("Hello") {} // 直接拷贝构造 ``` 2. **强制场景支持** 以下情况**必须**使用初始化列表: - 初始化 `const` 成员(常量创建后不可修改) - 初始化引用成员(引用必须绑定对象) - 初始化没有默认构造函数的类成员 ```cpp class ConstDemo { public: ConstDemo(int x) : m_const(x) {} // const成员必须在此初始化 private: const int m_const; }; ``` 3. **避免未定义行为** 确保成员在使用前已被正确初始化: ```cpp class Danger { public: Danger(int val) : m_ptr(new int(val)) {} // 正确初始化指针 /* 错误示例(未初始化指针): Danger(int val) { m_ptr = new int(val); // 在此之前m_ptr是野指针 } */ private: int* m_ptr; }; ``` --- #### 三、初始化顺序规则 1. **声明顺序优先** 初始化按类中成员的**声明顺序**执行,与初始化列表中的书写顺序无关: ```cpp class OrderDemo { public: // 实际初始化顺序:m_b -> m_a(声明顺序) OrderDemo() : m_a(m_b + 1), m_b(5) {} private: int m_b; // 先声明 int m_a; // 后声明 }; ``` > ⚠️ 错误示例:若 `m_a` 依赖 `m_b`,但 `m_a` 声明在 `m_b` 前会导致未定义行为 2. **基类优先原则** 派生类构造函数中,基类初始化**优先于**派生类成员: ```cpp class Derived : public Base { public: Derived() : Base(42), m_derived(10) {} // 先初始化Base }; ``` --- #### 四、实际应用技巧 1. **委托构造(C++11+)** 复用其他构造函数的初始化逻辑: ```cpp class Delegation { public: Delegation() : Delegation(0, 0.0) {} // 委托双参数构造 Delegation(int a, double b) : m_a(a), m_b(b) {} }; ``` 2. **聚合初始化C++11+)** 对数组/结构体成员直接初始化: ```cpp class ArrayInit { public: ArrayInit() : m_arr{1, 2, 3} {} // 初始化数组 private: int m_arr[3]; }; ``` 3. **默认成员初始化C++11+)** 结合类内初始值与初始化列表: ```cpp class SmartInit { public: SmartInit(int x) : m_x(x) {} // 覆盖类内初始值 private: int m_x = 10; // 类内默认值 }; ``` --- #### 五、重要注意事项 1. **资源管理** 在初始化列表初始化智能指针可避免资源泄漏: ```cpp // 推荐方式(异常安全) ResourceHolder() : m_ptr(std::make_unique<Resource>()) {} ``` 2. **避免循环依赖** 成员相互依赖时需调整声明顺序或改用构造函数体 3. **性能陷阱** 内置类型(`int`, `float`等)在初始化列表与构造函数体赋值效率相同,类类型差异显著
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值