直接上代碼
上面紅色框起來的部分就是類成員初始化列表,成員初始化列表一般用在類的構造函數中,包括拷貝構造函數。對於這種用法,作爲C++程序員一點都不陌生。下面從幾個疑惑開始講解,成員初始化列表:
1.什麼時候必須要使用初始化列表
(1)初始化成員有引用
以上代碼編譯器會報錯,編譯器不允許這樣初始化,至於爲什麼不允許,後面再探討,只能按照一下方式來初始化引用成員數據
這樣編譯器就不會報錯了
(2)初始化const類型成員
這樣初始化const 類型成員編譯器會報錯,至於編譯器爲什麼會允許這樣做,還沒明白。按照以下做法就不會報錯
(3)類繼承於一個父類,且父類含有有參數的構造函數
(3)含有類成員變量,且類成員的構造函數有參數
2.爲什麼要使用成員初始化列表,答案是爲了提高程序的效率
既然發明了這個語法,一定有一定的道理,且一定有利於程序的運行。以下代碼可以非常清晰的說明:
class A {
public:
int m_a;
int m_b;
A(){
cout << "A 的構造函數" << endl;
}
A(int tmp):m_a(tmp),m_b(tmp) {
cout << "A 的拷貝構造函數" << endl;
}
~A() {
cout << "A 的析構函數" << endl;
}
};
class B {
public:
int tt_a;
int tt_b;
A m_aobj;
B(int a, int b) : tt_a(a), tt_b(b) {
m_aobj = a;
cout << "B 的構造函數" << endl;
}
~B() {
cout << "B 的析構函數" << endl;
}
};
int main()
{
//A a_obj1(10,20);
B b(10, 20);
std::cout << "Hello World!\n";
return 0;
}
這時候m_aobj 成員我們沒有用初始化列表來初始化,運行結果爲
如果m_aobj換成在初始化列表中初始化,如下代碼
class B {
public:
int tt_a;
int tt_b;
A m_aobj;
B(int a, int b) :m_aobj(a), tt_a(a), tt_b(b) {
//m_aobj = a;
cout << "B 的構造函數" << endl;
}
~B() {
cout << "B 的析構函數" << endl;
}
};
運行結果就變成
很明顯的看到後者少調用了一次A的構造函數和一次析構函數。因爲前者編譯器會生成一個臨時對象。由此說明成員初始化列表優化程序運行效率。
(3)使用成員初始化列表需要注意哪些細節
(1)成員初始化列表會被編譯器轉換爲代碼並被放在用戶代碼之前。‘
(2)成員的初始化並不是按照初始化列表的順序來的,而是按照成員在類的定義順序來初始化
class A {
public:
int m_a;
int m_b;
A(int a):m_a(a){
cout << "A 的構造函數" << endl;
}
~A() {
cout << "A 的析構函數" << endl;
}
};
class B {
public:
int tt_a;
int tt_b;
B(int a, int b) : tt_a(a), tt_b(b) {
//m_aobj = a;
cout << "B 的構造函數" << endl;
}
~B() {
cout << "B 的析構函數" << endl;
}
};
class C {
public:
A aa;
B bb;
C(int a) :bb(a,a), aa(a) {
cout << "C 的構造函數" << endl;
}
};
int main()
{
//A a_obj1(10,20);
C c(10);
std::cout << "Hello World!\n";
return 0;
}
這裏我們的初始化列表順序是 B A,定義順序是A B。運行結果如下
顯然是按照定義的順序來初始化的,而不是初始化列表順序。