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