多態基類的析構函數必須加上virtual

《Effective C++》說:

        因爲C++明確指出,當derived class對象經由一個base class指針被刪除,而base class帶着一個non-virtual析構函數,其結果未有定義---實際執行時通常發生的是對象的derived成分沒被銷燬。如:baseclass *ptb = derivedclassFuc() //子類的一個函數; 其中baseclass中有個non-virtual析構函數。解決這一問題的方法就是把基類中的析構函數聲明爲virtual,通常還有其他virtual函數。任何class只要還有virtual函數都幾乎確定應該也有一個virtual析構函數。                                     

       如果class不含virtual函數,通常表示它並不意圖被用做一個base class.當class不企圖被當作base class,令其析構函數爲virtual往往是個餿主意。許多人的心得是:只有當class內含至少一個virtual函數,才爲它聲明virtual析構函數。

有時候令Class帶一個pure virtual析構函數,可能頗爲便利,純虛函數導致抽象類,也就是不能被實體化的類,你不能爲這種類型創建對象。所以爲你希望它成爲抽象的那個類聲明一個pure virtual析構函數,這樣你就不需要擔心析構函數的問題了,不過你必須爲這個pure virtual析構函數提供一份定義:如,AWOV::~AWOV ( ) { …….},析構函數的運作方式是,最深層派生的那個class其析構函數最先被調用,然後是其每一個base class的析構函數被調用。編譯器會在AWOV的derived classes的析構函數中創建一個對~AWOV的調用動作,所以你必須爲這個函數提供一份定義,否則,連接器會出問題。

=======================================
把析構函數定義成虛函數,可以有效的防止在之後繼承的時候,子類指針的內存泄露.
比如,
class A
class B:public A
A *ptr=new B
在這種情況下調用析構函數的時候,就會發生刪除了A的空間而沒有刪除B的空間,
所以將基類定義爲抽象類,可以讓其子類動態的去調用它自身的函數。

========================================

class Base
{
public:
    Base(){}
    virtual void VirFun()
    {
    }
     ~Base(){}    //實際上這裏必須加virtual 
private:
    //Some attribute
};

class Sub : public Base
{
public:
    Sub(){}
    virtual void VirFun()
    {
    }
    ~Sub(){}
private:
    //Some attribute
};

上面的例子是個簡單的多態。

在我們應用的時候,我們經常會這麼幹:

Base * pBase = new Sub();//new了一個Sub對象,它實際上包含了Base 的子對象。
pBase->VirFun(); //很好,它會根據實際的類型調用Sub 的 VirFun()
delete pBase;//完蛋了,它調用了Base的析構。Sub的析構?這可不關我事,我可是Base類型的。

於是內存泄漏了。。。

給Base的析構函數加上virtual之後呢?

delete pBase; //很好,它繼續多態調用實際類型對象的析構。

大家知道,子類的析構函數會自動調用父類的析構。

於是,啊哈,終於安全了。

至此,大家應該對題目的意思有了大概的瞭解了。

有沒有發現,virtual 析構函數挺有意思的,它的子類析構函數名字和父類不同,一樣會重寫父類的析構函數。

爲什麼題目要強調“多態 基類”呢?

class Base
{
public:
    Base(){}
    void Fun()
    {
    }
   

    virtual ~Base(){}
private:
    //Some attribute
};

class Sub : public Base
{
public:
    Sub(){}
    void Fun()
    {
    }


    ~Sub(){}
private:
    //Some attribute
};

這樣的繼承中,有沒有必要給父類析構函數加virtual呢?

從語法意義上來說,是應該的,因爲你像下面這樣寫的時候,語法是沒有錯誤的:

Base * pBase = new Sub();//new了一個Sub對象,它實際上包含了Base 的子對象。
delete pBase; //很好啊,程序多安全啊。有什麼問題嗎?

在這樣寫的時候,你應該譴責自己。

pBase的所有行爲都是Base中定義的,爲什麼要給它一個Sub的身體呢?

(爲什麼網上很多男士都愛用美女作頭像呢。。。)

所以,當你設計的類系不具備多態性的時候,請不要:

1.用父類的指針指向子類;

2.給父類的析構函數加上virtual(畢竟虛函數表也是不小的開銷不是?)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章