15.4.4 虛析構函數
刪除指向動態分配對象的指針時,需要運行析構函數在釋放對象的內存之前清除對象。處理繼承層次中的對象時,指針的類型可能與被刪除對象的動態類型不同,可能刪除實際指向派生類對象的基類類型指針。
如果刪除基類指針,則需要運行基類析構函數並清除基類的成員,如果對象實際是派生類型的,則沒有定義該行為。要保證運行適當的析構函數,基類中的析構函數必須為虛函數。
如果析構函數為虛函數,那麼通過指針調用時,運行哪個析構函數將因指針所指對象類型的不同而不同。
像其他虛函數一樣,析構函數的虛函數性質都將繼承。因此,如果層次中根類的析構函數為虛函數,則派生類析構函數也將是虛函數,無論派生類顯式定義析構函數還是使用合成析構函數,派生類析構函數都是虛函數。
基類析構函數是三法則的一個重要例外。三法則指出,如果類需要析構函數,則類幾乎也確定需要其他復制控制成員。基類幾乎總是需要析構函數,從而將析構函數設為虛函數。如果基類為了將析構函數設為虛函數而具有空析構函數,那麼,類具有析構函數不表示也需要賦值操作符或復制構造函數。
即使析構函數沒有工作要做,繼承層次的根類也應該定義一個虛析構函數。
構造函數和賦值操作符不是虛函數
在復制控制成員中,只有析構函數應定義為虛函數,構造函數不能定義為虛函數。構造函數是在對象完全構造之前運行的,在構造函數運行的時候,對象的動態類型還不完整。
雖然可以在基類中將成員函數operator=定義為虛函數,但這樣做並不影響派生類中使用的賦值操作符。每個類有自己的賦值操作符,派生類中的賦值操作符有一個與類本身類型相同的形參,該類型必須不同於繼承層次中任意其他類的賦值操作符的形參類型。
將類的賦值操作符設為虛函數很可能會令人混淆,而且不會有什麼用處。
15.4.5 構造函數和析構函數中的虛函數
構造派生類對象時首先運行基類構造函數初始化對象的基類部分。在執行基類構造函數時,對象的派生類部分是未初始化的。實際上,此時對象還不是一個派生類對象。
撤銷派生類對象時,首先撤銷它的派生類部分,然後按照構造順序的逆序撤銷它的基類部分。
為了適應這種不完整,編譯器將對象的類型視為在構造或析構期間發生了變化。在基類構造函數或析構函數中,將派生類對象當作基類類型對象看待。
構造或析構期間的對象類型對虛函數的綁定有影響。
如果在構造函數或析構函數中調用虛函數,則運行的是為構造函數或析構函數自身類型定義的版本。
摘自 xufei96的專欄