原文鏈接 https://www.cnblogs.com/dishengAndziyu/p/10906081.html
參考鏈接:https://www.cnblogs.com/laiqun/p/5776212.html
https://blog.csdn.net/zzyczzyc/article/details/87542418
https://www.cnblogs.com/cthon/p/9178701.html
http://blog.sina.com.cn/s/blog_4c79cc450100lkzh.html
1,初始化列表是在 C++ 中才引入的;
2,以“類中是否可以定義 const 成員?”這個問題來引入初始化列表:
1,const 這個關鍵字可以定義真正意義上的常量,也可以在某些情況下定義只讀變量;
3,小實驗:
1,下面的類定義是否合法?如果合法,ci 的值是什么,存儲在哪里?
1 #include <stdio.h>
2
3 class Test
4 {
5 private:
6 const int ci; // const 作用於 C++ 中的成員變量后得到的是只讀成員變量,只讀成員變量是不可以出現在成員符號左邊的;所以會出現第 10 行的錯誤信息;
7 public:
8 /*
9 Test() // 在這里編譯器顯示:ci 是一個 const 成員,沒有進行初始化;因此如果要初始化 ci 成員變量,必須要在這一行進行,這個時候就讓初始化列表出廠了;
10 {
11 ci = 10; // 在這里編譯器顯示:ci 在這個類中是一個只讀的成員變量;
12 }
13 */
14
15 /* 由上面的語句改換如下 */
16 Test() : ci(10) // ci 在初始化之后可以改變,因為 ci 在這里只是一個只讀的成員變量,僅僅是不能出現在賦值符號左邊而已;我們依舊可以通過指針的方式來修改 ci 里面的值;
17 {
18 // ci = 10;
19 }
20
21 int getCI()
22 {
23 return ci;
24 }
25 };
26
27 int main()
28 {
29 Test t; // 當這里沒有手工定義上面程序中的無參構造函數的時候,顯示有“未初始化的 const 的成員”的錯誤; 同時的當這里沒有通過類來定義對象的時候,可以通過編譯,說明 const 可以修飾 C++ 中的成員變量;
30
31 printf("t.ci = %d\n", t.getCI());
32
33 return 0;
34 }
4,C++ 中提供了初始化列表對成員變量進行初始化,其語法規則為:
1,代碼示例:
1 ClassName::ClassName() : m1(v1), m2(v1, v2), m3(v3) // 用 v1, (v1, v2), v3 分別對 m1, m2, m3 初始化;
2 {
3 // some other initialize operation;
4 }
1,初始化列表應該在構造函數的地方使用;
2,構造函數參數列表之后函數體之前定義初始化列表;
3,其作用就是對成員變量進行初始化;
2,注意事項(避免 bug 很重要):
1,成員的初始化順序與成員的聲明順序相同;
2,成員的初始化順序與初始化列表中的位置無關;
3,初始化列表先於構造函數的函數體執行;
(1)當構造函數的函數體開始執行的時候,對象已經創建完畢了,執行構造函數的函數體僅僅是為了初始化我們這個對象的狀態而已;
(2)所以說初始化列表既然是用於初始化,那么必須在我們這個類對象創建的同時來進行執行,而不應該是對象已經創建好了才來進行一系列的初始化工作,這一點是有明確差異的,這個差異也就是初始化和賦值之間的差異;
5,初始化列表的使用編程實驗:
1 #include <stdio.h>
2
3 class Value
4 {
5 private:
6 // int mi = 0; // 要初始化成員變量,只能使用初始化列表;在構造函 數當中的那是對成員變量賦值,不是初始化;
7
8 int mi;
9
10 public:
11 Value(int i)
12 {
13 printf("i = %d\n", i);
14 mi = i;
15 }
16
17 int getI()
18 {
19 return mi;
20 }
21 };
22
23 class Test
24 {
25 private:
26 /*
27 Value m2(2); // 這種明確的調用一個參數的方式也是有語法錯誤的;
28 Value m3(3);
29 Value m1(1);
30 */
31 Value m2;
32 Value m3;
33 Value m1;
34
35 public:
36 /*
37 Test() // 這里編譯器顯示沒有 value 類的無參構造函數來匹配調用;
38 {
39
40 }
41 */
42 Test() : m1(1), m2(2), m3(3) // 成員變量的初始化必須通過初始化列表來完成;
43 {
44 printf("Test::Test()\n"); // 初始化列表先於構造函數的函數體執行;
45 }
46 };
47
48 int main()
49 {
50 Test t;
51
52 return 0;
53 }
6,類中的 const 成員:
1,類中的 const 成員會被分配空間的;在這里注意:(只有編譯時 用立即數初始化的才是真的常量,const成員在編譯時 沒法直接賦值,能不能進符號表 就看編譯時是否可以直接知道值,類只是一個模子 所以不可能給模子賦值 只有在創建對象時才可能 因為創建對象時是分配空間的時候)
(1)const 成員分配的空間和我們整個類對象分配的空間一致;
2,類中的 const 成員的本質是只讀變量;
(1)根據編譯提供的錯誤 bug 信息而得來;
3,類中的const 成員只能在初始化列表中指定初始值;
(1)編譯器無法直接得到 const 成員的初始值,因此無法進入符號表成為真正意義上的常量;
(2) 運行時才來定義對象申請空間,調用構造函數,繼而來調用初始化列表初始化成員變量;
7,只讀成員變量編程實驗:
1,代碼示例:
1 #include <stdio.h>
2
3 class Value
4 {
5 private:
6 int mi;
7 public:
8 Value(int i)
9 {
10 printf("i = %d\n", i);
11 mi = i;
12 }
13 int getI()
14 {
15 return mi;
16 }
17 };
18
19 class Test
20 {
21 private:
22 const int ci;
23
24 Value m2;
25 Value m3;
26 Value m1;
27
28 public:
29 Test() : m1(1), m2(2), m3(3), ci(100)
30 {
31 printf("Test::Test()\n");
32 }
33
34 int getCI()
35 {
36 return ci;
37 }
38
39 int setCI(int v)
40 {
41 int* p = const_cast<int*>(&ci); // 通過指針來操作常量對象;
42
43 *p = v;
44 }
45 };
46
47
48 int main()
49 {
50 Test t;
51
52 printf("t.ci = %d\n", t.getCI());
53
54 t.setCI(10);
55
56 printf("t.ci = %d\n", t.getCI());
57
58 return 0;
59 }
這個實驗說明:類中的 const 成員不是真正意義上的常量,它只是只讀變量(編譯器告訴的);
8。小插曲:
1,初始化與賦值不同:
1,初始化:對正在創建的對象進行初始值設置;初始化的時候,對象還沒創建好,在創建的同時,我們將它的值確定了;
2,賦值:對已經存在的對象進行值設置;
1 int main()
2 {
3 int i = 0; // 這是初始化,初始化的時候 i 還不存在;
4 // ...
5 i = 0; // 這是賦值, i 是實際存在的了,並且 i 已經有一個值了,這個時候將 i 的值被改變了
6 }
9,小結:
1,類中可以使用初始化列表對成員進行初始化;
(1)類中不能直接初始化成員變量(不論變量為一般的還是類的對象),只能通過初始化列表來初始化;
2,初始化列表先於構造函數體執行;
3,類中可以定義 const 成員變量(這里是變量);
(1)const 作用於類的成員后得到的僅是只讀變量;
4,const 成員變量必須在初始化列表中指定初始值;
5,const 成員變量為只讀變量;

