構造函數、析構函數調用虛函數

    昨天筆試的時候碰到一個很有意思的題目,大體如下:

class Parent
{
public:
    Parent()
    {
        doit();
    }
    ~Parent()
    {
        doit();
    }
    virtual void doit()
    {
        cout << "I'm Parent!" << endl;
    }
};
class Child: public Parent
{
public:
    Child()
    {
    }
    ~Child()
    {
    }
    void doit()
    {
        Parent::doit();
        cout << "I'm Child!" << endl;
    }
};
int main()
{
    Parent *p_base = new Child();
    p_base->doit();
    delete p_base;
    return 0;
}

    以前在項目中並沒有寫過在構造函數中調用虛函數的情況,這一般也是不允許的,增加了代碼的複雜度(參見Effective C++ 條款9)。這裏謹記C++繼承中構造、析構的順序就不難寫出答案:

I'm Parent!
I'm Parent!
I'm Child!
I'm Parent!

    但是我覺得題目應該可以出的更巧妙一些:

class Parent
{
public:
    Parent()
    {
        doit();
    }
    ~Parent()
    {
        doit();
    }
    virtual void doit()
    {
        cout << "I'm Parent!" << endl;
    }
};
class Child: public Parent
{
public:
    Child()
    {
        doit();
    }
    ~Child()
    {
        doit();
    }
    void doit()
    {
        Parent::doit();
        cout << "I'm Child!" << endl;
    }
};
int main()
{
    Parent *p_base = new Child();
    p_base->doit();
    delete p_base;
    return 0;
}

    如果你寫下:

I'm Parent!
I'm Parent!
I'm Child!
I'm Parent!
I'm Child!
I'm Parent!
I'm Child!
I'm Parent!

    那麼,恭喜你,你答錯了。因爲這個題目根本不會調用子類的析構函數,爲啥?因爲父類的析構函數是非虛函數,但是main函數中在釋放的靜態類型指向父類,所以它根本不調用子類的析構函數。這也是爲什麼在繼承體系中一般都需將父類的析構函數設爲虛函數(參見Effective C++ 條款7),否則有可能造成內存泄露。

     正確答案是:

I'm Parent!
I'm Parent!
I'm Child!
I'm Parent!
I'm Child!
I'm Parent!
I'm Child!
I'm Parent!


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