• 对象内存布局 (12)


    下面来看看虚基类对对象内存布局的影响。虚基类的主要作用就是在所有的派生类中,保留且仅保留一份虚基类的suboject。

    a. 一个虚基类的情况

    #include <iostream>
    using namespace std;
    
    class Base
    {
    public:
        int base_member;
    };
    class Derived : public virtual Base {};
    
    int main(void)
    {
        Base b;
        Derived d;
        cout << sizeof(b) << endl;
        cout << sizeof(d) << endl;
        return 0;
    }

    运行结果:

    注意使用了虚继承,即class Derived : public virtual Base。这次Derived的对象大小为什么为8 bytes呢?这是因为编译器会给Derived对象安插一个虚基类表指针vbptr,下面给出Derived对象的memory layout:

     

    虚基类表指针vbptr指向Derived类的virtual bass class table(虚基类表),虚基类表中存放的是Derived类的虚基类表指针到虚基类实例指针的偏移量

     在main函数的return前,增加如下语句:

    #include <iostream>
    using namespace std;
    
    class Base
    {
    public:
        int base_member;
    };
    
    class Derived : public virtual Base {};
    
    int main(void)
    {
        Base b;
        Derived d;
        cout << sizeof(b) << endl;
        cout << sizeof(d) << endl;
        cout << "Derived object d's vbptr = " << (unsigned long*)(&d) << endl;
    
        cout << "Address of virtual base class table = " << (unsigned long*)*(unsigned long*)(&d) << endl;
    
        cout << "Item 1 in virtual base class table = " << *(unsigned long*)*(unsigned long*)(&d) << endl;
    
        cout << "Item 2 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 1) << endl;
    
        cout << "Item 3 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 2) << endl;
    
        cout << "The address of virtual base class Base = " << (Base*)(&d) << endl;
        return 0;
    }

    编译后运行结果:

    编译后运行结果:

    不难发现,虚基类示例地址 = vbptr + offset,即0x0012FF78 = 0x0012FF74 + 4。图示如下:

    b. 我们来看看Derived有两个虚基类的情况:

    #include <iostream>
    using namespace std;
    
    class Base1
    {
    public:
        int base1_member;
    };
    class Base2
    {
    public:
    
        int base2_member;
    };
    
    class Derived : public virtual Base1, public virtual Base2 {};
    
    int main(void)
    {
        Base1 b1;
    
        Base2 b2;
    
        Derived d;
    
        cout << sizeof(b1) << endl;
    
        cout << sizeof(b2) << endl;
    
        cout << sizeof(d) << endl;
    
        cout << "Derived object d's vbptr = " << (unsigned long*)(&d) << endl;
    
        cout << "Address of virtual base class table = " << (unsigned long*)*(unsigned long*)(&d) << endl;
    
        cout << "Item 1 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 0) << endl;
    
        cout << "Item 2 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 1) << endl;
    
        cout << "Item 3 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 2) << endl;
    
        cout << "Item 3 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 3) << endl;
    
        cout << "The address of virtual base class: Base1's instance = " << (Base1*)(&d) << endl;
    
        cout << "The address of virtual base class: Base2's instance = " << (Base2*)(&d) << endl;
    
        return 0;
    
    }

    编译运行结果如下:

    Derived对象的memory layout图解如下:

     

    不管Derived类有多少个虚基类,它只有一个vbptr和一个virtual base class table

  • 相关阅读:
    一个MMORPG的常规技能系统
    as3.2版本中中jar生成方法
    lua中的weak table
    lua中使用table实现类和继承
    Javascript-设计模式_代理模式
    Javascript-设计模式_职责链模式
    Javascript-设计模式_策略模式
    前端安全第四期
    前端安全第三期
    前端安全第二期
  • 原文地址:https://www.cnblogs.com/wuchanming/p/4092159.html
Copyright © 2020-2023  润新知