天天看點

第六篇:為多态基類聲明虛析構函數

前言

       在很多類中,可以看到其析構函數都是聲明為虛函數的。

       那麼,為何要将析構函數聲明為虛函數?哪些情況要将析構函數聲明為虛函數?

       本文将為你解惑。

       在使用 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++ 資料,本文不再累述。

小結

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