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