條款07 為多型基類宣告virtual析構函式

2021-06-28 07:31:37 字數 2233 閱讀 5453

(1)任何帶有虛函式的類都幾乎確定應該定義乙個虛析構函式。乙個經驗是:只有當類含有至少乙個virtual函式才會為它宣告virtual析構函式。

(2)如果乙個類不含有virtual函式,通常表示它並不意圖作為基類;當類不意圖作為基類,令其析構函式為virtual是個餿主意。因為有虛函式,該類就要有指向虛函式 表的指標,這樣的話,類物件的體積就會增大(參考sizeof計算類的大小)。

(3)作為基類的類應該具有析構函式,以保證在刪除(指向動態分配物件的)基類指標時,根據指標實際指向的物件所屬的型別執行適當的析構函式。

用於多型用途的繼承中,如果沒有為基類宣告virtual析構函式會引發問題,看下面的**。

class a 

~a()

//virtual ~a()

virtual void a()

};class b:public a

~b()

};int main()

執行的結果是:

問題出現在:基類a的指標指向了派生類b的物件,而該物件由乙個基類指標delete,此時的基類含有的是非虛的析構函式,這會導致災難。因為c++指出,當派生類物件經由乙個基類指標刪除,而基類帶有的是非虛的析構函式,其結果是未定義的——實際執行時通常發生的是物件的派生成分沒有被銷毀,然而基類部分卻被銷毀了,正如**中所示,a的析構函式呼叫了,但是派生類b的析構函式沒有被呼叫。於是這是乙個詭異的「區域性銷毀」的問題,會導致記憶體洩露,敗壞資料結構,在除錯時浪費時間。

解決方法:為基類新增乙個virtual析構函式,這樣,通過基類指標銷毀派生類物件就會將會呼叫派生類的建構函式,那麼會將整個物件銷毀。將基類a的析構函式改為注釋處所示的虛析構函式,那麼執行結果如下圖所示。

總結

(1)任何帶有虛函式的類都幾乎確定應該定義乙個虛析構函式。乙個經驗是:只有當類含有至少乙個virtual函式才會為它宣告virtual析構函式。

(2)如果乙個類不 含有virtual函式,通常表示它並不意圖作為基類;當類不意圖作為基類,令其析構函式為virtual是個餿主意。因為有虛函式,該類就要有指向虛函式 表的指標,這樣的話,類物件的體積就會增大(參考sizeof計算類的大小)。

上述的為基類宣告乙個虛析構函式只適用於多型基類上。這種類的設計目的是通過基類介面處理派生物件。但並不是所有基類設計的目的都是為了多型用途。如表中string和stl容器都不是設計作為基類使用,更不要提多型了。因此他們不需要虛析構函式。

如果你試圖繼承乙個沒有任何虛析構函式的類,包括stl容器如vector,list,unordered_map等,容易導致錯誤。

在複製控制成員中,只有析構函式應該定義為虛函式,建構函式不能定義為虛函式

建構函式是在物件完全構造之前執行的,在建構函式執行的時候,物件的動態型別還不完整。虛函式是在基類指標或引用執行派生類物件時起的作用不同,現在建構函式執行時,物件並沒有構造出來,那麼肯定不可能使用虛函式完成動態繫結。編譯器不允許將建構函式宣告為virtual的。

雖然可以在基類中將成員函式operator=定義為虛函式,但這樣做並不影響派生類中使用的賦值操作符。每個類有自己的賦值操作符,派生類中的賦值操作符有乙個與類本身型別相同的形參,該型別必須不同於繼承層次中任意其他類的賦值操作符的形參型別。

將賦值操作符符設為虛函式可能會令人混淆,而且沒什麼用。因為虛函式必須在基類和派生類中具有相同的形參,而派生類中賦值操作符應該有乙個與派生類自己類本身型別相同的形參(而不是乙個基類形參)。基類賦值操作符有乙個形參是自身類型別的引用,如果該操作符為虛函式,則每個類都將得到乙個虛函式成員,該成員定義了引數為乙個基類物件的operator=,但是,對派生類而言,這個操作符與賦值操作符是不同的。

這裡將了為什麼基類的析構應該為虛、構造和賦值操作符為什麼不能為虛,參考文章:條款09 絕不在構造和析構過程中呼叫virtual函式,看看為什麼不能在構造或析構函式中呼叫虛函式。

條款07 為多型基類宣告virtual析構函式

結論1 polymorphic 帶多型性質的 base classes 應宣告乙個virtual 析構函式。如果class帶有任何virtual函式,它就應該擁有乙個virtual析構函式。c 指出當derived class物件經由乙個base class指標被刪除,而該base class帶有乙...

條款07 為多型基類宣告virtual析構函式

條款07 為多型基類宣告virtual析構函式 1.c 明確指出,當子類物件經由乙個基類指標刪除,而該基類帶著乙個non virtual析構函式,其結果未有定義。實際執行時通常發生的是物件的derived成分沒有被銷毀。也就是不光子類 裡面的成員變數可能沒被銷毀,而子類的析構函式也未能執行起來。而基...

條款07 為多型基類宣告virtual析構函式

總結 1.帶有多型性質的基類,應該將其析構函式宣告為virtual,如果class帶有任何虛函式,他就應該有乙個virtual的析構函式。因為如果乙個基類的指標指向派生類的物件,而這個基類的析構函式不是虛函式的話,那麼在銷毀這個指標的時候,派生類對物件中的派生類成份沒有被銷毀,這樣會造成詭異的區域性...