轉載自:
https://blog.csdn.net/coder_xia/article/details/7447822
常用的初始化可能如下:
1)賦值初始化
class Student
{
public:
Student(string in_name, int in_age)
{
name = in_name;
age = in_age;
}
private :
string name;
int age;
};
可以達到預期效果,不過不是最佳做法,因爲在構造函數中,是對name進行賦值,不是初始化,而string對象會先調用它的默認構造函數,再調用string類(貌似是basic_string類)的賦值構造函數,產生了臨時對象,速度慢;對於上例的age,因爲int是內置類型,應該是賦值的時候獲得了初值。
要對成員進行初始化,而不是賦值,可以採用初始化列表(member initialization list)改寫爲如下:
2)初始化列表
class Student
{
public:
Student(string in_name, int in_age):name(in_name),age(in_age) {}
private :
string name;
int age;
};
結果與上例相同,不過在初始化的時候調用的是string的拷貝構造函數,而上例會調用兩次構造函數,**在分配內存空間時直接初始化,**從性能上會有不小提升
有的情況下,是必須使用初始化列表進行初始化的:const對象、引用對象
3)初始化列表初始順序
考慮以下代碼:
#include <iostream>
using namespace std;
class Base
{
public:
Base(int i) : m_j(i), m_i(m_j) {}
Base() : m_j(0), m_i(m_j) {}
int get_i() const
{
return m_i;
}
int get_j() const
{
return m_j;
}
private:
int m_i;
int m_j;
};
int main()
{
Base obj(98);
cout << obj.get_i() << endl << obj.get_j() << endl;
return 0;
}
輸出爲一個隨機數和98,爲什麼呢?
因爲對於初始化列表而言,對成員變量的初始化,是嚴格按照聲明次序,而不是在初始化列表中的順序進行初始化,如果改爲賦值初始化則不會出現這個問題,當然,爲了使用初始化列表,還是嚴格注意聲明順序吧,比如先聲明數組大小,再聲明數組這樣。
類對象的構造順序:
1.分配內存,調用構造函數時,隱式/顯示的初始化各數據成員;
2.進入構造函數後在構造函數中執行一般賦值與計算。
以下三種情況下需要使用初始化成員列表:
■ 情況一、需要初始化的數據成員是對象的情況(這裏包含了繼承情況下,通過顯示調用父類的構造函數對父類數據成員進行初始化);
■情況二、需要初始化const修飾的類成員或初始化引用成員數據;
■ 情況三、子類初始化父類的私有成員;
■情況一的說明:數據成員是對象,並且這個對象只有含參數的構造函數,沒有無參數的構造函數;
如果我們有一個類成員,它本身是一個類或者是一個結構,而且這個成員它只有一個帶參數的構造函數,而沒有默認構造函數,這時要對這個類成員進行初始化,就必須調用這個類成員的帶參數的構造函數,如果沒有初始化列表,那麼他將無法完成第一步,就會報錯。
例子:
#include "iostream"
using namespace std;
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){ //初始化
cout << "Mytest" << endl;
};
private:
Test test; //聲明
};
int _tmain(int argc, _TCHAR* argv[])
{
Mytest test;
return 0;
}
輸出結果:
① 如果沒有mytest():test(1,2,3){}初始化列表就會報錯:
因爲Test有了顯示的帶參數的構造函數,那麼他是無法依靠編譯器生成無參構造函數的,所以沒有三個int型數據,就無法創建Test的對象。Test類對象是MyTest的成員,想要初始化這個對象test,那就只能用成員初始化列表,沒有其他辦法將參數傳遞給Test類構造函數。
②初始化列表在構造函數執行前執行(這個可以看上面的結果,對同一個變量在初始化列表和構造函數中分別初始化,首先執行參數列表,後在函數體內賦值,後者會覆蓋前者)。
■情況二的說明:對象引用或者cosnt修飾的數據成員
情況二:當類成員中含有一個const對象時,或者是一個引用時,他們也必須要通過成員初始化列表進行初始化,因爲這兩種對象要在聲明後馬上初始化,而在構造函數中,做的是對他們的賦值,這樣是不被允許的。
例子:
class Test
{
priate:
const int a; //const成員聲明
public:
Test():a(10){} //初始化
};
或
class Test
{
private:
int &a; //聲明
public:
Test(int a):a(a){} //初始化
}
■情況三的說明:子類初始化父類的私有成員,需要在(並且也只能在)參數初始化列表中顯示調用父類的構造函數:如下:
例子:
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){
//Test(110); // 構造函數只能在初始化列表中被顯示調用,不能在構造函數內部被顯示調用
};
};
int _tmain(int argc, _TCHAR* argv[])
{
Test *p = new Mytest();
p->show();
return 0;
};