🎧1构造函数体赋值
🔎在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。
⭐️就像上述代码中的构造函数,其函数体的语句只能被称为赋予初值而不能称为初始化。因为初始化是在定义的同时赋值且只赋值一次,而构造函数体内是先定义后赋值。
🎧2初始化列表
2.1什么叫初始化列表?
🔎在C++中,构造函数的初始化列表是一种用于在创建对象时对成员变量进行初始化的特殊语法。它出现在构造函数的函数体之前,使用冒号
:
分隔构造函数的参数列表和初始化列表,初始话列表中的语句用逗号“,”隔开。
2.2初始化列表的作用?
🔎可以在对象创建时直接对成员变量进行初始化,而不需要在构造函数的函数体中再次进行赋值操作。这可以提高代码效率,并且在一些情况下是必要的,例如对于常量成员变量或引用成员变量。
2.3使用举例
🔎 以上代码乍一看这初始化列表和函数体赋值好像就是使用方式不一样。实则不然。就从功能角度来说,初始化列表只能用于初始化。而构造函数体中,可以实现其它的操作,比如打印。
2.4初始化列表的具体使用细则
1.每个成员在初始化列表中只能出现一次(初始化只能初始一次)
2.类中包含以下成员,必须放在初始化列表位置进行初始化
🔥引用成员变量
🔥const成员变量
🔥自定义类型成员变量(且该类没有默认构造函数)
💬引用成员变量比较好理解,因为之前我们已经讲过引用类型的变量必须初始化且不能被再次赋值。const成员变量无法被赋值,只能放在初始化列表进行初始化,而自定义类型如果没有默认的构造函数的话(编译器生成的无参的),也就不能先定义后再赋值,且该类里面也可能又引用或者const成员变量,所以必须再定义的同时初始化。
3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,
一定会先使用初始化列表初始化。
4.成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后
次序无关。
举例:
观察以下代码
class A { public: A(int a) :_a1(a) , _a2(_a1) {} void Print() { cout <<"a1=" << _a1 << " " <<"a2=" << _a2 << endl; } private: int _a2; int _a1; }; void test1() { A aa(1); aa.Print(); }
如果调用函数test1()会输出什么呢?
💬我们可以看到,虽然再初始化列表中_a1的顺序在_a2前面,但是由于声明顺序是_a2先声明,所以先初始化_a2.也就是先将_a1的值赋给_a2,但是由于此时的_a1并没有初值是一个随机值,所以会得到这样的结果。
🎧3两者的区别🚦
-
执行时机:
- 初始化列表: 初始化列表会在进入构造函数的函数体之前执行,即在构造函数开始执行之前。这确保了在进入函数体之前,所有的成员变量都已经得到了适当的初始化。
- 构造函数体内的赋值: 构造函数体内的赋值则是在进入构造函数的函数体后执行的操作。
-
语法形式:
- 初始化列表: 使用冒号
:
后面跟着成员变量的初始化语句。 - 构造函数体内的赋值: 在构造函数的函数体内,通过赋值语句对成员变量进行初始化。
- 初始化列表: 使用冒号
🎧4总结🚦
在实践中,推荐使用初始化列表,特别是对于非静态常量成员、引用成员或具有自定义构造函数的成员。这样可以确保在进入构造函数体之前,所有成员都得到了正确的初始化。