今天看啥
热点:

多重虚继承下的对象内存布局


《深入C++对象模型》绝对是一本值得深读的一本书,书里多次出现一句话,“一切常规遇见虚继承,都将失效”。这是一个有趣的问题,因为C++标准容忍对象布局的实现有较大的自由,出现了各编译器厂商实现的方式不同。
 
今天谈谈visual studio2013多重虚继承下对象布局。有错不要客气,不要吝啬你的留言,请直接开喷。
 
 
 
class y和class z都是从class x虚继承来的子类(也叫派生类),class A是class y和class z的多重继承子类。为了简化问题,下面的data member都是none_static data member。不提static data member是为了描述起来简单~
 
 
#include<iostream>
class x
{
public:
    int _x;
};
class y : public virtual x
{
public:
    int _y;
};
class z : public virtual x
{
public:
    int _z;
};
class A:public z,public y
{
public:
    int _a;
};
    int main()
{
    std::cout <<"sizeof(x): "<< sizeof(x) << std::endl;
    std::cout <<"sizeof(y): "<< sizeof(y) << std::endl;
    std::cout <<"sizeof(A): "<< sizeof(A) << std::endl;
    std::cout <<"&A::_x :"<< &A::_x << std::endl;;
    std::cout << "&A::_y :" << &A::_y << " " << std::endl;
    std::cout << "&A::_z :" << &A::_z << " " << std::endl;
    std::cout <<"&A::_a :"<< &A::_a << " " << std::endl;

    getchar();
    return 0;
}

 

 
 
输出:
 
sizeof(x): 4
sizeof(y): 12
sizeof(A): 24
 
sizeof(x)和sizeof(y)的结果在我们的意料中:x中没有虚函数,所以sizeof(x) = sizeof(int)。class y虚继承自class x,它需要一个指针指向类似于virtual base table的指针(下面简称vbptr),指向自己实际的x对象地址,所以sizeof(y)=2*sizeof(int) + sizeof(vbptr),我使用32位编译器生成的代码,所以sizeof(y)=12.
 
按照我开始的料想,sizeof(A)应该等于sizeof(int)*4(分别是:_x,_y,_z,_a) + sizeof(vbptr)=20。这里的vbptr指向了唯一的x实例。
 
(注意啦,我要开始了)
 
C++标准中有规定,子类的对象模型中,应该保持父类对象的布局。在上面,我们说了sizeof(y)=2*sizeof(int) + sizeof(vbptr),bingo~,这里的sizeof(A)就是sizeof(y) + sizeof(z)=24
 
而vbptr因为出在了两个父类中,已经不需要额外的一个vbptr指向了。
 
你是不是要问这个vbptr(虚基类表指针)到底是干什么的?
 
我们知道虚继承的父类x,无论它被派生多次,它在最后多重继承的子类中,只存在一份实例。这样可能出现这样的情况:
 
y object_y;
 
A object_A;
 
object_A._x =1;
 
object_y = object_A;//这里发生类对象的剪切,将子类中的非父类成员剪去,剩下的赋给父类。
 
可能你还没有明白,没关系,我再啰嗦一句~
 
抱歉没有很好的绘图工具,我们使用“|“来隔开内存中的成员。
 
 object_y 的内存布局应该是这样的:vbptr | _x | _y,注意先实例化父类,再实例化子类。
 
而,object_A的内存布局应该是这样的:vbptr_z | _z | vbptr_y | _y | _a | _x,注意我们多重继承的先后顺序:class A:public z,public y,这个顺序决定了z的对象布局在y对象前面。因为虚继承的原因,我们对象布局发生了改变:先实例化不共享部分(也就是class y和class z中除了class x的成员),这个部分依然是先父类再子类。最后才是虚继承的公共部分:class x的成员。
 
我们发现,直接进行内存布局的剪切行不通(红色部分),这需要编译器介入,但编译器也不是神仙啊,它需要信息去找_x在哪里,这就是vbptr中存的信息——它告诉编译器去哪里找_x,这里的信息可能是偏移,也可能是指针。为什么是表呢?而不是直接指向成员的指针呢?因为,如果你再虚继承几个父类,你的这个指针会越来越多,对象的规模也就越来越大,这不能容忍。使用表可以始终只占一个指针大小,只是需要间址查询,但是这完全可以由编译器优化之。

www.bkjia.comtruehttp://www.bkjia.com/cjjc/985834.htmlTechArticle多重虚继承下的对象内存布局 《深入C++对象模型》绝对是一本值得深读的一本书,书里多次出现一句话,一切常规遇见虚继承,都将失效。...

相关文章

相关搜索: 布局 对象 内存

帮客评论

视觉看点