Hello,everybody!構造函數的內容比較多,語法還有些復雜。我分成了兩篇文章進行講解,大家在看過構造函數(上)后再來看這篇文章更容易理解喲!
1.初始化列表的格式
類似這種格式,在初始化列表中第一行用冒號開頭,剩下的用逗號開頭。初始化列表結束后,后面才是函數體。
初始化列表也是初始化類中成員的一種方式,就目前這個例子感覺在初始化列表中初始化與在函數體中初始化沒啥區別。咱們還無法窺探其中的奧妙。
不過我先給大家一個建議:
能用初始化列表,就用初始化列表,用不了的時候再考慮用函數體初始化。
下面開始介紹初始化列表獨特的地方:
1.其實初始化列表才是類中成員定義的地方,初始化列表優先于函數體運行,等程序走到函數體時,類中的所有成員都已經被定義過了。這就意味著初始化后不可被修改的成員和定義時必須初始化的成員等只能通過初始化列表初始化。例如被const修飾過的成員和引用等。
被const修飾過的x就不能通過函數體初始化,因為x在初始化列表中已經定義并初始化過了(盡管我們沒有寫出來)。在函數體中做的工作是賦值,修改。
還有一個就是引用,因為引用要求在定義的時候必須初始化。
看過以上兩個例子可以知道,就算初始化列表中什么都不寫,它也會幫我們把類中的成員都定義好,然后我們在函數體中給成員修改,賦值。如果在初始化列表中直接完成初始化,就省去了在函數體中修改數據這一步驟,程序效率相對來說要高一點。
另外要補充一點:
既然初始化列表是成員定義的地方,那么同一成員變量只能被定義一次,不能被多次定義。
2.當類中的成員變量有自定義類型時
在上文中,我們提到:引用成員變量和const成員變量只能在初始化列表中初始化。
這里補充最后一條:自定義類型成員也只能在初始化列表中初始化。
在構造函數(上)中,我們提到:對于編譯器默認生成的構造函數,在對象實例化后對于內置類型不做處理,對于自定義類型回去調用它的默認構造函數。
在這個例子中,Date類型的成員中有一個A類型,在對象實例化后編譯器直接調用了A的默認構造函數看似好像沒啥問題,實際上和前兩行的黑體字表達的意思有所出入。
注意:在Date類型中,我們已經把默認構造函數寫出來了,這個構造函數不是編譯器默認生成的為什么還會回去調用A中的默認構造函數呢?
實際上是"大道同歸"。編譯器默認生成的構造函數也好,自己寫的構造函數也好,在調用函數體前,都會先運行初始化列表,在初始化列表中不管我們寫與不寫,都會幫我們定義好A _aa。在定義的過程中就相當于對象實例化,自然就會調用A中的默認構造函數!
那問題來了!如果A中沒有默認構造函數呢?比如,我把缺省參數去掉:
這時我們就需要在Date中構造函數的初始化列表中手動給A _aa初始化,否則會因為A中沒有可以調用的默認構造函數而報錯。
3.初始化列表與函數體搭配運用
除了引用成員變量,const成員變量和類成員變量,其他成員變量的初始化既可以在初始化列表中,也可以在函數體中,但建議在初始化列表中,原因在上文已經介紹的很清楚了。
雖然初始化列表的功能很強大,但也有它無法完成的任務,這時就需要和函數體配合使用:
如果需要動態開辟空間,在初始化列表中可以完成。但是空間是否開辟成功需要進行檢查,初始化列表就無法勝任了,需要搭配函數體使用。再比如一個數組的初始化需要用到循環語句,初始化列表也是無法完成的!