虛函數是C++實現多態的關鍵,沒有虛函數,C++只能是OB,不能完成OO。對於VC++中虛函數的實現機制,有很多文章,我看過的是陳浩寫的,連結如下:
http://blog.csdn.net/haoel/article/details/1948051。總覺得還是有些不太清楚的,所以自己做了進一步的實驗,記錄下來以供參考。
本文介紹的是沒有繼承情況下,帶有虛函數的類在記憶體中布局,以及其執行個體(對象)記憶體布局。
1.源碼
#include <iostream>#include <stdio.h>using namespace std;class CVirtual{public:int x;public:virtual void VF(){cout<<this->x<<endl;cout<<"hello"<<endl;}public:CVirtual(int x){this->x = x;}};typedef void (CVirtual::*Fun)();union{Fun f;unsigned int addr;}ut;int main(int argc, char** argv){//列印出類執行個體的大小cout<<"對象大小為 :"<<sizeof(CVirtual)<<endl;CVirtual *p = new CVirtual(999);CVirtual *p1 = new CVirtual(888);//列印對象地址cout<<"建立對象的地址 :"<<p<<endl;//列印第一個成員變數地址cout<<"對象中第一個成員變數的地址 :"<<&p->x<<endl;//列印虛函數的地址ut.f = &(CVirtual::VF);cout<<"類中第一個虛函數的地址 :"<<std::hex<<std::showbase<<ut.addr<<endl;//虛表指標unsigned int vptr = *((unsigned int*)p);cout<<"對象1中虛表指標(即虛表地址)為 :"<<std::hex<<std::showbase<<vptr<<endl;//虛表第一項值為unsigned slot0 = *((unsigned int*)vptr);cout<<"虛表中第一項的值(第一個虛函數地址):"<<std::hex<<std::showbase<<slot0<<endl;//虛表指標unsigned int vptr1 = *((unsigned int*)p1);cout<<"對象2中虛表指標(即虛表地址)為 :"<<std::hex<<std::showbase<<vptr1<<endl;//虛表第一項值為unsigned slot01 = *((unsigned int*)vptr1);cout<<"虛表中第一項的值(第一個虛函數地址):"<<std::hex<<std::showbase<<slot01<<endl;//虛函數的原型typedef void (__thiscall *MyFun)(void* pThis);//調用虛函數表中的第一個函數MyFun f = (MyFun)slot0;f(p);//調用虛函數MyFun f1 = (MyFun)ut.addr;f1(p);delete p;delete p1; cin>>argc;}
2.結果
3.記憶體布局圖
4.結論
- 虛函數表在編譯期間已經確定,建立在data區,運行期只是把由建構函式把對象的vptr值設定為這個地址,同一個類的所有執行個體共用同一個虛函數表;
- 虛函數表中的每一個項目不一定是虛函數的地址,很可能是一個代理函數,然後由代理函數再調用虛函數;