对象内存布局 (12)

简介: 下面来看看虚基类对对象内存布局的影响。虚基类的主要作用就是在所有的派生类中,保留且仅保留一份虚基类的suboject。   a. 一个虚基类的情况 #include using namespace std; class Base { public: int base...

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

相关文章
|
存储 安全 算法
深入剖析JVM内存管理与对象创建原理
JVM内存管理,JVM运行时区域,直接内存,对象创建原理。
41 2
|
2月前
|
存储 算法 安全
【JVM】深入理解JVM对象内存分配方式
【JVM】深入理解JVM对象内存分配方式
30 0
|
4月前
|
存储 C++
|
23天前
|
缓存 Java
Java中循环创建String对象的内存管理分析
Java中循环创建String对象的内存管理分析
22 2
|
2天前
为对象分配内存TLAB
为对象分配内存TLAB
|
2天前
|
Java
SpringBoot 项目启动初始化一个Map对象到内存
SpringBoot 项目启动初始化一个Map对象到内存
|
3天前
|
存储 机器学习/深度学习 Java
【Java探索之旅】数组使用 初探JVM内存布局
【Java探索之旅】数组使用 初探JVM内存布局
11 0
|
2月前
|
Python
Python中如何判断两个对象的内存地址是否一致?
Python中如何判断两个对象的内存地址是否一致?
18 0
|
2月前
|
存储 安全 Java
【JVM】Java堆 :深入理解内存中的对象世界
【JVM】Java堆 :深入理解内存中的对象世界
56 0
|
3月前
|
存储 编译器 程序员
近4w字吐血整理!只要你认真看完【C++编程核心知识】分分钟吊打面试官(包含:内存、函数、引用、类与对象、文件操作)
近4w字吐血整理!只要你认真看完【C++编程核心知识】分分钟吊打面试官(包含:内存、函数、引用、类与对象、文件操作)
109 0