构造函数初始化必须采用初始化列表的情况
转自:https://blog.csdn.net/u012611878/article/details/79200544
https://my.oschina.net/assange/blog/542896
1.赋值与初始化
初始化为变量分配空间,一般变量是在编译时根据定义初始化;赋值是擦除旧值与写入新值的过程,没有空间的分配。
2.const/引用类型
当成员变量是const类型或者引用时,必须通过初始化列表初始化,而不能放在构造函数体中(这样就是赋值了),因为const和引用类型的变量必须声明时初始化。
static数据成员需要在类外初始化,int CSomeClass::myVar=3; static变量应该在类的构造函数前被初始化。
3.对象,且没有默认构造函数
数据成员是对象,且没有默认的构造函数。例子:
class Test { public: Test (int, int, int){ cout <<"Test" << endl; } private: int x; int y; int z; }; class Mytest { public: Mytest():test(1,2,3){ //初始化ok //test(Test(1,2,3));//error: no match for call to '(Test) (Test)' //test=Test(12,3,4);//error: no matching function for call to 'Test::Test()'
//test(1,2,3);//error: no match for call to '(Test) (int, int, int)' cout << "Mytest" << endl; }//注:在尝试下面三个时,初始化列表已删掉 private: Test test; //声明 };
错误1:尝试在内部初始化,不行
错误2:尝试在内部通过赋值的方式初始化,但没有默认的构造函数,即参数列表为空,那么test就会首先被默认初始化,但是Test类没有默认的构造函数从而出现错误,所以初始化只能放在列表中。
4.子类初始化父类私有成员
class Test{ public: Test(){} Test (int x){ int_x = x;} void show(){cout<< int_x << endl;} private: int int_x; }; class Mytest:public Test{ public: Mytest():Test(110){//打印出110 //Test(110); // 构造函数只能在初始化列表中被显示调用,不能在构造函数内部被显示调用 。不报错但打印随机数:14887136 } }; int main(){ Test *p = new Mytest(); p->show(); return 0; }
5.初始化列表效率更高
使用初始化列表是直接初始化,而在函数体内是先初始化再赋值。存在效率的差异,如果是类对象,那么效率更低。
注意:不论是否出现在初始化列表中,变量都会被在此处按照声明顺序进行初始化,所以为了保证效率,最好初始化列表顺序与声明顺序一致。
为什么变量的初始化顺序是按照声明而不是初始化列表的顺序?
因为需要考虑到析构的过程,析构按照构建的相反顺序,如果参照初始化列表的话,还需要再额外维护一个顺序,开销太大。