#include<iostream> using namespace std;
class A{ public: int i; char c; void f(){cout<<"A::f()"<<endl;} virtual void vf(){cout<<"A::vf()"<<endl;} A():i(11){} }a;
class B{ public: void f(){cout<<"B::f()"<<endl;} virtual void vf(){cout<<"B::vf()"<<endl;} int c; int i; B():i(22),c(66){} }b;
int main(){ A *pA=(A*)&b; pA->f();/*編譯時(shí)就決定了調(diào)用A::f()。因?yàn)椴皇翘摵瘮?shù),不存在"運(yùn)行時(shí)決定類型"。 (所謂運(yùn)行時(shí)決定類型,其實(shí)就是在調(diào)用虛函數(shù)時(shí),將根據(jù)對象的內(nèi)存地址來偏移,找到虛函數(shù)表。。。) 類的非虛成員函數(shù)其實(shí)是全局函數(shù)(因此,就存儲空間而言,它”不屬于“類),調(diào)用時(shí)根據(jù)隱 含指針this來決定調(diào)用哪個,其實(shí)就是全局的重載函數(shù)——根據(jù)形參決定調(diào)用版本。 這里傳遞的是A類指針,當(dāng)然調(diào)用的是void f(A* this) 這個版本。 因此,編譯時(shí)就確定了調(diào)用的哪個函數(shù)。 為什么不在運(yùn)行時(shí)決定?因?yàn)樗?#8221;不屬于“類,它是全局的,不可能根據(jù)類對象地址來偏移來尋址。 */ cout<<pA->i<<endl;/*編譯時(shí)認(rèn)為將輸出A::i,但是運(yùn)行時(shí)根據(jù)類對象尋址類成員變量, 輸出的其實(shí)是:int(b對象的地址 + a對象中i相對于&a的偏移)。 為什么要在運(yùn)行時(shí)決定?因?yàn)樗?#8220;屬于”類的,要根據(jù)類對象的地址來偏移尋址。 cout<<pA->b<<endl;編譯時(shí)認(rèn)為將輸出A::b,所以編譯出錯:"class A has no member named 'b' */ pA->vf();/*運(yùn)行時(shí)決定。 他是怎么做到運(yùn)行時(shí)決定的呢?魔術(shù),說穿了,所謂“運(yùn)行時(shí)動態(tài)類型”根本就是一個障眼法。 編譯時(shí),調(diào)用什么并不知道,只知道調(diào)用的是一個虛函數(shù),因此,根據(jù)指針指向的對象——b來尋址,(其實(shí),此刻它仍然把pA指向的b當(dāng)作A類對象,但是同一個編譯器下虛表相對于對象起始地址的偏移是編譯器已經(jīng)確定了的。)找到虛函數(shù)表地址(虛表是在類內(nèi)部的),然后根據(jù)虛表找到虛函數(shù)地址。 因此,“運(yùn)行時(shí)決定”的立足點(diǎn)是虛函數(shù)。 */ cout<<"\n------------------>"<<endl; cout<<sizeof b<<" "<<sizeof a<<endl; /*VC中,類對象各成員的存儲順序依次為:虛表(如果有則)4字節(jié),非靜態(tài)成員變量按聲明順序依次(默認(rèn)4字節(jié)對齊)。 靜態(tài)成員和成員函數(shù)都不在類對象的“內(nèi)部”*/ cout<<int(* ((char*)&b+4) )<<endl; cout<<int(* ((char*)&b+8) )<<endl; typedef void(*F)(); F ff= (F)*( (int*)*(int*)&b +0 ) ; ff(); cout<<"<------------------\n"<<endl;
system("pause"); }
|