1. 程式人生 > >虛擬函式、純虛擬函式

虛擬函式、純虛擬函式

      對於純虛擬函式:當派生類繼承了基類的時候,如果派生類中沒有寫基類中的虛擬函式,則編譯的時候不會出現什麼錯誤,但是當寫了基類中的虛擬函式的時候,卻沒有使用,則在編譯過程中會出現一些連結方面的錯誤。

     對於虛擬函式:當派生類繼承了基類的時候,只要用派生類的物件來初始化基類就可以呼叫派生類裡面的函式。

     純虛擬函式和虛擬函式的區別:區別體現在定義的時候,如果是純虛擬函式,則在定義的時候對純虛擬函式不會有什麼實現,但是虛擬函式會在內部有所實現。

   例如:虛擬函式:virtual int  add(void) {  a+b;}

              純虛擬函式:virtual int add();

    下面是轉載文章,原文作者申明如下:

疑問:什麼情況下必須用虛析構?

    先看個例子:

  1. #include <iostream> 
  2. class A  
  3. {  
  4. public:  
  5.     A(){};  
  6.     ~A()  
  7.     {  
  8.         std::cout << "~A" << std::endl;  
  9.     };  
  10. private:  
  11.     int a;  
  12. };  
  13. class B : public A  
  14. {  
  15. public:  
  16.     B(){};  
  17.     ~B()  
  18.     {  
  19.         std::cout << "~B"
     << std::endl;  
  20.     }  
  21. private:  
  22.     int b;  
  23. };  
  24. int main()   
  25. {       
  26.     B b;       
  27.     return 0;  
  28. }  

    除錯發現,視窗依次輸出: ~B 和 ~A,也就是說,B類物件b析構的時候,先呼叫了B類的解構函式,然後呼叫了基類的解構函式。

    如果 main 函式中的程式碼,替換為如下呢?

  1. int main() 
  2.     A *pb = new B(); 
  3.     delete pb; 
  4.     return 0; 

    你會發現,還是依次輸出了 ~B 和 ~A,也就是說,當使用子類指標指向子類物件的時候,析構的時候,依然會依次呼叫子類和基類的解構函式。

    如果 main 函式中的程式碼,替換為如下呢?

  1. int main() 
  2.     A * pa = new B(); 
  3.     delete pa; 
  4.     return 0; 

    除錯發現,這份程式碼,只會輸出 ~A, 哦,到此終於明白了,當用基類指標指向派生類物件時,如果基類解構函式不設定為 virtual 的話,則在 delete 基類指標的時候,無法成功呼叫子類的解構函式。這才是虛解構函式發揮作用的真正場合。

    上述程式碼解決方法: 把基類 A 的解構函式設定為 virtual,則可以成功實現delete pa 的時候依次呼叫B類和A類的析構函數了。

    那麼,進一步講,我們是否應該把所有類的解構函式都設定為虛析構呢?

    不應該,這樣設定不合理,只有在該類可能作為基類的情況下,並且可能使用到多型特性的時候,才有必要把基類的解構函式設定為虛析構,否則,沒有必要,因為設定為虛析構會產生額外的開銷,即下一個問題:

    一個類如果把解構函式設定為 virtual 是否也會產生虛擬函式表?

    我們把上述程式碼稍微改一下: 

  1. class A  
  2. {  
  3. public:  
  4.    A(){};  
  5.    ~A()  
  6.    {  
  7.        std::cout << "~A" << std::endl;  
  8.    };  
  9.    void test() 
  10.    { 
  11.       std::cout << "~test" << std::endl; 
  12.    } 
  13. private:  
  14.     int a;  
  15. };  
  16. int main()  
  17. {  
  18.     std::cout << sizeof(A) << std::endl;  
  19. }  

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

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

    可以得出如下結論:

   (1) 如果類沒有virtual成員函式時,類的大小由資料成員大小決定

   (2) 虛解構函式也會使類產生虛擬函式表,並且虛擬函式表的大小是 4 位元組