c++複習基礎要點03 虛析構函數、虛函數表

1.虛析構函數的作用:

  當基類對象指針通過new動態創建一個子類的對象時,通過該指針釋放子類對象時,如果基類的析構函數不是虛函數,則釋放該對象時只會調用基類的析構函數而不會調用子類析構函數。這樣子類釋放對象時就無法釋放已分配的資源。

如果基類的析構函數爲虛函數,則在基類對象指針去釋放子類對象時,就會先調用子類的析構函數,在調用基類的析構函數:

 

#include<iostream>

using namespace std;

 

 

class A

{

public:

       virtual  void fun()

       {

              cout<<"thisis virtual for A"<<endl;

       }

       virtual~A()

       {

              cout<<"thisis virtual ~ for A"<<endl;

       }

};

 

class B:public A

{

public:

       voidfun()

       {

              cout<<"thisis virtual for B"<<endl;

       }

 

       virtual~B()

       {

              cout<<"thisis virtual ~ for B"<<endl;

       }

};

 

 

int main()

{

       A*a;

       a=newB;

       a->fun();

       deletea;

       return0;

}

 

結果:

this is virtual for B

this is virtual ~ for B

this is virtual ~ for A

 

當virtual ~A() 去掉virtual時,結果爲:

this is virtual for B

this is virtual ~ for A

 

也就是說,類B的析構函數根本就沒被調用,一般情況下類的析構函數裏面都是釋放內存資源,而析構函數不被調用的話就會造成內存泄漏。

 

所以基類的析構函數應該被定義爲虛函數,這樣做是爲了當用一個基類的指針刪除一個派生類的對象時,派生類的析構函數會被調用。

 

 當然,並不是要把所有類的析構函數都寫成虛函數。因爲當類裏面有虛函數的時候,編譯器會給類添加一個虛函數表,裏面來存放虛函數指針,這樣就會增加類的存儲空間。所以,只有當一個類被用來作爲基類的時候,才把析構函數寫成虛函數。

 

2.虛函數表

 

多態性可分爲兩類:靜態多態和動態多態。函數重載和運算符重載實現的多態屬於靜態多態,動態多態性是通過虛函數實現的。

每個含有虛函數的類有一張虛函數表(vtbl),表中每一項是一個虛函數的地址, 也就是說,虛函數表的每一項是一個虛函數的指針。

沒有虛函數的C++類,是不會有虛函數表的

 

例子:

class Class1

{

 public:

    m_data1;

    m_data2;

    virtual  vfunc1();

    virtual  vfunc2();

    virtual  vfunc3();

};

 

圖示:


 

class Class2 : public Class1

{

 public:

    m_data3;

    virtual vfunc2();

 

};

 

圖示:


虛函數表的指針4個字節大小(vptr),存在於對象實例中最前面的位置(這是爲了保證取到虛函數表的有最高的性能——如果有多層繼承或是多重繼承的情況下)。這意味着我們通過對象實例的地址得到這張虛函數表,然後就可以遍歷其中函數指針,並調用相應的函數。

 

 

發佈了96 篇原創文章 · 獲贊 4 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章