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


    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
    请按任意键继续. . .
    */
    
    
  • 相关阅读:
    Java 集合(静态导入)
    Java 集合 (Collections、Arrays)
    Java 异常
    Java 多态
    Java 继承

    内网服务器配置访问公网
    替换centos的原生yum源为阿里云yum源
    centos7安装杀毒软件ClamAV
    linux程序名称带devel跟不带的区别
  • 原文地址:https://www.cnblogs.com/cswuyg/p/1804084.html
Copyright © 2020-2023  润新知