C 虛函式的底層實現原理

2021-12-30 04:48:47 字數 2707 閱讀 4091

在c++中,多型是利用虛函式來實現的。比如說,有如下**:

#include

using namespace std;

class animal

};class dog :public animal

};void makeanimalcry(animal& animal)

int main()

輸出如下圖:

這裡定義了乙個animal類,dog類繼承該類,並覆蓋了它的cry方法。有乙個makeanimalcry方法,傳入了animal的引用,傳入了dog物件,但是輸出確是animal的輸出。理想的情況下,使用者希望傳入的是dog物件,就該呼叫dog的cry方法。要實現這種多型行為,需要將animal::cry()宣告為虛函式。可以通過animal指標或者animal引用來訪問animal物件,這種指標或者引用可以指向animal、dog、cat物件,而不需要關心它們具體指向的是哪種物件。修改**如下:

#include

using namespace std;

class animal

};class dog :public animal

};class cat:public animal

};void makeanimalcry(animal& animal)

int main()

修改後的輸出如下:

這就是多型的效果,將派生類物件視為基類物件,並執行派生類的cry實現。如果基類指標指向的是派生類物件,通過該指標呼叫運算子delete時,即對於使用new在自由儲存區中例項化的派生類物件,如果將其賦給基類指標,並通過該指標呼叫delete,將不會呼叫派生類的析構函式。這可能會導致資源未釋放、記憶體洩露等問題,為了避免這種問題,可以將基類的析構函式宣告為虛函式

在上面的程式中,演示了多型的效果,即在函式makeanimalcry中,雖然通過animal引用呼叫cry方法,但是實際呼叫的確是dog::cry或者cat::cry方法。在編譯階段,編譯器並不知道將要傳遞給該函式的是哪種物件,無法確保在不同的情況下執行不同的cry方法。應該呼叫哪個cry方法顯然是在執行階段決定的。這是使用多型的不可見邏輯實現的,而這種邏輯是編譯器在編譯階段提供的。下面詳細地說明一下虛函式的底層實現原理。

比如說有下面的基類base,它宣告了n個虛函式:

class base

virtual void func2()

//func3、func4等虛函式的實現

virtual void funcn()

};下面的derived類繼承了base類,並且覆蓋了除func2之外的其他所有虛函式,

class derived:public base

//除去func2的其他所有虛函式的實現**

virtual void funcn()

};編譯器見到這種繼承層次結構後,知道base定義了虛函式,並且在derived類中覆蓋了這些函式。在這種情況下,編譯器將為實現了虛函式的基類和覆蓋了虛函式的派生類分別建立乙個虛函式表(virtual function table,vft)。也就是說base和derived類都將有自己的虛函式表。例項化這些類的物件時,將建立乙個隱藏的指標vft*,它指向相應的vft。可將vft視為乙個包含函式指標的靜態陣列,其中每個指標都指向相應的虛函式。base類和derived類的虛函式表如下圖所示:

每個虛函式表都由函式指標組成,其中每個指標都指向相應虛函式的實現。在類derived的虛函式表中,除乙個函式指標外,其他所有的函式指標都指向本地的虛函式實現。derived沒有覆蓋base::func2,因此相應的虛函式指標指向base類的func2的實現。這就意味著,當執行下面的**時,編譯器將查詢derived類的vft,確保呼叫base::func2的實現:

derived objderived;

objderived.func2();

呼叫被覆蓋的方法時,也是這樣:

void dosomething(base& objbase)

int main()

在這種情況下,雖然將objderived傳遞給了objbase,進而被解讀成乙個base例項,但該例項的vft指標仍然指向derived類的虛函式表,因此通過該vft執行的是derived::func1.虛函式表就是通過上面的方式來實現c++的多型。

要驗證虛函式表的存在其實也很簡單,可以通過比較同乙個類,乙個包含虛函式,乙個不包含,對比其大小就知道了。

#include

using namespace std;

class test };

class base };

int main()

{ cout《執行輸出如下:

雖然兩個類幾乎相同,因為base中的dosomething方法是乙個虛函式,編譯器為base類生成了乙個虛函式表,並為其虛函式表指標預留空間,所以base類占用的記憶體空間比test類多了8個位元組。 

C 多型,虛函式作用及底層實現原理

簡述c 虛函式作用及底層實現原理 c 是物件導向程式設計,其包括3項特點 1 資料抽象 介面和實現分離 2 繼承 父類和子類 3 多型 動態繫結 本文討論多型。當父類希望子類重新定義某些函式時,用virtual關鍵字宣告為虛函式。當我們使用乙個基類型別的引用或者指標,呼叫乙個虛函式時就引發動態繫結 ...

C 虛函式實現原理

c 中的虛函式的作用主要是實現了多型的機制。基類定義虛函式,子類可以重寫該函式。每個類物件新增乙個成員,該成員中儲存了乙個指向函式位址陣列的指標,稱為虛表指標 vptr 該陣列稱為虛函式表 virtual function table,vtbl 即,每個類使用乙個虛函式表,每個類物件用乙個虛表指標。...

虛函式的底層實現機制

1 多型的實現機制 c 在基類中宣告乙個帶關鍵之virtual的函式,這個函式叫虛函式 它可以在該基類的派生類中被重新定義並被賦予另外一種處理功能。通過指向指向派生類的基類指標或引用呼叫虛函式,編譯器可以根據指向物件的型別在執行時決定呼叫的目標函式。這就實現了多型。2 例項 cpp view pla...