我們知道當我們sizeof 乙個類的時候,類的成員函式是不計算在物件的大小的裡的,這是為什麼呢?因為類的成員函式不是屬於某乙個物件的,而是類的所有物件所共享的,就像static變數那樣。如果虛函式和普通成員函式一樣,那麼我們就不能通過指向子類的基類指標來引用子類的方法了,因為我們將不知道呼叫哪個方法,多型就無從談起。那麼多型是怎麼實現的呢?
我們可以做乙個小實驗
classa};class b:public
a;b obj_b;
obj_b.a=1;
obj_b.b=2;
a *p=&b;
cout
cout
a)+1)a)的值是相差4個位元組的,最後一行輸出的值為1 ,2。我們可以推斷出obj_b在記憶體中的分布是首先乙個占有4位元組的某型別,然後是int a,最後是int b。
初始的4位元組其實就是虛指標。
而類a的物件在記憶體的分布其實是虛指標然後是int a。
如果類b繼承a,在b構造的時候,會繼承虛指標和int a,但是虛指標指向的虛表就不同了。若在b中實現了虛函式則虛表中的對應函式的入口位址也會改變。從而達到多型的目的。
注意指標p並訪問不到b,因為p是a型別的指標,可見指標的訪問範圍由的型別決定了。所以我們通過&(p->a)+1來訪問b。
那麼多重繼承時是什麼情況呢?
多重繼承的時候,對於每個有虛函式的基類,子類都會繼承相應的虛指標並改寫虛表。
1.對於非虛函式,this指標的基準位址為函式定義所在層級物件的首位址,範圍為該層級物件始末。
如:ia::ff();
this指標型別是以d0h為首位址,範圍是從首位址開始到dfh為止。(其實裡面有記憶體空洞,我們不去糾結這個)
derived::ff();
this指標型別是c0h為首位址,範圍是從首位址到e8h為止。
2.對於虛函式,this指標的基準位址為函式首先宣告者的首位址,範圍為實現者的始末。
如:ia::f();
其this指標型別是以d0h為首位址,範圍是從首位址開始到dfh為止。
derived::f();
其this指標型別是以d0h為首位址,範圍是從c0h到e8h為止。
那麼當有ia* a=new derived();後,
a->f();便是這麼訪問b成員的了。假設首位址d0h儲存在暫存器rax裡,
rax-8
C 虛函式指標與虛函式表
當父類中某個方法有virtual關鍵字修飾,則該方法被放入虛函式表中,同時,有乙個指標指向該父類的虛函式表。當子類繼承父類後,子類會繼承父類的虛函式指標和虛函式表,在子類構造函式呼叫時 會將自己的虛函式指標指向自己的虛函式表,但是如果子類重寫了該方法 加virtual或者不加都可以,但是方法必須完全...
C 虛函式實現 虛函式表 虛表指標
內聯函式 編譯時展開的,虛函式是為了實現多型,是動態行為,兩者是矛盾的。內聯函式展開就不存在了,也就不存在函式位址了,無法呼叫。但是,由於inline只是向編譯器建議,所以編譯器不會讓inline和virtual同時起作用,所以也不會報錯。建構函式 虛函式使用虛指標呼叫函式,呼叫建構函式之前沒有構造...
C 虛函式指標虛函式表
c 的多型可以分為靜態多型和動態多型。函式過載和運算子過載實現的多型屬於靜態多型,而通過虛函式可以實現動態多型。實現函式的動態聯編其本質核心則是虛表指標與虛函式表。1.虛函式與純虛函式區別 1 虛函式在子類裡面也可以不過載的 但純虛必須在子類去實現 2 帶純虛函式的類叫虛基類也叫抽象類,這種基類不能...