1. 程式人生 > >C++:為什麼在繼承關係中,父類的解構函式最好定義為虛擬函式?

C++:為什麼在繼承關係中,父類的解構函式最好定義為虛擬函式?

我們先來看一段簡單程式碼,A類有一個指標成員_pa,B類公有繼承了A類,然後自己有一個指標成員_pb:

class A{
public:
    A(int x = 1)
        :_pa(new int(x))
    {}

    ~A()
    {
        cout << "~A()" << endl;
    }
protected:
    int* _pa;
};

class B : public A{
public:
    B(int b)
        :A(b)
        ,_pb(new int(b))
    {}

    ~B()
    {
        cout << "~B()"
<< endl; } protected: int* _pb; };

如果不把父類的解構函式定義為虛擬函式,會有什麼問題?

void Test()
{
    A* pa = new B(0);//父類的指標指向了子類的物件
    delete pa;//
}

pa是A類的指標,它指向了新建立的B類物件,在析構時,理應呼叫B類的解構函式,然後執行結果是呼叫了A類的解構函式:
這裡寫圖片描述
原因就是,沒有構成多型,與型別有關,因為pa是父類的指標,就一定呼叫的是父類的解構函式。
但如果把A類的解構函式定義為虛擬函式:

......
    virtual ~A()
    {
        cout << "~A()" << endl;
    }
......

問題是,父子的解構函式名字不相同,就算我加了virtual使父類的解構函式變為虛擬函式,也不會被子類重寫啊。
其實,解構函式是一個特殊的函式,編譯器在編譯時,解構函式的名字統一為destucter,所以只要父類的解構函式定義為虛擬函式,不管子類的解構函式前是否加virtual(可以理解為編譯器優化),都構成重寫。
再看剛才的問題:

void Test()
{
    A* pa = new B(0);//父類的指標指向了子類的物件
    delete pa;//
}

父類的指標指向了子類的物件,然後呼叫重寫虛擬函式——解構函式,不就構成了多型嘛,而多型與型別無關,只與物件有關,所以呼叫的就是子類的析構函數了。