為什么基類的析構函數要寫成虛函數?


為什么基類的析構函數要寫成虛函數?

 答:在實現多態時,當用基類操作派生類,在析構時防止只析構基類而不析構派生類的狀況發生。

 

代碼說明如下

第一段代碼:

 1 #include<iostream>
 2 using namespace std;  
 3   
 4 class ClxBase  
 5 {public:  
 6    ClxBase() {}  
 7    ~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl}  
 8   
 9    void DoSomething() { cout << "Do something in class ClxBase!" << endl; }  
10 };  
11   
12 class ClxDerived : public ClxBase  
13 {public:   
14    ClxDerived() {}  
15    ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl}  
16   
17    void DoSomething() { cout << "Do something in class ClxDerived!" << endl; }  
18 };   
19   
20 int main()  
21 {  
22    ClxDerived *p =  new ClxDerived;   
23    p->DoSomething();   
24    delete p;   
25   
26    return 0;   
27 }  

運行結果:

Do something in class ClxDerived!   

Output from the destructor of class ClxDerived!

Output from the destructor of class ClxBase!  

 

這段代碼中基類的析構函數不是虛函數,在main函數中用繼承類的指針去操作繼承類的成員,釋放指針P的過程是:先釋放繼承類的資源,再釋放基類資源. 

 

第二段代碼:

 1 #include<iostream>
 2 using namespace std;  
 3   
 4 class ClxBase  
 5 {public:   
 6    ClxBase() {}  
 7    ~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl}  
 8   
 9    void DoSomething() { cout << "Do something in class ClxBase!" << endl}  
10 };  
11   
12 class ClxDerived : public ClxBase  
13 {public:   
14    ClxDerived() {}  
15    ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl }  
16   
17    void DoSomething() { cout << "Do something in class ClxDerived!" << endl}  
18 };  
19   
20 int main()  
21 {   
22    ClxBase *p =  new ClxDerived;   
23    p->DoSomething();   
24    delete p;   
25   
26    return 0;   
27 }   

輸出結果:

Do something in class ClxBase! 

Output from the destructor of class ClxBase!

 

 這段代碼中基類的析構函數同樣不是虛函數,不同的是在main函數中用基類的指針去操作繼承類的成員,釋放指針P的過程是:只是釋放了基類的資源,而沒有調用繼承類的析構函數.調用dosomething()函數執行的也是基類定義的函數.

 

 一般情況下,這樣的刪除只能夠刪除基類對象,而不能刪除子類對象,形成了刪除一半形象,造成內存泄漏.

 

 在公有繼承中,基類對派生類及其對象的操作,只能影響到那些從基類繼承下來的成員.如果想要用基類對非繼承成員進行操作,則要把基類的這個函數定義為虛函數.

析構函數自然也應該如此:如果它想析構子類中的重新定義或新的成員及對象,當然也應該聲明為虛的. 

 

第三段代碼:

 1 #include<iostream>  
 2 using namespace std;  
 3 class ClxBase  
 4 {public:   
 5    ClxBase() {}   
 6    virtual ~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl}  
 7   
 8    virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl}  
 9 };  
10   
11   
12 class ClxDerived : public ClxBase  
13 {public:   
14    ClxDerived() {}   
15    ~ClxDerived() { cot << "Output from the destructor of class ClxDerived!" << endl}  
16   
17    void DoSomething() { cout << "Do something in class ClxDerived!" << endl}  
18 };  
19   
20 int   main()  
21 {  
22    ClxBase *p = new ClxDerived;  
23    p->DoSomething();   
24    delete p;  
25   
26    return 0;  
27 }  

運行結果:

Do something in class ClxDerived!

Output from the destructor of class ClxDerived!

Output from the destructor of class ClxBase!

 

這段代碼中基類的析構函數被定義為虛函數,在main函數中用基類的指針去操作繼承類的成員,釋放指針P的過程是:只是釋放了繼承類的資源,再調用基類的析構函數.調用dosomething()函數執行的也是繼承類定義的函數.  

 

如果不需要基類對派生類及對象進行操作,則不能定義虛函數,因為這樣會增加內存開銷.當類里面有定義虛函數的時候,編譯器會給類添加一個虛函數表,里面來存放虛函數指針,這樣就會增加類的存儲空間.所以,只有當一個類被用來作為基類的時候,才把析構函數寫成虛函數.

 

 

注:本內容屬於借鑒,目的在於相互學習,與大家共同進步


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM