C++對象記憶體布局--④VS編譯器--單個虛擬繼承
在VS2005編譯器下,證明單個虛擬繼承的記憶體布局:無論有無虛函數,必然含有虛基類表指標。虛基類表中的內容為本類執行個體的位移和基類執行個體的相對位移值。
如果有虛函數,那麼基類的虛函數表跟衍生類別的虛函數表是分開的。
在記憶體布局上,地址從低到高,順序如下:衍生類別的虛函數表指標,虛基類表指標,衍生類別的成員變數,基類的虛函數表指標,基類的成員變數。
也就是說衍生類別在上,基類在下。這個跟普通的繼承相反。
特別說明,GNU的GCC編譯器在處理虛擬繼承上跟VS有不同的地方。它的記憶體布局是:衍生類別的虛函數表跟虛基類表合并,另外分析。
另外,發現如果衍生類別實現了基類的虛函數,那麼衍生類別對象,衍生類別和基類的執行個體之間會多出一個值為0的間隔。
//VS編譯器--單個虛擬繼承.cpp//2010.8.18#include <iostream>using namespace std;//////////////////////////////////////////////////////////////////class Base{ public: Base(int a = 10):a(a) { cout << "Base::Base()" << endl; } virtual void show1() { cout << "Base::show1()" << endl; } private: int a;};//////////////////////////////////////////////////////////////////class Derived : virtual public Base{ public: Derived(int b = 100):b(b) { cout << "Derived::derived()" << endl; } virtual void show2() { cout << "Derived::show2()" << endl; } private: int b;};//////////////////////////////////////////////////////////////////int main(){ Derived obj; int** p = (int**)&obj; typedef void (__thiscall *fun)(void*pThis);//非常重要 cout << "虛擬繼承了基類的衍生類別的對象記憶體布局:" <<endl; for (int i = 0; i != sizeof(obj)/4; ++i) { cout << p[i] << endl; } cout << endl << "第一虛函數表第一項,虛函數Derived::show2()地址:" << (int*)p[0][0] << endl; ((fun)(p[0][0]))(p); cout << "第二虛函數表第一項,虛函數Base::show1()地址 :" << (int*)p[3][0] << endl; ((fun)(p[3][0]))(p+3); cout << endl << "虛基類表第一項,本類對象地址 - 虛基類表指標地址 = " << (int*)p[1][0] << endl; cout << "虛基類表第二項,基類對象地址 - 虛基類表指標地址 = " << (int*)p[1][1] << endl; system("pause"); return 0;}/*Base::Base()Derived::derived()虛擬繼承了基類的衍生類別的對象記憶體布局:0041C2F80041C2FC000000640041C2F00000000A第一虛函數表第一項,虛函數Derived::show2()地址:00401280Derived::show2()第二虛函數表第一項,虛函數Base::show1()地址 :00401250Base::show1()虛基類表第一項,本類對象地址 - 虛基類表指標地址 = FFFFFFFC虛基類表第二項,基類對象地址 - 虛基類表指標地址 = 00000008請按任意鍵繼續. . .*/