对象内存布局 (13)

来源:互联网 发布:程序员工作特长 编辑:程序博客网 时间:2024/06/04 23:35

转自http://blog.csdn.net/pathuang68/article/details/4105810


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

 

如果Derived有两个虚基类,那么这两个虚基类的实例指针,分别位于虚基类表的第2项和第3项,最后一项为0,意味着虚基类表的结束。虚基类表中的第1项是什么?目前不清楚,但是它的值大部分时候为0(请牛人指教,编译器是VC6)。下面我们来检验之。

 

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

         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;

编译后运行结果:

不难发现,虚基类示例地址 = 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。

 


0 0
原创粉丝点击