1、原因:
在實(shí)現(xiàn)多態(tài)時(shí), 當(dāng)用基類指針操作派生類, 在析構(gòu)時(shí)候防止只析構(gòu)基類而不析構(gòu)派生類。
2、例子:
(1)、
#include<iostream> using namespace std; class Base{ public: Base() {}; ~Base() {cout << "Output from the destructor of class Base!" << endl;}; void DoSomething() { cout << "Do something in class Base!" << endl; }; }; class Derived : public Base{ public: Derived() {}; ~Derived() { cout << "Output from the destructor of class Derived!" << endl; }; void DoSomething() { cout << "Do something in class Derived!" << endl; }; }; int main(){ Derived* p = new Derived; p->DoSomething(); delete p; return 0; }運(yùn)行結(jié)果:
Do something in class Derived!
Output from the destructor of class Derived!
Output from the destructor of class Base!
代碼中基類的析構(gòu)函數(shù)不是虛函數(shù),在main函數(shù)中用繼承類的指針去操作繼承類的成員,釋放指針P的過(guò)程是:先釋放繼承類的資源,再釋放基類資源。
(2)、
#include<iostream> using namespace std; class Base{ public: Base() {}; ~Base() {cout << "Output from the destructor of class Base!" << endl;}; void DoSomething() { cout << "Do something in class Base!" << endl; }; }; class Derived : public Base{ public: Derived() {}; ~Derived() { cout << "Output from the destructor of class Derived!" << endl; }; void DoSomething() { cout << "Do something in class Derived!" << endl; }; }; int main(){ Base* p = new Derived; p->DoSomething(); delete p; return 0; }運(yùn)行結(jié)果:
Do something in class ClxBase!
Output from the destructor of class ClxBase!
代碼中基類的析構(gòu)函數(shù)同樣不是虛函數(shù),不同的是在main函數(shù)中用基類的指針去操作繼承類的成員,釋放指針P的過(guò)程是:只釋放基類的資源,而沒(méi)有調(diào)用繼承類的析構(gòu)函數(shù)。 調(diào)用DoSomething()函數(shù)執(zhí)行的也是基類定義的函數(shù)。
一般情況下,這樣的刪除只能夠刪除基類對(duì)象,而不能刪除子類對(duì)象,形成了刪除一半形象,造成內(nèi)存泄漏。
在公有繼承中,基類對(duì)派生類及其對(duì)象的操作,只能影響到那些從基類繼承下來(lái)的成員。如果想要用基類對(duì)非繼承成員進(jìn)行操作,則要把基類的這個(gè)函數(shù)定義為虛函數(shù)。 析構(gòu)函數(shù)自然也應(yīng)該如此:如果它想析構(gòu)子類中的重新定義或新的成員及對(duì)象,當(dāng)然也應(yīng)該聲明為虛的。
(3)、
#include<iostream> using namespace std; class Base{ public: Base() {}; virtual ~Base() {cout << "Output from the destructor of class Base!" << endl;}; virtual void DoSomething() { cout << "Do something in class Base!" << endl; }; }; class Derived : public Base{ public: Derived() {}; ~Derived() { cout << "Output from the destructor of class Derived!" << endl; }; void DoSomething() { cout << "Do something in class Derived!" << endl; }; }; int main(){ Base* p = new Derived; p->DoSomething(); delete p; return 0; }運(yùn)行結(jié)果:
Do something in class ClxDerived!
Output from the destructor of class ClxDerived!
Output from the destructor of class ClxBase!
代碼中基類的析構(gòu)函數(shù)被定義為虛函數(shù),在main函數(shù)中用基類的指針去操作繼承類的成員,釋放指針P的過(guò)程是:釋放了繼承類的資源,再調(diào)用基類的析構(gòu)函數(shù)。調(diào)用DoSomething()函數(shù)執(zhí)行的也是繼承類定義的函數(shù)。
3、總結(jié):
基類指針可以指向派生類的對(duì)象(多態(tài)性),如果刪除該指針delete p;就會(huì)調(diào)用該指針指向的派生類析構(gòu)函數(shù),而派生類的析構(gòu)函數(shù)又自動(dòng)調(diào)用基類的析構(gòu)函數(shù),這樣整個(gè)派生類的對(duì)象完全被釋放。如果析構(gòu)函數(shù)不被聲明成虛函數(shù),則編譯器實(shí)施靜態(tài)綁定,在刪除基類指針時(shí),只會(huì)調(diào)用基類的析構(gòu)函數(shù)而不調(diào)用派生類析構(gòu)函數(shù),這樣就會(huì)造成派生類對(duì)象析構(gòu)不完全。所以,將析構(gòu)函數(shù)聲明為虛函數(shù)是十分必要的。
新聞熱點(diǎn)
疑難解答