這個(gè)是我們組的每日一例,主要目的是想通過老隊(duì)員指導(dǎo)新隊(duì)員,同時(shí)又可以鞏固大家的cpp知識(shí)。我們組長說,項(xiàng)目做完之后這些東東可以整理出書了~
這一份是我寫的,所以就發(fā)布出來啦!~這個(gè)還算寫得比較詳細(xì)吧!
Chapter One - 調(diào)用構(gòu)造函數(shù)對成員變量進(jìn)行構(gòu)造、初始化 在類構(gòu)造的時(shí)候,對于類成員變量的構(gòu)造貌似可以在構(gòu)造函數(shù)中完成,那為什么還需要成員初始化表呢?
我們來看看這樣的情況:
1 /* programme 1 */
2 class Base
3 {
4 public:
5 Base(int val)
6 : i(val) //這里為什么要放在成員初始化表呢?
7 {
8 //i = val??
9 }
10 ~Base(){}
11
12 private:
13 int i;
14 };
15
16 class UseBase
17 {
18 Base b;
19 public:
20 UseBase(){} //沒有用Base的構(gòu)造函數(shù)
21 ~UseBase(){}
22 };
23
24 int main()
25 {
26 return 0;
27 };
28 /* end of programme 1 */
程序出現(xiàn)這樣的錯(cuò)誤:error C2512: 'Base' : no appropriate default constructor available,在UseBase中Base沒有被合理地初始化。
1 /* programme 2 */
2
3 //

4
5 class UseBase
6 {
7 Base b;
8 public:
9 UseBase() : b(0){} //可以編譯通過
10 ~UseBase(){}
11 };
12
13 //

14
15 /* end of programme 2 */
由此可以看出成員初始化列表的一個(gè)要點(diǎn),調(diào)用構(gòu)造函數(shù)對成員變量進(jìn)行構(gòu)造、初始化。對于內(nèi)置成員變量(int、double等等,個(gè)人理解為C語言中就已經(jīng)有的類型,詳細(xì)信息參見Primer)而言沒有明顯的問題,但對于非內(nèi)置成員變量而言,即便編程者沒有在成員初始化表中顯示調(diào)用構(gòu)造函數(shù),編譯器也會(huì)隱式地調(diào)用默認(rèn)構(gòu)造函數(shù)。所謂“默認(rèn)構(gòu)造函數(shù)”就是指"$classname$(void)"這樣的形式。上面的例子就是因?yàn)檫@個(gè)原因而編譯失敗的,Base沒有提供默認(rèn)構(gòu)造函數(shù)。也就是說,需要特殊構(gòu)造的類必須在成員初始化列表進(jìn)行構(gòu)造、初始化。
而如果有默認(rèn)構(gòu)造函數(shù),是否就可以在成員初始化表中置之不理呢?答案是否定的,這涉及到效率問題。(以下程序可以中的Base完全可以用string類型來取代,但為了方便調(diào)試方式查看,所以重新編寫了Base。)
1 /* programme 3 */
2
3 class Base
4 {
5 public:
6 Base(void)
7 : i(0)
8 {
9 // breakpoint 1
10 }
11 // 賦值操作符重載
12 Base& operator= ( const int val )
13 {
14 i = val;// breakpoint 2
15 return *this;
16 }
17
18 ~Base(){}
19
20 private:
21 int i;
22 };
23 class UseBase
24 {
25 Base b;
26 public:
27 UseBase()
28 //: b(0)
29 {
30 b = 3;// breakpoint 3
31 }
32 ~UseBase(){}
33 };
34
35 int main()
36 {
37 UseBase ub;
38 return 0;
39 };
40 /* end of programme 3 */
breakpoint的順序?yàn)?-3-2,這說明UseBase中的Base既進(jìn)行了默認(rèn)構(gòu)造,之后又進(jìn)行了賦值,原本可以通過一個(gè)構(gòu)造函數(shù)完成的操作,現(xiàn)在分成了兩個(gè)步驟,效率降低了。
Chapter Two - 派生類的成員初始化表 在派生類的成員初始化表中,可以調(diào)用基類的構(gòu)造函數(shù)來初始化其基類成分。
1 /* programme 4 */
2 #include <iostream>
3 using namespace std;
4 class Base
5 {
6 public:
7 Base( const int val )
8 : i(val)
9 {
10 }
11
12 Base& operator= ( const int val )
13 {
14 i = val;
15 return *this;
16 }
17
18 virtual ~Base(){}
19
20 void print() const
21 {
22 cout << "val: " << i << endl;
23 }
24
25 private:
26 int i;
27 };
28
29 class Derived : public Base
30 {
31 public:
32 Derived( const int val )
33 : Base(val)
34 {}
35 };
36
37 int main()
38 {
39 Derived d(1);
40 d.print();
41 getchar();
42 return 0;
43 };
44 /* end of programme 4 */
一個(gè)小錯(cuò)誤,很多人可能會(huì)犯的:
1 /* programme 5 */
2 //

3
4 class Derived : public Base
5 {
6 public:
7 Derived( const int val )
8 //: Base(val)
9 {
10 Base(val);
11 }
12 };
13
14 //

15 /* end of programme 5 */
在構(gòu)造函數(shù)體內(nèi)直接調(diào)用基類的構(gòu)造函數(shù),但這樣是不能完成對基類成分的初始化的。這個(gè)語句的意義是創(chuàng)建一個(gè)臨時(shí)的Base對象。
Chapter Three - 初始化const、引用成員 利用成員初始化表能夠初始化const、引用成員,這在構(gòu)造函數(shù)體內(nèi)是無法做到的。因?yàn)橐话闱闆r下,const、引用的對象在聲明的時(shí)候就要同時(shí)將值或?qū)ο蠼壎ǖ揭黄稹?br>
1 /* programme 6 */
2 #include <iostream>
3 #include <string>
4 using namespace std;
5 class dummy
6 {
7 const int ci;
8 string& szStr;
9
10 public:
11 dummy(const int i, string &sz)
12 : ci(i)
13 , szStr(sz)
14 {}
15
16 void printi()
17 {
18 cout << "const int: " << ci << endl;
19 }
20
21 void printsz()
22 {
23 cout << "string&: " << szStr << endl;
24 }
25
26 void setsz(string &sz)
27 {
28 szStr = sz;
29 }
30 };
31
32 int main()
33 {
34 string _4ref("hello");
35 dummy d(10, _4ref);
36 d.printi();
37 d.printsz();
38 cout << endl;
39 d.setsz( string("goodbye") );
40 d.printsz();
41 cout << "_4ref: " << _4ref << endl;
42 getchar();
43 return 0;
44 };
45 /* end of programme 6 */
輸出結(jié)果
const int: 10
string&: hello
string&: goodbye
_4ref: goodbye