菱形继承图示:
本实例以经典的菱形多重继承、虚继承为例,研究类对象的大小,假设有以下的虚继承实例代码:
<span style="font-size:14px;">class Point2d
{
public:
float _x,_y;
};
class Vertex : public virtual Point2d
{
public:
Vertex *next;
};
class Point3d : public virtual Point2d
{
public:
float _z;
};
class Vertex3d : public Vertex,public Point3d
{
public:
float mumble;
};
void main()
{
cout << "Point2d: "<< sizeof(Point2d)<<endl;
cout << "Point3d: "<< sizeof(Point3d)<<endl;
cout << "Vertex: "<< sizeof(Vertex)<<endl;
cout << "Vertex3d: "<< sizeof(Vertex3d)<<endl;
}</span>
本程序在VS2010下做测试,通过查看类 Vertex3d 类的内存布局如下:
从上图可以清晰的看到:sizeof(Vertex3d) = 28;
标号1处是 class Vetex内存布局,占用 8 字节空间,vbptr 是指向 virtual base Point2d 的指针;next是其自身的数据成员
标号2处是 class Point3d内存布局,占用 8字节空间,vbptr同样是指向 virtual base Point2d的指针,_z是该类自身的数据成员
标号3处是 class Vertex3d自身的数据成员 mumble,由于上图就是class Vertex3d自身的布局图,大小是 28
标号4处是 class Point2d内存布局,占用8字节空间,_x,_y是该类自身的数据成员
可见,class Vertex3d 虚继承自 Vertex和Point3d,自身数据组成有四部分:
(1)Vertex,如上图标号1所示
(2)Point3d,如上图标号2所示
(3)自身的数据成员 mumble,如图标号3所示
(4)Point2d,如图标号4所示
在多层的虚继承中,最后继承的类(例如本例的Verted3d类),将重复继承的基类(Point2d)部分保留一份,它的上层基类(Vertex,Point3d)内部只是保留自身的数据成员和一个指向虚基类的指针。
如果在基类中加入虚函数,研究指向虚基类的指针和虚函数表指针是否会重合,代码如下:
class Point2d
{
public:
virtual void func(); //加入一个虚函数
float _x,_y;
};
class Vertex:public virtual Point2d
{
public:
Vertex *next;
};
class Point3d:public virtual Point2d
{
public:
float _z;
};
class Vertex3d:public Vertex,public Point3d
{
public:
float mumble;
};
void main()
{
cout << "Point2d: "<< sizeof(Point2d)<<endl;
cout << "Point3d: "<< sizeof(Point3d)<<endl;
cout << "Vertex: "<< sizeof(Vertex)<<endl;
cout << "Vertex3d: "<< sizeof(Vertex3d)<<endl;
}
class Vertex的内存布局:
总结:最初始的基类(例如.Point2d)的数据保留在最后继承的类(例如.Vertex3d)中,中间的类(例如.Vertex、Point3d)只是保留自身的数据和一个指向虚基类的指针而已。描述起来词不达意的感觉,详细请看《深入理解C++对象模型》