1. 程式人生 > >effective c++乾貨之條款07:為多型基類宣告virtual解構函式

effective c++乾貨之條款07:為多型基類宣告virtual解構函式

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. 抽象類

一般而言,我們用普通類就可以實現多型,但是為什麼還要用抽象類呢?

如果你看到一個抽象類,那麼你可以確定它就是用來實現多型的,你會更加關注它子類的情況;

如果你看到一個普通的基類,你不確定它會不會被用來實現多型,會不會在某個地方被例項化。

簡而言之,不容易讓人產生迷惑。

抽象類實現方法:類中成員函式只要有一個是純虛擬函式,那麼這個類就會成為一個抽象類。