疑問:什麼狀況下必須用虛析構?ios
先看個例子:微信
#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,也就是說,當使用子類指針指向子類對象的時候,析構的時候,依然會依次調用子類和基類的析構函數。.net
若是 main 函數中的代碼,替換爲以下呢?指針
int main() { A * pa = new B(); delete pa; return 0; }
調試發現,這份代碼,只會輸出 ~A, 哦,到此終於明白了,當用基類指針指向派生類對象時,若是基類析構函數不設置爲 virtual 的話,則在 delete 基類指針的時候,沒法成功調用子類的析構函數。這纔是虛析構函數發揮做用的真正場合。調試
上述代碼解決方法: 把基類 A 的析構函數設置爲 virtual,則能夠成功實現delete pa 的時候依次調用B類和A類的析構函數了。對象
那麼,進一步講,咱們是否應該把全部類的析構函數都設置爲虛析構呢?blog
不該該,這樣設置不合理,只有在該類可能做爲基類的狀況下,而且可能使用到多態特性的時候,纔有必要把基類的析構函數設置爲虛析構,不然,沒有必要,由於設置爲虛析構會產生額外的開銷,即下一個問題:get
一個類若是把析構函數設置爲 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 字節
結束語
免費學習更多精品課程,登陸樂搏學院官網http://h.learnbo.cn/
或關注咱們的官方微博微信,還有更多驚喜哦~
本文出自 「Jhuster的專欄」 博客,請務必保留此出處http://ticktick.blog.51cto.com/823160/961418