[C++]虛析構函數的做用

 
C++中的虛析構函數到底何時有用的,什麼做用呢。
 
一.虛析構函數的做用
總的來講虛析構函數是爲了不內存泄露,並且是當子類中會有指針成員變量時纔會使用獲得的。也就說 虛析構函數使得在刪除指向子類對象的基類指針時能夠調用子類的析構函數達到釋放子類中堆內存的目的,而防止內存泄露的
咱們知道,用C++開發的時候,用來作基類的類的析構函數通常都是虛函數。但是,爲何要這樣作呢?下面用一個小例子來講明:
 1 #include<iostream>
 2 using namespace std;
 3 
 4 class ClxBase
 5 {
 6     public:
 7         ClxBase() {};
 8         virtual ~ClxBase() { cout<<"delete ClxBase"<<endl; };
 9 
10         virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl;  };
11 
12 };
13 
14 class ClxDerived : public ClxBase
15 {
16     public:
17         ClxDerived() {};
18         ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl;  };
19 
20         void DoSomething() { cout << "Do something in class ClxDerived!" << endl;  };
21 
22 };
23 
24 int main(int argc, char const* argv[])
25 {
26      ClxBase *pTest = new ClxDerived;
27      pTest->DoSomething();
28      delete pTest;
29     return 0;
30 }

可是,若是把類ClxBase析構函數前的virtual去掉,那輸出結果就是下面的樣子了: ios

沒有調動子類的析構函數
也就是說,類ClxDerived的析構函數根本沒有被調用!通常狀況下類的析構函數裏面都是釋放內存資源,而析構函數不被調用的話就會形成內存泄漏。我想全部的C++程序員都知道這樣的危險性。固然,若是在析構函數中作了其餘工做的話,那你的全部努力也都是白費力氣。
因此,文章開頭的那個問題的答案就是--這樣作是爲了當用一個基類的指針刪除一個派生類的對象時,派生類的析構函數會被調用。
固然,並非要把全部類的析構函數都寫成虛函數。由於當類裏面有虛函數的時候,編譯器會給類添加一個虛函數表,裏面來存放虛函數指針,這樣就會增長類的存儲空間。因此,只有當一個類被用來做爲基類的時候,才把析構函數寫成虛函數。程序員

總結一下虛析構函數的做用:
(1)若是父類的析構函數不加virtual關鍵字
當父類的析構函數不聲明成虛析構函數的時候,當子類繼承父類,父類的指針指向子類時,delete掉父類的指針,只調動父類的析構函數,而不調動子類的析構函數。
(2)若是父類的析構函數加virtual關鍵字
當父類的析構函數聲明成虛析構函數的時候,當子類繼承父類,父類的指針指向子類時,delete掉父類的指針,先調動子類的析構函數,再調動父類的析構函數。 函數

二.虛析構函數的原理分析spa

 

 1 #include<iostream>
 2 using namespace std;
 3 
 4 class Base
 5 {
 6 public:
 7     Base(){cout<<"create Base"<<endl;}
 8     virtual ~Base(){cout<<"delete Base"<<endl;}
 9 };
10 
11 class Der : public Base
12 {
13 public:
14     Der(){cout<<"create Der"<<endl;}
15     ~Der(){cout<<"Delete Der"<<endl;}
16 };
17 int main(int argc, char const* argv[])
18 {
19     Base *b = new Der;
20     delete b;
21 
22     return 0;
23 }

 

從建立講起,用gdb調試你會發現, 
(1)先調用父類的構造函數,再調用子類的構造函數.net

這裏有一個問題:父類的構造函數/析構函數與子類的構造函數/析構函數會造成多態,可是當父類的構造函數/析構函數即便被聲明virtual,子類的構造/析構方法仍沒法覆蓋父類的構造方法和析構方法。這是因爲父類的構造函數和析構函數是子類沒法繼承的,也就是說每個類都有本身獨有的構造函數和析構函數。指針

(2)而因爲父類的析構函數爲虛函數,因此子類會在全部屬性的前面造成虛表,而虛表內部存儲的就是父類的虛函數調試

 

(3)當delete父類的指針時,因爲子類的析構函數與父類的析構函數構成多態,因此得先調動子類的析構函數;之因此再調動父類的析構函數,是由於delete的機制所引發的,delete 父類指針所指的空間,要調用父類的析構函數。 
因此結果就是這樣 
這裏寫圖片描述code

相關文章
相關標籤/搜索