究竟什么時候該用虛析構函數?
C++中明確指出,當派生類對象經由一個基類指針被刪除,而此基類僅提供了non-virtual析構函數,其結果是未定義的。如果刪除基類指針,則需要運行基類構造函數并清除基類的成員,如果對象實際是指向派生類類型的對象,則沒有定義這種行為。實際執行是通常發生的是對象的derived成分沒有被銷毀,而派生類中的base class成分通常會被銷毀,這就造成了一個“局部銷毀”的對象,從而造成資源泄露。消除這個問題很簡答:給base class一個virtual析構函數,這會保證運行適當的析構函數。
所以,如果類要作為父類的話,要定義虛析構函數。
即使class完全不帶virtual函數,就要注意了,不要試圖去繼承它。如標準的string和標準庫中的容器vector,list,set等都不帶有任何的virtual函數,如果你試圖寫這樣的代碼:
class SpecialString:pulic std::string{...};
文章剛開始提到過的問題,你是不是能夠避免呢?有時候你會不自覺的義正言辭的去做的。拒絕誘惑吧,畢竟C++沒有提供類似于Java的final class禁止派生機制。
有時候令class帶有一個pure virtual析構函數,可能會帶來便利,如Meyers在《More Effective C++》中“條款33:將非尾端類設計為抽象類”曾經提到過的那樣。
這樣Base成為一個abstract class,當有時候你希望擁有abstract class,但是沒有任何pure virtual函數怎么辦?很簡答:為你希望成為abstract class的那個class聲明一個pure virtual析構函數吧。雖然abstract class不能被實例化,但是別忘了需要為pure virtual析構函數提供一個定義,這也只能在類外進行了:
Base::~Base(){} //pure virtual析構函數的定義
畢竟,派生類析構函數還是回調用此函數來析構其相應部分的。
最后請記住:
1) 帶多態性質的基類應該聲明一個virtual析構函數。如果class帶有任何virtual函數,它就應該擁有一個virtual析構函數。
2) 類的設計目的如果不是作為基類使用,或者不是為了具備多態性,就不應該聲明virtual析構函數。