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() 虚拟继承了基类的派生类的对象内存布局: 0041C2F8 0041C2FC 00000064 0041C2F0 0000000A 第一虚函数表第一项,虚函数Derived::show2()地址:00401280 Derived::show2() 第二虚函数表第一项,虚函数Base::show1()地址 :00401250 Base::show1() 虚基类表第一项,本类对象地址 - 虚基类表指针地址 = FFFFFFFC 虚基类表第二项,基类对象地址 - 虚基类表指针地址 = 00000008 请按任意键继续. . . */