effective c++乾貨之條款07:為多型基類宣告virtual解構函式
阿新 • • 發佈:2018-12-15
1. 避免記憶體洩漏
首先,我們實現一個多型:
class CPeople { public: CPeople(){} virtual ~CPeople(){} }; class CChinese:public CPeople { public: CChinese(){...} ~CChinese(){...} } class CAmerican:public CPeople { public: CAmerican(){...} ~CAmerican(){...} } class CJapanese:public CPeople { public: CJapanese(){...} ~CJapanese(){...} }
這樣我們就可以用一個基類指標指向不同國家的人:
CPeople *pSomePeopleA = new CChinese;
CPeople *pSomePeopleB = new CJapanese;
CPeople *pSomePeopleC = new CAmerican;
然而,當我們delete掉基類指標時,就會出現記憶體洩漏的問題:
delete pSomePeopleA;
delete pSomePeopleB;
delete pSomePeopleC;
這是因為delete操作僅僅刪除了子類中基類的部分,而子類的部分並沒有釋放掉。
產生的原因是因為基類的解構函式是一個non-virtual析構。
這裡先說一下解構函式的運作方式:
如果一個子類物件的生命週期結束,那麼子類物件中的解構函式會呼叫其父類物件的解構函式,也就是從底往上依次呼叫析構,但不會出現自上而下呼叫析構,也就是說,如果刪除了一個具有non-virtual的父類物件,那麼它不會繼續向下呼叫析構,所以子類部分並沒有被刪除。
解決的方法顯而易見,將父類的non-virtual析構改為virtual解構函式:
class CPeople
{
public:
CPeople(){}
virtual ~CPeople(){}
};
這樣,編譯器就會從父類開始向下直到找到一個具有non-virtual解構函式的子類物件,然後再自底向上呼叫析構,這樣就可以避免記憶體洩漏。
2. 何時應該新增virtual析構
如果基類被設計的目的是為了實現多型,即class中至少有一個虛擬函式,那麼我們就要為這個基類新增虛析構。
3. 抽象類
一般而言,我們用普通類就可以實現多型,但是為什麼還要用抽象類呢?
如果你看到一個抽象類,那麼你可以確定它就是用來實現多型的,你會更加關注它子類的情況;
如果你看到一個普通的基類,你不確定它會不會被用來實現多型,會不會在某個地方被例項化。
簡而言之,不容易讓人產生迷惑。
抽象類實現方法:類中成員函式只要有一個是純虛擬函式,那麼這個類就會成為一個抽象類。