C/C++基類的解構函式為什麼必須定義為虛擬函式?
C/C++基類的解構函式為什麼必須定義為虛擬函式?
為什麼基類的解構函式是虛擬函式?
在實現多型時,當用基類操作派生類,在析構時防止只析構基類而不析構派生類的狀況發生。
(1)第一種情況:沒有多型,建立派生類物件,基類的解構函式不是虛擬函式
#include<iostream> using namespace std; //基類 class ClxBase{ public: ClxBase() {}; //解構函式不是虛擬函式 ~ClxBase() { cout << "Output from the destructor of class ClxBase!" << endl; }; void DoSomething() { cout << "Do something in class ClxBase!" << endl; }; }; //派生類 class ClxDerived : public ClxBase{ public: ClxDerived() {}; ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; void DoSomething() { cout << "Do something in class ClxDerived!" << endl; }; }; int main(){ //沒有多型,派生類物件 ClxDerived *p = new ClxDerived; p->DoSomething(); delete p; return 0; } //執行結果 Do something in class ClxDerived! Output from the destructor of class ClxDerived! Output from the destructor of class ClxBase!
這段程式碼中基類的解構函式不是虛擬函式,在main函式中用派生類的指標去操作派生類的成員。釋放指標P的過程是:先釋放派生類的資源(執行~ClxDerived()),再釋放基類資源(C++ primer裡說編譯器總是顯示呼叫派生類物件基類部分的解構函式~ClxBase())。
(2)第二種情況:有多型,建立派生類物件,基類的解構函式不是虛擬函式
#include<iostream> using namespace std; //基類 class ClxBase{ public: ClxBase() {}; //解構函式不是虛擬函式 ~ClxBase() { cout << "Output from the destructor of class ClxBase!" << endl; }; void DoSomething() { cout << "Do something in class ClxBase!" << endl; }; }; //派生類 class ClxDerived : public ClxBase{ public: ClxDerived() {}; ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; void DoSomething() { cout << "Do something in class ClxDerived!" << endl; } }; int main(){ //有多型 ClxBase *p = new ClxDerived; p->DoSomething(); delete p; return 0; } //執行結果 Do something in class ClxBase! Output from the destructor of class ClxBase!
這段程式碼中基類的解構函式同樣不是虛擬函式,不同的是在main函式中用基類的指標去操作派生類的成員。釋放指標P的過程是:只是釋放了基類的資源,而沒有呼叫派生類的解構函式(因沒有多型,靜態繫結,只執行基類的解構函式~ClxBase())。呼叫dosomething()函式執行的也是基類定義的函式。
一般情況下,這樣的刪除只能夠刪除基類物件,而不能刪除子類物件,形成了刪除一半的現象從而造成記憶體洩漏。正因為如此,需要將基類的解構函式定義為虛解構函式!!
在公有繼承中,基類對派生類及其物件的操作,只能影響到那些從基類繼承下來的成員。如果想要用基類對非繼承成員進行操作,則要把基類的這個函式定義為虛擬函式。
解構函式自然也應該如此:如果它想析構子類中的重新定義或新的成員及物件,當然也應該宣告為虛的。
(3)第三種情況:有多型,建立派生類物件,基類的解構函式是虛擬函式
#include<iostream>
using namespace std;
//基類
class ClxBase{
public:
ClxBase() {};
virtual ~ClxBase() {
cout << "Output from the destructor of class ClxBase!" << endl;
};
virtual void DoSomething() {
cout << "Do something in class ClxBase!" << endl;
};
};
//派生類
class ClxDerived : public ClxBase{
public:
ClxDerived() {};
~ClxDerived() {
cout << "Output from the destructor of class ClxDerived!" << endl;
};
void DoSomething() {
cout << "Do something in class ClxDerived!" << endl;
};
};
int main(){
//有多型
ClxBase *p = new ClxDerived;
//當基類是虛擬函式時,基類的指標將表現為派生類的行為(非虛擬函式將表現為基類行為)
p->DoSomething();
delete p;
return 0;
}
//執行結果
Do something in class ClxDerived!
Output from the destructor of class ClxDerived!
Output from the destructor of class ClxBase!
這段程式碼中基類的解構函式被定義為虛擬函式,在main函式中用基類的指標去操作派生類的成員。釋放指標P的過程是:先釋放了繼承類的資源,再呼叫基類的解構函式。呼叫dosomething()函式執行的也是繼承類定義的函式。