C++对象内存布局--④VS编译器--单个虚拟继承

时间:2023-01-02 10:27:40

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
请按任意键继续. . .
*/