所謂虛函式表就是存放著當前類中所有虛函式位址的表。在例項化乙個具有虛函式的類時,這個表也被分配到這個例項物件的記憶體中,通過虛函式表可以指明所要呼叫的函式的位置。在c++編譯器中虛函式表的位址存放在物件的最前面,這是為了即使多繼承下也能快速獲取到虛函式表。
我們可以通過下示的**簡單看下虛函式表結構:
這裡有個問題:為什麼b1中沒有成員函式 c 的資訊?在了解了虛函式表在單個例項化物件中的結構後,我們看一下在單繼承下的虛函式表。因為成員函式在編譯期間確定,物件在呼叫時直接call函式名去呼叫,所以不需要在物件中儲存成員函式資訊。
這裡所提到的覆蓋也就是常說的重寫是指:派生類在繼承父類虛函式之後有沒有過載基類的函式,如果有就會發生覆蓋,反之。
同樣,我們執行下述**進行實驗:
class base
virtual void b()
};class derive :public base
virtual void d()
};int main()
但結果並不是我們所想的那樣:
這裡面沒有我們派生類的虛函式指標。這是因為編譯器故意隱藏了這兩個函式。
不過我們可以在通過**列印出來。
思路:取出b1、d1物件的頭4bytes,就是虛表的指標,而虛函式表本質是乙個存虛函式指標的指標陣列,這個陣列最後麵放了乙個nullptr。**實現:1.先取b1的位址,強轉成乙個int*的指標;
2.再解引用取值,就取到了b1物件頭4bytes的值,這個值就是指向虛表的指標;
3.再強轉成pvtable*,因為虛表就是乙個存虛函式指標型別的陣列;
4.虛表指標傳遞給printvtable進行列印虛表;
5.需要說明的是這個列印虛表的**經常會崩潰,因為編譯器有時對虛表的處理不乾淨,虛表最後面沒有放nullptr,導致越界,這是編譯器的問題。我們只需要點目錄欄的-生成-清理解決方案,再編譯就好了。
typedef void(*pvtable)(void);
void printvtable(pvtable vtable)
cout << endl;
}int main()
執行結果:
如果發生如下圖所示錯誤,中斷-->生成-->清理解決方案-->重新生成解決方案 就ok了:
結論:一般來講基類宣告虛函式就是為了讓派生類重寫,所以我們了解下重寫之後的虛函式表。虛函式按照其宣告順序放於表中。
父類的虛函式在子類的虛函式前面。
只需在派生類重寫下基類的方法:
class derive :public base
virtual void c()
virtual void d()
};
執行完結果,明顯看出此時派生類物件中派生類虛函式位址已將基類虛函式位址覆蓋掉了,而沒有重寫的虛函式b依然與基類位址相同:
結論:看完單繼承自然而然開始討論多繼承下的虛函式表,同樣分為兩種情況討論:如果派生類對基類的虛函式進行重寫,則將被重寫的虛函式位址覆蓋為派生類的函式位址。其他未被覆蓋的保持不變。
在之前**中新增base2類,並讓derive繼承base2,建立base2物件b2。
class base
virtual void b()
};class base2
virtual void b()
};class derive :public base, public base2
virtual void d()
};
由於多繼承下派生類會產生多個虛表,就本例而言會有兩個虛表如下圖所示:
執行結果:
如果我們將繼承順序顛倒:
class derive :public base2, public base
virtual void d()
};
執行結果:
結論:最後在看看多繼承下覆蓋後的虛函式表,結合之前示例實現此過程就很容易,不再貼**直接執行出結果:每個基類都要一張虛函式表,且在派生類中按序排放(這裡的按序指宣告順序);
派生類自己的虛函式位址存放在第一張虛函式表中。(這樣做就是為了解決不同的父類型別的指標指向同乙個子類例項,而能夠呼叫到實際的函式。)
結論:基類虛函式a()位置被替換成了派生類的函式指標。這樣,我們就可以任一靜態型別的基類來指向派生類,並呼叫派生類的a()了。
虛函式表指標,虛函式表
對c 了解的人都應該知道虛函式 virtual function 是通過一張虛函式表 virtual table 來實現的。簡稱為v table。在這個表中,主是要乙個類的虛函式的位址表,這張表解決了繼承 覆蓋的問題,保證其容真實反應實際的函式。這樣,在有虛函式的類的例項中這個表被分配在了 這個例項...
虛函式表和虛函式表的指標
有虛函式的類都有乙個虛函式表,它是實現多型的關鍵。虛函式表可以繼承,如果子類沒有重寫虛函式,那麼子類虛函式表中仍然會有該函式的位址,只不過這個位址指向的是基類的函式實現。如果子類重寫了相應的虛函式,那麼虛函式表中的位址就會改變,指向自身的函式實現。如果派生類中有自己的虛函式,那麼虛函式表中會新增該項...
虛函式之虛函式表
多型性可分為兩類 靜態多型和動態多型。函式過載和運算子過載實現的多型屬於靜態多型,動態多型性是通過虛函式實現的。每個含有虛函式的類有一張虛函式表 vtbl 表中每一項是乙個虛函式的位址,也就是說,虛函式表的每一項是乙個虛函式的指標。沒有虛函式的c 類,是不會有虛函式表的。兩張圖 簡單例子 inclu...