搞清虛析構函數的使用場合

立刻要找工做了,開始複習一下c/c++基礎知識了。今天看到虛析構這一塊,產生幾個疑問,發現本身之前的理解還不夠透徹,寫了幾個程序測試驗證了一下,終於算搞清楚了。ios


疑問:什麼狀況下必須用虛析構?c++


先看個例子:ide


#include <iostream>  
class A  
{  
public:  
    A(){};  
    ~A()  
    {  
        std::cout << "~A" << std::endl;  
    };  
private:  
    int a;  
};  
  
class B : public A  
{  
public:  
    B(){};  
    ~B()  
    {  
        std::cout << "~B" << std::endl;  
    }  
private:  
    int b;  
};  
  
int main()   
{       
    B b;       
    return 0;  
}

    

調試發現,窗口依次輸出: ~B 和 ~A,也就是說,B類對象b析構的時候,先調用了B類的析構函數,而後調用了基類的析構函數。函數


若是 main 函數中的代碼,替換爲以下呢?測試


int main() 
{ 
    B *pb = new B(); 
    delete pb; 
    return 0; 
}

    

你會發現,仍是依次輸出了 ~B 和 ~A,也就是說,當使用子類指針指向子類對象的時候,析構的時候,依然會依次調用子類和基類的析構函數。spa


若是 main 函數中的代碼,替換爲以下呢?指針


int main() 
{ 
    A * pa = new B(); 
    delete pa; 
    return 0; 
}


調試發現,這份代碼,只會輸出 ~A, 哦,到此終於明白了,當用基類指針指向派生類對象時,若是基類析構函數不設置爲 virtual 的話,則在 delete 基類指針的時候,沒法成功調用子類的析構函數。這纔是虛析構函數發揮做用的真正場合。調試

    

上述代碼解決方法: 把基類 A 的析構函數設置爲 virtual,則能夠成功實現delete pa 的時候依次調用B類和A類的析構函數了。對象

    

那麼,進一步講,咱們是否應該把全部類的析構函數都設置爲虛析構呢?it

    

不該該,這樣設置不合理,只有在該類可能做爲基類的狀況下,而且可能使用到多態特性的時候,纔有必要把基類的析構函數設置爲虛析構,不然,沒有必要,由於設置爲虛析構會產生額外的開銷,即下一個問題:

    

一個類若是把析構函數設置爲 virtual 是否也會產生虛函數表?

    

咱們把上述代碼稍微改一下: 


class A  
{  
public:  
   A(){};  
   ~A()  
   {  
       std::cout << "~A" << std::endl;  
   };  
   void test() 
   { 
      std::cout << "~test" << std::endl; 
   } 
private:  
    int a;  
};  
  
int main()  
{  
    std::cout << sizeof(A) << std::endl;  
}


若是 ~A 前面不加 virtual 則輸出的結果是: 4

若是 ~A 前面加 virtual 則輸出的結果是: 8 


能夠得出以下結論:


(1) 若是類沒有virtual成員函數時,類的大小由數據成員大小決定

(2) 虛析構函數也會使類產生虛函數表,而且虛函數表的大小是 4 字節


好啦,大體就寫這麼多了,算是複習過程當中留下的筆記,但願對C++新手有所幫助,有疑問歡迎留言探討。

相關文章
相關標籤/搜索