(笔记):初始化列表之初始化顺序
一、前面已经介绍了初始化列表的好处,尤其对于类类型的变量来说,会提高效率,下面来介绍必须放在初始化列表的情况(无关效率问题):
1、常量成员,因为常量(const)只能初始化不能赋值(虽说不可以赋值,但是可以通过指针的方式来访问修改该值),所以必须放在初始化列表里面。
2、引用类型,引用必须在定义的时候初始化,并且不能重新赋值(这是C++中引用的使用规则,这点与指针是不同的,它在运行时刻不能改变),所以也要写在初始化列表里面
3、没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。对于这一点来说,上个笔记(构造函数之初 始化列表)中有记载。因为一个类类型的变量在定义的时候会自动调用默认构造函数进行初始化, 所以当一个类类型的成员变量没有默认构造函数时,只能在初始化列表 中进行。且是拷贝构造函数在起作用。如下代码:一个调用默认构造函数和赋值构造函数,另一个调用拷贝构造函数(两种情况已经在代码中标注):
1 #include<iostream> 2 3 using namespace std; 4 5 class Student1 { 6 public: 7 int a; 8 9 Student1() // 无参构造函数 10 { 11 cout << "默认构造函数Student1" << endl ; 12 } 13 14 Student1(const Student1& t1) // 拷贝构造函数 15 { 16 cout << "拷贝构造函数Student1" << endl ; 17 this->a = t1.a ; 18 } 19 20 Student1& operator = (const Student1& t1) // 赋值运算符 21 { 22 cout << "赋值函数Student1" << endl ; 23 this->a = t1.a ; 24 return *this; 25 } 26 }; 27 class Student2 28 { 29 public: 30 31 Student1 test ; 32 Student2(Student1 &t1){ //这样的话调用默认构造函数和赋值构造函数 33 test = t1 ; 34 } 35 // Student2(Student1 &t1):test(t1){} //这样的话仅仅调用拷贝构造函数, 36 }; 37 int main() 38 { 39 40 Student1 A; //进入默认构造函数 41 Student2 B(A); //进入拷贝构造函数 42 43 }
二、初始化顺序
初始化顺序最好要按照变量在类声明的顺序一致,否则会出现下面的特殊情况
仍然拿上面的代码作为例子,加入适当的代码,代码效果如下:
1 #include<iostream> 2 3 using namespace std; 4 5 class Student1 { 6 public: 7 int a; 8 int b; 9 void fprint(){ 10 cout<<" a = "<<a<<" "<<"b = "<<b<<endl; 11 } 12 13 Student1(int i):b(i),a(b){ } //异常顺序:发现a的值为0 b的值为2 说明初始化仅仅对b有效果,对a没有起到初始化作用 14 // Student1(int i):a(i),b(a){ } //正常顺序:发现a = b = 2 说明两个变量都是初始化了的 15 16 Student1() // 无参构造函数 17 { 18 cout << "默认构造函数Student1" << endl ; 19 } 20 21 Student1(const Student1& t1) // 拷贝构造函数 22 { 23 cout << "拷贝构造函数Student1" << endl ; 24 this->a = t1.a ; 25 } 26 27 Student1& operator = (const Student1& t1) // 赋值运算符 28 { 29 cout << "赋值函数Student1" << endl ; 30 this->a = t1.a ; 31 return *this; 32 } 33 34 }; 35 class Student2 36 { 37 public: 38 39 Student1 test ; 40 Student2(Student1 &t1){ 41 test = t1 ; 42 } 43 // Student2(Student1 &t1):test(t1){} 44 }; 45 int main() 46 { 47 48 Student1 A(2); //进入默认构造函数 49 Student2 B(A); //进入拷贝构造函数 50 A.fprint(); //输出前面初始化的结果 51 52 }
两种不同的初始化方法结果如下:
异常初始化顺序:
正常初始化顺序:
由上面的例子可知,初始化列表的顺序要跟你在类声明的顺序要一致。否则像上面的那种特殊情况,有些变量就不会被初始化。经过测试发现,类中变量为下面的情况也是能够正常初始化的:也就是说,只要成员变量的初始化不依赖其他成员变量,即使顺序不同也能正确的初始化。
1 int a; 2 int b; 3 int c; 4 Student1(int i):b(i),a(i),c(i){} 5 main: 6 Student1 A(2); 7 A.fprint();
结果:
1 int a; 2 int b; 3 int c; 4 Student1(int i,int j,int k):b(i),a(j),c(k){} 5 main: 6 Student1 A(2,3,4); 7 A.fprint();
结果:
欢迎大家关注我的微信公众号「佛系师兄」,里面会有各种其他技术文章。
比如
「反复研究好几遍,我才发现关于 CMake 变量还可以这样理解!」
更多好的文章会优先在里面不定期分享!打开微信客户端,扫描下方二维码即可关注!