C++对象内存布局

来源:互联网 发布:狗笼子淘宝 编辑:程序博客网 时间:2024/06/16 01:55
#include <iostream>using namespace std;//本程序在VS2010 和 Linux 下测试。/*类之间的关系图:       _____      |__X__|      /v    \v   _____     _____  |__Y__|   |__Z__|   (v)\ _____ /(v)      |__A__|          |       _____          |__B__|*/class X{public:X(int a): x(a){};virtual ~X(){};//protected:int x;};class Y: virtual public X {public:Y(int a, int b): X(a), y(b){};//protected:int y;};class Z: virtual public X {public:Z(int a, int b): X(a), z(b){};//protected:int z;};/*class A: public Y, public Z //A不是虚继承{public:A(int ax, int bx, int cx): X(ax), Y(ax, bx), Z(ax, bx), a(cx){};//virtual void test(){};int a;};*//*class B: public A //A不是虚继承{public:B(int ax, int bx, int cx, int dx): X(ax),  A(ax, bx, cx), b(dx){};int b;};*/class A: virtual public Y, virtual public Z//A是虚继承{public:A(int ax, int bx, int cx): X(ax), Y(ax, bx), Z(ax, bx), a(cx){};int a;};class B: public A //A是虚继承{public:B(int ax, int bx, int cx, int dx): X(ax), Y(ax, bx), Z(ax, bx),  A(ax, bx, cx), b(dx){};int b;};int main(){X xx(1);Y yy(1, 2);Z zz(1, 2);A aa(1, 2, 3);B bb(1, 2, 3, 4);cout<<"SIZE of xx: "<<sizeof(xx)<<endl; //8cout<<"address of xx && xx.x: "<<&xx<<"  "<<&xx.x<<endl; // 0013F910  0013F914 说明vptr放在成员之前,布局为:vptr_x, xcout<<"SIZE of yy: "<<sizeof(yy)<<endl; //16cout<<"address of yy && yy.y && yy.x: "<<&yy<<"  "<<&yy.y<<"  "<<&yy.x<<endl;//0028F8F8  0028F8FC  0028F904 说明布局为: vptr_y, y, vptr_x, x cout<<"SIZE of zz: "<<sizeof(zz)<<endl; //16 同Ycout<<"address of zz && zz.z && zz.x: "<<&zz<<"  "<<&zz.z<<"  "<<&zz.x<<endl;cout<<"SIZE of aa: "<<sizeof(aa)<<endl; //28 A不是虚继承, 且A的所有虚函数已经包含在X中了,所以自己不需要vptr_a,如果A中添加虚函数test则在最顶端添加vptr_a                                        //32 A是虚继承,有vprt_acout<<"address of aa && aa.a && aa.y && aa.z && aa.x: "<<&aa<<"  "<<&aa.a<<"  "<<&aa.y<<"  "<<&aa.z<<"  "<<&aa.x<<endl;                                        //A不是虚继承:0025FA3C  0025FA4C  0025FA40  0025FA48  0025FA54 布局为vptr_y, y, vptr_z, z, a, vptr_x, x (先确定基类)            //A是虚继承:  001BF800  001BF804  001BF814  001BF81C  001BF80C 布局为vptr_a, a, vptr_x, x, vptr_y, y, vptr_z, z(先确定A中不变部分)cout<<"SIZE of bb: "<<sizeof(bb)<<endl; //32  A不是虚继承                                        //36  A是虚继承cout<<"address of bb && bb.y && bb.z && bb.a && bb.b && bb.x: "<<&bb<<"  " <<&bb.y<<"  "<< &bb.z<<" "<<&bb.a<<"  "<<&bb.b<<"  "<<&bb.x<<endl;                                        //A不是虚继承:        0027F954     0027F958      0027F960     0027F964     0027F968    0027F970 布局为vptr_y, y, vptr_z, z, a, b, vptr_x, x                                        //A是虚继承:          0022F78C     0022F7A4      0022F7AC     0022F790     0022F794    0022F79C 布局为vptr_a, a, b, vptr_x, x, vptr_y, y, vptr_z, z}

vptr放在数据成员前。

a:
   1. 对于普通继承(不管包不包括虚函数),都是按照继承顺序从左至右先为基类对象分配内存,再为派生类分配

   2. 存在虚函数时,如果派生类中没有新增虚函数,则只需要基类的虚函数指针vptr即可,否则还要新增一个自己的vptr,多重继承时每个包含虚函数的分支的基类都要有vptr;

b:

   虚继承时,先为本类中不变部分分配内存,再确定共享部分的内存;虚继承一定需要vptr来存储共享部分的偏移。

 

原创粉丝点击