c++ 初始化成员列表

本文介绍了C++中初始化的两种方式:构造函数内赋值和初始化列表初始化,并分析了它们的优缺点。构造函数内赋值存在无法对const或引用类型赋值、效率低等问题;初始化列表初始化可解决这些问题,且效率更高。推荐使用成员初始化列表。

在c++中,初始化一般有两种方式,一种在构造函数内通过赋值初始化,一种是通过初始化列表初始化。

下面通过对两者进行比较,来分析初始化成员列表和构造函数内赋值的优缺点。

一、构造函数内赋值:

class Text {
public:
	Text() {
		std::cout << "I'm Text Construction" << std::endl;
	}
	Text(int num):_num(num) {
		std::cout << "I'm Text Construction" << "num = " << num << std::endl;
	}

private:
	int _num;
};


class Workers {
public:
	//一、构造函数内通过赋值初始化
	//缺点:无法对const修饰的_sex、或者引用类型_name赋值
	//如果Text类不存在默认构造函数,也会报错
	Workers(){
		_age = 30;
		_weigth = 120;

		//这样写 会调用一次默认构造函数,加一次带参构造函数,因为多调用了一次默认构造函数、效率降低
		_text = Text(15);	
	}
private:
	int _age;
	int _weigth;
	//打开以下注释会报错
	//const std::string _sex;
	//std::string &_name;
	Text _text;	
};

缺点:

1、无法对const修饰的_sex、或者引用类型_name赋值
如果Text类不存在默认构造函数,也会报错。

2、通过_text = Text(15);对_text赋值,会调用一次默认构造函数,加一次带参构造函数,因为多调用了一次默认构造函数、造成效率降低。

二、通过初始化列表初始化:

/*需要使用初始化成员列表时的几种情况
*1、当数据成员是引用时
*2、当数据成员被const修饰时(因为const或者引用只能被初始化,不能赋值)
*3、当数据成员是对象时,该对象无默认构造函数,即有带参的构造函数时
*4、子类需要初始化父类的private数据成员时
*/

class F {
public:
	F(int &num):_num(num) {
		std::cout << "F num:" << _num << std::endl;
	}

private:
	int _num;
};

class WorkersEx : public F
{
public:
	WorkersEx(int &num) : _weigth(120),_name("a"),
		_sex("M"),	//const
		_age(num),	//引用
		_text(num), //对象 只调用一次带参构造函数
		F(num)		//父类
	{}
private:
	int &_age;
	int _weigth;
	const std::string _sex;
	std::string _name;
	Text _text;
};
​

优点:
1、可以对const成员初始化
2、可以对引用类型成员进行初始化
3、对对象进行初始化时,比构造函数内赋值效率更高,因为只调用了一次带参的构造函数,不会调用默认构造函数。而且不需要额外的赋值运算。


需要注意的是:初始化列表初始化的顺序和变量声明的顺序一致,和初始化中的顺序无关。

总结:

推荐使用成员初始化列表,因为其不仅可以满足const和引用数据成员初始化的要求,还可以有效预防初始化带参对象时调用默认构造函数的问题。

### C++ 初始化成员列表的用法与示例 在C++中,初始化成员列表(Initializer List)是一种用于在构造函数中初始化成员的有效方法。它不仅提高了代码的可读性,还避免了不必要的默认构造和赋值操作,从而提升程序性能[^1]。 #### 基本语法 初始化成员列表的基本语法如下: ```cpp ClassName::ClassName(参数列表) : 成员变量1(初始值1), 成员变量2(初始值2), ... { // 构造函数体 } ``` #### 示例代码 以下是一个使用初始化成员列表的完整示例: ```cpp #include <iostream> using namespace std; class Point { public: // 构造函数使用初始化成员列表 Point(int x, int y) : _x(x), _y(y) {} void print() { cout << "Point(" << _x << ", " << _y << ")" << endl; } private: int _x; // 成员变量 int _y; // 成员变量 }; int main() { Point p(3, 5); // 创建对象并初始化 p.print(); // 输出结果 return 0; } ``` 在这个例子中,`_x` 和 `_y` 是通过初始化成员列表直接初始化的,而不是在构造函数体内进行赋值。这种方式更加高效,因为避免了先调用默认构造函数再赋值的过程[^4]。 #### 解决的问题 初始化成员列表解决了以下问题: 1. **常量成员初始化**:如果类中包含 `const` 类型的成员变量,则必须通过初始化成员列表进行初始化,而不能在构造函数体内赋值[^3]。 2. **引用成员初始化**:对于引用类型的成员变量,只能通过初始化成员列表进行初始化。 3. **提高效率**:相比于在构造函数体内赋值,初始化成员列表直接在内存分配时完成初始化,减少了额外的操作。 4. **防止类型窄化**:初始化成员列表可以防止隐式类型转换导致的精度丢失[^3]。 #### 注意事项 - 初始化顺序由成员变量在类中声明的顺序决定,而非初始化列表中的顺序[^1]。 - 如果初始化列表中未显式初始化某个成员变量,则会尝试使用其默认构造函数或默认初始化器[^2]。 #### 运行结果分析 针对用户提供的代码片段,以下是运行结果的详细分析: ```cpp #include <iostream> using namespace std; class A { public: A(int a) : _a1(a), _a2(_a1) {} // 初始化列表 void Print() { cout << _a1 << " " << _a2 << endl; } private: int _a2 = 2; // 默认成员初始化器 int _a1 = 2; // 默认成员初始化器 }; int main() { A aa(1); aa.Print(); } ``` 在此代码中,`_a1` 和 `_a2` 的初始化顺序由它们在类中声明的顺序决定。尽管 `_a2` 在初始化列表中被指定为 `_a2(_a1)`,但由于 `_a2` 的初始化发生在 `_a1` 之前(根据声明顺序),此时 `_a1` 尚未被正确初始化,因此 `_a2` 的值是未定义的。最终输出结果为 `1 随机值`[^2]。 ###
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值