虛函式和虛函式表

2022-05-17 11:31:31 字數 2709 閱讀 4792

多型是由虛函式實現的,而虛函式主要是通過虛函式表(v-table)來實現的。

這個類的每乙個物件都會包含乙個虛指標(虛指標存在於物件例項位址的最前面,保證虛函式表有最高的效能),這個虛指標指向虛函式表。

注:物件不包含虛函式表,只有虛指標,類才包含虛函式表,派生類會生成乙個相容基類的虛函式表。

下圖是原始基類的物件,可以看到虛指標在位址的最前面,指向基類的虛函式表(假設基類定義了3個虛函式)

假設現在派生類繼承基類,並且重新定義了3個虛函式,派生類會自己產生乙個相容基類虛函式表的屬於自己的虛函式表

derive class 繼承了 base class 中的三個虛函式,準確的說,是該函式實體的位址被拷貝到 derive類的虛函式表,派生類新增的虛函式置於虛函式表的後面,並按宣告順序存放

現在派生類重寫基類的x函式,可以看到這個派生類構建自己的虛函式表的時候,修改了base::x()這一項,指向了自己的虛函式。

這個派生類多重繼承了兩個基類base1,base2,因此它有兩個虛函式表。

它的物件會有多個虛指標(據說和編譯器相關),指向不同的虛函式表。

多重繼承時指標的調整:

derive b;

base1* ptr1 = &b; //

指向 b 的初始位址

base2* ptr2 = &b; //

指向 b 的第二個子物件

因為 base1 是第乙個基類,所以 ptr1 指向的是 derive 物件的起始位址,不需要調整指標(偏移)。

因為 base2 是第二個基類,所以必須對指標進行調整,即加上乙個 offset,讓 ptr2 指向 base2 子物件。

當然,上述過程是由編譯器完成的。

base1* b1 = (base1*)ptr2;

b1->y(); //

輸出 base2::y()

base2* b2 = (base2*)ptr1;

b2->y(); //

輸出 base1::y()

其實,通過某個型別的指標訪問某個成員時,編譯器只是根據型別的定義查詢這個成員所在偏移量,用這個偏移量獲取成員。由於 ptr2 本來就指向 base2 子物件的起始位址,所以b1->y()呼叫到的是base2::y(),而 ptr1 本來就指向 base1 子物件的起始位址(即 derive物件的起始位址),所以b2->y()呼叫到的是base1::y()

虛繼承的引入把物件的模型變得十分複雜,除了每個基類(myclassa和myclassb)和公共基類(myclass)的虛函式表指標需要記錄外,每個虛擬繼承了myclass的父類還需要記錄乙個虛基類表vbtable的指標vbptr。myclassc的物件模型如圖4所示。

虛基類表每項記錄了被繼承的虛基類子物件相對於虛基類表指標的偏移量。比如myclassa的虛基類表第二項記錄值為24,正是myclass::vfptr相對於myclassa::vbptr的偏移量,同理myclassb的虛基類表第二項記錄值12也正是myclass::vfptr相對於myclassa::vbptr的偏移量。

編譯時若基類中有虛函式,編譯器為該的類建立乙個一維陣列的虛表,存放是每個虛函式的位址。基類和派生類都包含虛函式時,這兩個類都建立乙個虛表。建構函式中進行虛表的建立和虛表指標的初始化。在構造子類物件時,要先呼叫父類的建構函式,初始化父類物件的虛表指標,該虛表指標指向父類的虛表。執行子類的建構函式時,子類物件的虛表指標被初始化,指向自身的虛表。每乙個類都有虛表。虛表可以繼承,如果子類沒有重寫虛函式,那麼子類虛表中仍然會有該函式的位址,只不過這個位址指向的是基類的虛函式實現。派生類的虛表中虛函式位址的排列順序和基類的虛表中虛函式位址排列順序相同。當用乙個指標/引用呼叫乙個函式的時候,被呼叫的函式是取決於這個指標/引用的型別。即如果這個指標/引用是基類物件的指標/引用就呼叫基類的方法;如果指標/引用是派生類物件的指標/引用就呼叫派生類的方法,當然如果派生類中沒有此方法,就會向上到基類裡面去尋找相應的方法。這些呼叫在編譯階段就確定了。當涉及到多型性的時候,採用了虛函式和動態繫結,此時的呼叫就不會在編譯時候確定而是在執行時確定。不在單獨考慮指標/引用的型別而是看指標/引用的物件的型別來判斷函式的呼叫,根據物件中虛指標指向的虛表中的函式的位址來確定呼叫哪個函式。

參考:

虛函式和虛函式表

虛函式和虛函式表 1 虛函式 c 中的虛函式的作用主要是實現了多型的機制。關於多型,簡而言之就是用父型別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。這種技術可以讓父類的指標有 多種形態 這是一種泛型技術。如果呼叫非虛函式,則無論實際物件是什麼型別,都執行基類型別所定義的函式。非...

虛函式表指標,虛函式表

對c 了解的人都應該知道虛函式 virtual function 是通過一張虛函式表 virtual table 來實現的。簡稱為v table。在這個表中,主是要乙個類的虛函式的位址表,這張表解決了繼承 覆蓋的問題,保證其容真實反應實際的函式。這樣,在有虛函式的類的例項中這個表被分配在了 這個例項...

虛函式指標和虛函式表

虛函式指標和虛函式表 虛函式表的定義 多型是由虛函式實現的,而虛函式主要是通過虛函式表 v table 來實現的。如果乙個類中包含虛函式 virtual修飾的函式 那麼這個類就會包含一張虛函式表 vftbl 虛函式表儲存的每一項是乙個虛函式的位址。在乙個物件的記憶體布局中,指向這張虛函式表的指標 v...