1、帶有虛函數的類
class Base { public: virtual void FunTest1() { cout << "Base::FunTest1()" << endl; } virtual void FunTest2() { cout << "Base::FunTest2()" << endl; } int _data1; }; int main() { Base b; b._data1 = 0x01; return 0; }
對象模型:
mian函數的反匯編:
如果類中沒有自己寫構造函數,並且含有虛函數,那麼編譯器就會合成一個缺省的構造函數。
Base()的構造函數分析:
1>在它的構造函數中主要完成的是:在&b指向的那塊空間中,填寫了虛指針,
2>注意:虛表是編譯器在編譯和鏈接完成之後就已經建立好的,在構造函數中只是將虛表的地址填寫到對象的前4個字節。
3>虛表中虛函數地址的存放順序,是按照它在類中聲明的順序存放的。
4>虛表中最後的00 00 00 00 表示虛表結束(編譯器不同就不一定了)
vptr指向虛表:
對象模型:
先是虛函數指針,再是該類的數據成員
2、單繼承(派生類中沒有虛函數的覆蓋)
class Base { public: virtual void FunTest1() {cout<<"Base::FunTest1()"<
主要還是完成虛指針的填寫
在是Derive的構造函數:
派生類最後的對象模型為:如果派生類沒有對基類中的虛函數進行重寫時,派生類中的虛表先是基類的虛函數地址,然後再加上自己的虛函數地址。虛函數地址的順序為在類中聲明的順序。
派生類中Base的虛表
3、單繼承(含有虛函數的覆蓋)
class Base { public: virtual void FunTest1() { cout << "Base::FunTest1()" << endl; } virtual void FunTest2() { cout << "Base::FunTest2()" << endl; } int _data1; }; class Derive :public Base { public: virtual void FunTest1()//覆蓋基類中的FunTest1 { cout << "Derive::FunTest1()" << endl; } virtual void FunTest3() { cout << "Derive::FunTest3()" << endl; } virtual void FunTest4() { cout << "Derive::FunTest4()" << endl; } int _data2; }; typedef void (*VtbFun)(); void PrintVtable() { cout << "Derive類的虛函數表: " << endl; Derive d1; d1._data1 = 0x01; d1._data2 = 0x02; int* pVTable = (int *)*(int*)&d1; VtbFun FunTest = (VtbFun )*pVTable; while (NULL != FunTest) { FunTest(); cout << ( int*)FunTest << endl; pVTable += 1; FunTest = ( VtbFun)*pVTable; } cout << "虛表結束: " << endl; } int main() { PrintVtable(); return 0; }
派生類對象模型及虛表建立規則:先將基類的虛表搬移過來,若派生類對基類中的某個函數進行了重寫,則會用派生類重寫的虛函數的地址替換掉虛表中相應位置基類中虛函數的地址,替換完之後再將派生類自己的虛函數地址按照聲明的順序添加到虛表中
4、多繼承(沒有虛函數的覆蓋)
class Base { public: virtual void FunTest1() { cout << "Base::FunTest1()" << endl; } virtual void FunTest2() { cout << "Base::FunTest2()" << endl; } int _data1; }; class Base1 { public: virtual void FunTest3() { cout << "Base1::FunTest3()" << endl; } virtual void FunTest4() { cout << "Base1::FunTest4()" << endl; } int _data2; }; class Derive :public Base, public Base1 { public: virtual void FunTest5() { cout << "Derive::FunTest5()" << endl; } int _data3; }; typedef void (*VtbFun)(); void PrintVtable() { cout << "Derive類的虛函數表: " << endl; Derive d1; d1._data1 = 0x01; d1._data2 = 0x02; int* pVTable = (int *)*(int*)&d1; VtbFun FunTest = (VtbFun )*pVTable; while (NULL != FunTest) { FunTest(); cout << ( int*)FunTest << endl; pVTable += 1; FunTest = ( VtbFun)*pVTable; } cout << "虛表結束. " << endl; } int main() { Derive d; d._data1 = 0x01; d._data2 = 0x02; d._data3 = 0x03; PrintVtable(); return 0; }
5、多繼承(含有虛函數的覆蓋)
classBase { public: virtualvoidFunTest1() { cout<<"Base::FunTest1()"<
此時派生類的對象模型和虛表的結構:
派生類虛表建立過程:先建立和Base1相同的部分,在Derive中對FunTest3進行了重寫,所以替換掉虛表中原來的Base1::FunTest3改為了Derive::FunTest3,為了提高訪問速度,將自己特有的虛函數加在第一份虛表的後面,建立Base虛表的過程與Base1相同。
6、虛擬繼承
classBase { public: virtualvoidFunTest1() { cout<<"Base::FunTest1()"<