前言
在很多類中,可以看到其解構函式都是宣告為虛擬函式的。
那麼,為何要將解構函式宣告為虛擬函式?哪些情況要將解構函式宣告為虛擬函式?
本文將為你解惑。
在使用 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++ 資料,本文不再累述。
小結
如果有某個類你希望將它宣告為抽象類,但是一時又沒確定設哪個成員函式為純虛擬函式,那麼自然而然想到可以將其解構函式宣告為純虛擬函式。不過在這種情況下,這個純虛擬函式必須有定義,原因不解釋。