原文鏈接 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 成員變量為只讀變量;