第六篇:為多型基類宣告虛解構函式

穆晨發表於2017-01-27

前言

       在很多類中,可以看到其解構函式都是宣告為虛擬函式的。

       那麼,為何要將解構函式宣告為虛擬函式?哪些情況要將解構函式宣告為虛擬函式?

       本文將為你解惑。

       在使用 C++ 實現多型的時候,有一點一定要清楚:當派生類物件經由基類指標被刪除,而此基類的解構函式沒有被宣告為虛擬函式的話,那麼解構函式只會釋放基類部分的成員而無視派生類成員。

       如果不對這一點加以防範,那麼很多時候,會帶來記憶體洩露這樣災難性的後果。

問題描述

       假設,有以下幾個類,分別代表:鍾,原子鐘,水鍾,腕錶:

 1 //
 2 class TimeKeeper {
 3 public:
 4     TimeKeeper();
 5     ~TimeKeeper();
 6     //......
 7 };
 8 
 9 // 原子鐘
10 class AtomicClock : public TimeKeeper {
11     //......
12 };
13 
14 // 水鍾
15 class WaterClock : public TimeKeeper {
16     //......
17 };
18 
19 // 腕錶
20 class WristWatch : public TimeKeeper {
21     //......
22 };

       由於很多客戶只關注一個時間的結果,對如何實現時間根本沒興趣,這時我們可以定義一個函式,它返回指標指向一個基類指標,指向新生成的派生類物件:

1 TimerKeeper *ptk = getTimeKeeper();

       必須先說明一下,這個函式返回的指標指向物件必須是heap。

       好了,使用完這個指標,那麼必須要delete掉吧,現在問題來了:對於不同的這幾個派生類物件:原子鐘,水鍾,腕錶,呼叫的確實相同的解構函式 - 基類解構函式。

解決之道

       如要不同的物件執行其所屬類自身的解構函式,那麼相信你也自然而然想到了:使用虛解構函式來實現這種多型性。

       因此:

       對於要拿來實現多型的基類,其解構函式一定要宣告為虛擬函式。

       也就是說,任何類只要帶有虛擬函式,那麼也幾乎可以肯定其解構函式也要宣告為虛擬函式。

       而對於不用拿來當基類的類,或者拿來當基類但是不需要實現多型的類,則不要將解構函式宣告為虛擬函式型別。

       因為這樣增加了無謂的開銷,虛擬函式是會有一些開銷的,至於開銷是什麼,以及相關細節,可以查閱其他 C++ 資料,本文不再累述。

小結

       如果有某個類你希望將它宣告為抽象類,但是一時又沒確定設哪個成員函式為純虛擬函式,那麼自然而然想到可以將其解構函式宣告為純虛擬函式。不過在這種情況下,這個純虛擬函式必須有定義,原因不解釋。

相關文章