1、每個c++類都有一個vtable,每個類對象都有個vtable的vptr;
2、在vc中,類的繼承是在基類後面追加數據的形式進行繼承的。
測試代碼如下(在32位系統下的vs2008環境中測試的):
{
public:
Test(int a) {data = a;}
virtual ~Test() {cout<<"Test deconstruct"<<endl;}//基類中的虛析構函數
virtual void fun11() {cout<<"Test virtual fun11"<<endl;}//基類中的虛函數fun11
virtual void fun12() {cout<<"Test virtual fun12"<<endl;}//基類中的虛函數fun12
int data;
};
class Test1:public Test
{
public:
Test1(int d1, int d2):Test(d2) {data1 = d1;data2 = d2;}
int data1;
int data2;
virtual ~Test1() {cout<<"test1 deconstruct"<<endl;}//派生類中的虛析構函數
virtual void fun1() {cout<<"test1 virtual fun1"<<endl;}//派生類中的虛函數fun1,不是實現基類中的fun11的多態
virtual void fun2() {cout<<"test1 virtual fun2"<<endl;}//派生類中的虛函數fun2,不是實現基類中的fun12的多態
};
typedef void (*Fun)(void);//指向函數的指針
int main()
{
cout<<"test in 32bit system"<<endl;
Test1 obj(1,2);//定義對象obj
cout << "obj's Size = " << sizeof(obj) << endl;
cout << "obj 's Address = " << &obj << endl;
cout<<"second Test1 object's address = "<<&obj + 1<<endl;//爲了測試(int*)(&obj+1)和((int*)&obj+1)的區別
cout<<"third Test1 object's address = "<<&obj + 2<<endl;
cout<<"base data address and data: "<<(int*)&obj + 1<<"\t"<<*((int*)&obj + 1)<<endl;
cout<<"derivate data1 address and data1:"<<(int*)&obj + 2<<"\t"<<*((int*)&obj + 2)<<endl;
cout<<"derivate data2 address and data2:"<<(int*)&obj + 3<<"\t"<<*((int*)&obj + 3)<<endl;
//獲得虛表指針,顯示虛表中的內容
cout<<"vtable address = "<<(int*)&obj<<"\t"<<"value = "<<*((int*)&obj + 0)<<endl;
cout<<"vtable value0 = "<<*((int*)*(int*)((int*)&obj+0)+0)<<endl;
cout<<"vtable value1 = "<<*((int*)*(int*)((int*)&obj+0)+1)<<endl;
cout<<"vtable value2 = "<<*((int*)*(int*)((int*)&obj+0)+2)<<endl;
cout<<"vtable value3 = "<<*((int*)*(int*)((int*)&obj+0)+3)<<endl;
cout<<"vtable value4 = "<<*((int*)*(int*)((int*)&obj+0)+4)<<endl;
cout<<"vtable value5 = "<<*((int*)*(int*)((int*)&obj+0)+5)<<endl;
Fun pFun = NULL;
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1);
pFun();
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2);
pFun();
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+3);
pFun();
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+4);
pFun();
return 0;
}
輸出結果:
此時的派生類虛表結構爲:
virtual ~Test() |
virtual void fun11() |
virtual void fun12() |
virtual void fun1() |
virtual void fun2() |
將上述程序中標紅的程序分別改爲下面相應的程序:
~Test() {cout<<"Test deconstruct"<<endl;}
virtual ~Test1() {cout<<"test1 deconstruct"<<endl;}//派生類中的虛析構函數
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+0);
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1);
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+3);
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+4);
結果爲:
此時的派生類虛表結構爲:
virtual void fun11() |
virtual void fun12() |
virtual ~Test1() |
virtual void fun1() |
virtual void fun2() |
將上述程序中標紅的程序再分別改爲下面相應的程序:
virtual ~Test() {cout<<"Test deconstruct"<<endl;}
//virtual ~Test1() {cout<<"test1 deconstruct"<<endl;}//派生類中的虛析構函數
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1);
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2);
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+3);
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+4);
結果爲:
此時的派生類虛表結構爲:
此時的派生類虛表結構爲:
virtual ~Test() |
virtual void fun11() |
virtual void fun12() |
virtual void fun1() |
virtual void fun2() |
分析:
1、這個對象的大小爲16byte,包括最前面的一個int*型的虛表指針和3個int數據。
2、(int*)(&obj+1)和((int*)&obj+1)的區別是:前面表示的是地址按對象大小增加,後面表示的是一個對象地址按4個字節增加。
3、虛表中存放的是所有虛函數的首地址,存放順序和(繼承順序、函數的聲明順序)有關。
4、當派生類中重載了基類中的函數時,(包括析構函數),這時候虛表中就只會有基類中的虛函數的地址,但是當調用派生類中重載的虛函數時,實現的是重載的功能。
5、析構函數調用順序,先是派生類再是基類。