我們知道當我們sizeof 一個類的時候,類的成員函數是不計算在對象的大小的里的,這是為什么呢?因為類的成員函數不是屬於某一個對象的,而是類的所有對象所共享的,就像static變量那樣。如果虛函數和普通成員函數一樣,那么我們就不能通過指向子類的基類指針來引用子類的方法了,因為我們將不知道調用哪個方法,多態就無從談起。那么多態是怎么實現的呢?
- 虛函數、虛指針與虛表
我們可以做一個小實驗
class A{ public: int a; virtual void myfun(){} }; class B:public A{ public: int b; }; B obj_b;
obj_b.a=1;
obj_b.b=2; A *p=&B; cout<<p<<endl; cout<<&(p->a)<<endl;
cout<<p->a<<'\t'<<*(&(p->a)+1)<<endl;
p的值和&(p->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。
那么多重繼承時是什么情況呢?
多重繼承的時候,對於每個有虛函數的基類,子類都會繼承相應的虛指針並改寫虛表。
- this指針
我覺得一篇blog寫的挺好就引用過來了。博客地址為:http://www.cnblogs.com/CCQLegend/p/3270738.html
this指針跟不少人想象的不一樣,它的類型由被調用函數決定。它的類型遵循着這兩點規則:(途中打勾為首地址。)
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