本文重點:應該為多態基類聲明虛析構器。一旦一個類包含虛函數,它就應該包含一個虛析構器。如果一個類不用作基類或者不需具有多態性,便不應該為它聲明虛析構器。
1、原因:
在實現多態時, 當用基類指針操作派生類, 在析構時候防止只析構基類而不析構派生類。
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;
- }
運行結果:
Do something in class Derived!
Output from the destructor of class Derived!
Output from the destructor of class Base!
代碼中基類的析構函數不是虛函數,在main函數中用繼承類的指針去操作繼承類的成員,釋放指針P的過程是:先釋放繼承類的資源,再釋放基類資源。
(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;
- }
運行結果:
Do something in class ClxBase!
Output from the destructor of class ClxBase!
代碼中基類的析構函數同樣不是虛函數,不同的是在main函數中用基類的指針去操作繼承類的成員,釋放指針P的過程是:只釋放基類的資源,而沒有調用繼承類的析構函數。 調用DoSomething()函數執行的也是基類定義的函數。
一般情況下,這樣的刪除只能夠刪除基類對象,而不能刪除子類對象,形成了刪除一半形象,造成內存泄漏。
在公有繼承中,基類對派生類及其對象的操作,只能影響到那些從基類繼承下來的成員。如果想要用基類對非繼承成員進行操作,則要把基類的這個函數定義為虛函數。 析構函數自然也應該如此:如果它想析構子類中的重新定義或新的成員及對象,當然也應該聲明為虛的。
(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;
- }
運行結果:
Do something in class ClxDerived!
Output from the destructor of class ClxDerived!
Output from the destructor of class ClxBase!
代碼中基類的析構函數被定義為虛函數,在main函數中用基類的指針去操作繼承類的成員,釋放指針P的過程是:釋放了繼承類的資源,再調用基類的析構函數。調用DoSomething()函數執行的也是繼承類定義的函數。
3、總結:
基類指針可以指向派生類的對象(多態性),如果刪除該指針delete p;就會調用該指針指向的派生類析構函數,而派生類的析構函數又自動調用基類的析構函數,這樣整個派生類的對象完全被釋放。如果析構函數不被聲明成虛函數,則編譯器實施靜態綁定,在刪除基類指針時,只會調用基類的析構函數而不調用派生類析構函數,這樣就會造成派生類對象析構不完全。所以,將析構函數聲明為虛函數是十分必要的。
新聞熱點
疑難解答