C 虛函式及虛函式表解析 二

2021-07-02 01:52:49 字數 2488 閱讀 4344

c++中的成員和函式,有靜態和非靜態。

1、非靜態資料成員:放在每乙個物件體內,作為物件專有的資料成員。

2、靜態資料成員:被提取出來放在程式的靜態資料區內,為該類所有物件共享,因此只存在乙份。(引申下,乙個類模板中的靜態資料成員例項化成模板類之後有幾份?思考下。)

3、靜態和非靜態成員函式:最終都被提取出來放在程式的**中並為該類所有物件共享。因每乙個成員函式也只能存在乙份**屍體。在c++中的類的成員函式都是儲存在靜態儲存區中,那靜態函式也是儲存在靜態儲存區中,他們都是在類中儲存同乙個備份。

構成物件本身的只有資料,非靜態成員函式與物件的關係就是繫結,繫結的中介是this指標。成員函式為該類所有物件共享。

4、單繼承的物件的記憶體布局:第乙個為虛函式表指標vtbl,其後為成員且先基類後子類。虛函式表裡包含了所有虛函式的位址,以null結束。虛函式如果子類有重寫,就由子類的重新的代替。(注意,虛函式表是類所有,而虛函式表指標才是每個物件所有的,所以有虛函式的物件的位址會增加4,是指標的長度)

(1)當子類對父類的虛函式有重寫時,子類的函式替換父類的函式在對應的虛函式位置,

(2)當子類有新的虛函式時,這些虛函式被加在第乙個虛函式表的後面。

總結:與單繼承相同的是所有的虛函式都包含在虛函式表中,所不同的是多重繼承有多個虛函式表,當子類對父類的虛函式有重寫時,子類的函式覆蓋父類的函式在對應的虛函式位置,當子類有新的虛函式時,這些虛函式被加在第乙個虛函式表的後面。

6、虛繼承:使用公共的基類在子類中只有乙份,我們看到虛繼承在多重繼承的基礎上多了vtable來儲存到公共基類的偏移。

總結:虛繼承,使公共的基類在子類中只有乙份,我們看到虛基類在多重繼承的基礎上多了vtable來儲存到公共基類的偏移。 

編譯的角度

c++編譯器在編譯的時候,要確定每個物件呼叫的函式的位址,這稱為早期繫結(early binding).

前面輸出的結果是因為編譯器在編譯的時候,就已經確定了物件呼叫的函式的位址,要解決這個問題就要使用遲繫結(late binding)技術。當編譯器使用遲繫結時,就會在執行時再去確定物件的型別以及正確的呼叫函式。而要讓編譯器採用遲繫結,就要在基類中宣告函式時使用virtual關鍵字,這樣的函式我們稱為虛函式。一旦某個函式在基類中宣告為virtual,那麼在所有的派生類中該函式都是virtual,而不需要再顯式地宣告為virtual。

編譯器在編譯的時候,編譯器會為每個包含虛函式的類建立乙個虛表(即vtable),該表是乙個一維陣列,在這個陣列中存放每個虛函式的位址。

那麼如何定位虛表呢?編譯器另外還為每個類的物件提供了乙個虛表指標(即vptr),這個指標指向了物件所屬類的虛表。在程式執行時,根據物件的型別去初始化vptr,從而讓vptr正確的指向所屬類的虛表,從而在呼叫虛函式時,就能夠找到正確的函式。

正是由於每個物件呼叫的虛函式都是通過虛表指標來索引的,也就決定了虛表指標的正確初始化是非常重要的。換句話說,在虛表指標沒有正確初始化之前,我們不能夠去呼叫虛函式。那麼虛表指標在什麼時候,或者說在什麼地方初始化呢?

案是在建構函式中進行虛表的建立和虛表指標的初始化。還記得建構函式的呼叫順序嗎,在構造子類物件時,要先呼叫父類的建構函式,此時編譯器只「看到了」父類,並不知道後面是否後還有繼承者,它初始化父類物件的虛表指標,該虛表指標指向父類的虛表。當執行子類的建構函式時,子類物件的虛表指標被初始化,指向自身的虛表。

要注意:對於虛函式呼叫來說,每乙個物件內部都有乙個虛表指標,該虛表指標被初始化為本類的虛表。所以在程式中,不管你的物件型別如何轉換,但該物件內部的虛表指標是固定的,所以呢,才能實現動態的物件函式呼叫,這就是c++多型性實現的原理。

總結(基類有虛函式):

1、 每乙個類都有虛表。

2、 虛表可以繼承,如果子類沒有重寫虛函式,那麼子類虛表中仍然會有該函式的位址,只不過這個位址指向的是基類的虛函式實現。如果基類3個虛函式,那麼基類的虛表中就有三項(虛函式位址),派生類也會有虛表,至少有三項,如果重寫了相應的虛函式,那麼虛表中的位址就會改變,指向自身的虛函式實現。如果派生類有自己的虛函式,那麼虛表中就會新增該項。

3、 派生類的虛表中虛函式位址的排列順序和基類的虛表中虛函式位址排列順序相同。

在呼叫基類的建構函式時,編譯器只「看到了」父類,並不知道後面是否後還有繼承者,它只是初始化父類物件的虛表指標,讓該虛表指標指向父類的虛表,所以你看到結果當然不正確。只有在子類的構造函式呼叫完畢後,整個虛表才構建完畢,此時才能真正應用c++的多型性。換句話說,我們不要在建構函式中去呼叫虛函式,當然如果你只是想呼叫本類的函式,也無所謂。)

C 虛函式表解析 二

接c 虛函式表解析 一 如果乙個類沒有繼承關係,且該類中定義了虛函式,那麼這個類的例項只有一張虛函式表,如 一 所說明 對於乙個單繼承的類,即派生類的基類只有乙個,如果它有虛函式,也只有一張虛函式表。但是,對於多重繼承的類,它可能會有多張虛函式表。下面一一具體說明 還是以 為例,看下面 class ...

C 虛函式表解析

前言 c 中的虛函式的作用主要是實現了多型的機制。關於多型,簡而言之就是用父型別別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。這種技術可以讓父類的指標有 多種形態 這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變的 來實現可變的演算法。比如 模板技術,rtti技術,虛函式...

C 虛函式表解析

c 中的虛函式的作用主要是實現了多型的機制。關於多型,簡而言之就是用父型別別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。這種技術可以讓父類的指標有 多種形態 這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變的 來實現可變的演算法。比如 模板技術,rtti技術,虛函式技術,...