C++:為什麼在繼承關係中,父類的解構函式最好定義為虛擬函式?
阿新 • • 發佈:2019-01-28
我們先來看一段簡單程式碼,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;//
}
父類的指標指向了子類的物件,然後呼叫重寫虛擬函式——解構函式,不就構成了多型嘛,而多型與型別無關,只與物件有關,所以呼叫的就是子類的析構函數了。