一、認識構造函數
當創建一個類類型對象時,類通過一個或者幾個特殊的成員函數來控制對象的初始化,這種函數就是構造函數。它的任務就是用來初始化類對象的成員的,所以當創建類對象或者類對象被創建就會調用構造函數。
構造函數的幾個特點:
1.函數名和類名必須一樣,沒有返回值。
2.當沒有顯式的定義構造函數時,系統會自己生成默認的構造函數。
3.構造函數可以重載。
1 class Date 2 { 3 public: 4 Date() 5 { } 6 Date(int day) 7 { 8 _year = 1949; 9 _month = 10; 10 _day = day; 11 } 12 void print() 13 { 14 cout << _year << "-" << _month << "-" << _day << endl; 15 } 16 17 private: 18 int _year=1990; 19 int _month; 20 int _day; 21 };
在上面的代碼中,定義了一個簡單的Date類類型,可以看到有顯式的給出了構造函數,第一個是沒有參數列表且函數不做任何事的,還有一個是有一個整型參數day的,就是當我傳了一個day參數,則在函數內部把它的year和month初始化為1994和10。這樣的兩個構造函數就構成了重載,因為能夠重載,所以在寫構造函數的時候要保證只有一個缺省的構造函數。參數列表為空或者參數全缺省稱為缺省構造函數。
當不傳參的定義一個Date類型對象,會調用顯式定義的缺省構造函數,在沒有初始化列表的情況下采取類內初始化或默認初始化,上面的程序中,如果不傳參,那么構建的對象的_year成員為1990,另外兩個值為隨機值。
牢記:
我們在沒有顯式的定義構造函數時,系統會自動生成一個默認構造函數。當我們定義了一些其他的構造函數時,這個類就將沒有默認構造函數。所以當我們顯式的定義了其他構造函數,最好把默認構造函數也顯式的定義一遍。這樣也有好處,就是系統生成的默認構造函數有可能執行錯誤的操作或者無法完成類成員的初始化(例如:有一個成員是類類型的對象且它沒有缺省的構造函數)。
當我們定義的默認構造函數並不需要干什么事情,只是因為上面的情況才顯式的定義它,那么此時的默認構造函數等同於系統生成的默認構造函數,那么我們可以這么定義:
Date() = default;
因為在新標准中,如果需要系統默認的行為,就可以通過在參數列表后加上=default來使編譯器生成構造函數。
二、初始化列表
如下圖所示,在冒號和花括號之間的代碼部分稱為構造函數的初始值列表,它的作用是給創建的對象的某些成員賦初值。這種是在構建對象的時候的初始化,是在對象創建成功之前完成的,和在函數體內賦值是不一樣的,函數體內賦值是你的對象成員都已經創建好后對成員進行的賦值。
那么,可以看到,這種初始化並不是必須的。但是在以下幾種情況時是必須進行初始化的:
1.成員是const類型。
2.成員是引用類型。
3.有一個成員是類類型的對象(且它沒有缺省的構造函數)
1 class Time 2 { 3 public: 4 Time( ) 5 { 6 7 } 8 9 private: 10 int _hour; 11 }; 12 class Date 13 { 14 public: 15 Date(int year=1990,int month=1,int day=1) 16 :_year(year), _month(month), _day(day), t(10) 17 { } 18 void print() 19 { 20 cout << _year << "-" << _month << "-" << _day << endl; 21 } 22 private: 23 int _year=1990; 24 int _month; 25 int _day; 26 Time t; 27 };
解釋:
1.對於const和引用類型,必須要進行初始化,所以他們必須在初始化列表中進行初始化。
2.當類類型成員有缺省的構造函數時,在創建對象的時候體統會默認調用,因為不用傳參。當你的構造函數不是缺省的,如果不在初始化列表中進行調用構造函數,系統就無法知道怎么調用t的構造函數,那么就無法創建t了。
如上代碼中,需要在參數列表中調用t的構造函數才不會出錯。
成員初始化順序:
在上面的初始列表中,每個成員只能出現一次,因為一個變量多次初始化是無意義的。
還有重要的一點,初始化列表的順序並不限定初始化的執行順序。成員的初始化順序是與類中定義的順序保持一致。可以看看下面的初始化列表:

在這里的意思是想要用1來初始化_month,再用_month初始化_year。但其實是_year被先初始化,而此時你的_month並沒有初始化,所以,最后的結果是_year是一個隨機值。
所以,最好讓構造函數初始值的順序與成員聲明的順序保持一致。