條款7:為多態基類聲明virtual解構函式
C++明白指出,當derived class對象經由一個base class指標被刪除,而該base class帶著一個non-virtual解構函式,其結果未有定義。事實上,derived對象被局部銷毀,只有其base class部分記憶體被正確釋放。造成資源泄漏,敗壞資料結構。
任何class只要帶有virtual函數,都幾乎確定應該也有一個virtual解構函式。 如果class不含virtual函數,通常表示它不意圖被用作一個base class。當class不起圖被當做base class,令其解構函式為virtual往往是個餿主意:解構函式佔用對象空間;並且不再和其他語言(如C)有著相同的資料結構,不具有移植性。
心得:只有當class內含有至少一個virtual函數,才為它聲明virtual解構函式。
如果你曾經企圖繼承一個標準容器、string、或任何其他 ”帶有non-virtual解構函式“ 的class,你肯定遇到或將遇到麻煩。很不幸C++沒有提供類似java的final class的機制。
pure virtual函數導致abstract class(抽象類別),也就是不能被實體化(instantiated)的class。你不能為那種類型建立對象。
並非所有的base class的設計目的都是為了多態用途。某些classes的設計目的是作為base classes使用,不是為了多態。如條款6的Uncopyable,它們並非被設計用來經由base class介面(指標)處理derived class對象,因此它們不需要virtual解構函式。
小記: polymorphic(帶多態性質的)base classes應該聲明一個virtual解構函式。如果class帶有任何virtual函數,它就應該擁有一個virtual解構函式。
條款8:別讓異常逃離解構函式
C++並不禁止解構函式吐出異常,但它不鼓勵你這樣做。解構函式吐出異常就是危險,總會帶來過早結束程式或者發生不明確行為的風險。
解構函式絕對不要吐出異常。如果一個被解構函式調用的函數可能拋出異常,解構函式應該捕捉任何異常,然後吞下它們(不傳播)或結束程式。
如果客戶需要對某個操作函數運行期間拋出的異常做出反應,那麼class應該提供一個普通函數(而非在解構函式中)執行該操作。如果某個操作可能在失敗時拋出異常,而又存在某種需要必須處理該異常,那麼這個異常必須來自解構函式以外的某個函數。
條款9:絕不在構造和析構過程中調用virtual函數
在構造和析構期間不要調用virtual函數,因為這類調用從不下降至derived class調用函數(比起當前執行建構函式和解構函式的那層)。因為對象很可能已經不完整。
條款10:令 operater= 返回一個 reference to *this
先看一個連鎖賦值,int x, y, z; x=y=z=15。這樣是正確的,賦值操作符是右結合性的。為了實現連鎖賦值,賦值操作符必須返回一個reference指向操作符左側的實參。
注意,這隻是一個協議,並無強制性要求。
條款11:在operator=中處理 “自我賦值”
確保當前對象自我賦值時operator= 有良好行為。其中技術包括:1、比對 “來來源物件” 和 “目標對象” 的地址;2、精心周到的語句順序(需要臨時指標);3、以及copy-and-swap,也就是用copy建構函式建立一個臨時對象,之後將臨時對象和*this用swap函數交換。
條款12:複製對象時勿忘其每一個成分
copying函數,包括copy建構函式和copy assignment操作符,確保複製 “對象內的所有成員變數” 及 “所有base class 成分” 。