C++继承与Class 内存模型

一、前言

    C++类主要包括属性和操作两类,在对象模型中即一个对象实例中占用内存的只是Class的属性部分,也就是数据成员部分,本文旨在剖析C++对象模型中在有继承情形下类对象的内存布局,主要分4种情况讨论:单一继承没有多态、单一继承有多态、多重继承、虚拟继承。


二、单一继承没有多态

    所谓单一继承没有多态,也就是Class B继承于(public继承)Class A,而且Class A没有虚函数。在这种情况下,Class B的对象内存中就会包含一个父类部分,其整个内存模型有父类部分和本身部分组成。如有两个类Class Point2D和Class Point3D定义如下:

class Point2D
{
public:
	//成员函数
	
protected:
	float _x;
	float _y;
};

class Point3D : public Point3D
{
public:
	//成员函数
private:
	float _z;
};
可以看出这是一个单一继承模型,即Class Point2D继承于Class Point3D,由于派生类内存模型包含基本部分和自身两个部分,所以Point2D和Point3D对象的内存模型分别为:


注意,上图中右边是Point3D的对象模型,上半部分是基类部分,下半部分是自身部分,这种上下结构基本是继承模型(不管是单继承还是多继承)的一个标准结构,一般都是基类部分在上,自身部分在下。


三、单一继承带有多态

    所谓单一继承带有多态,也就是在上面Point2D和Point3D继承体系中基类Class Point2D有虚函数,这是Point2D和Point3D的定义如下:

class Point2D
{
public:
	//非virtual成员函数
public:
	//virtual函数
	virtual void drawpoint();
	
protected:
	float _x;
	float _y;
};

class Point3D : public Point3D
{
public:
	//非virtual成员函数
public:
	//virtual函数
	virtual void drawpoint();
	
private:
	float _z;
};
由于Class Point2D中带有虚函数,也就是对Point2D来说具有多态,因此编译器要做一些额外的工作,这些额外的工作包括:(1)编译器为Point2D生成一个虚函数表(virtual function table,简称为VFT),VTF中存储的是类中虚函数的地址;(2)编译器在Point2D内存模型中插入一个指针对象,即虚函数表指针,指向虚函数表;(3)编译器要在class的默认构造函数和析构函数中增加一些代码,用来处理新增加的虚函数表指针,使它指向每个class对应的虚函数表 (注意,在单一继承系统中,每个层次的class都只有一个虚函数表和虚函数表指针,而对于多重继承系统中的派生类就有多个,后面会说明)。此时,Point2D和Point3D的对象模型为:


上图中,左右分别为Point2D和Point3D对象内存模型,但请注意,在两个模型中的虚函数表指针都是int vp2D;而且int vp2D在Point3D模型中是属于基类部分,这里有两层意思:(1)在单一继承中,派生类的虚函数表指针是从基类继承而来的(当然,这只是在基类由虚函数的情况下,如果基类没有虚函数,而派生类有虚函数,那就不用继承);(2)继承而来的虚函数表指针在派生类的构造函数中需要重新赋值,指向派生类自己的虚函数表,因为派生类除了覆盖基类的虚函数外,还有可能拥有自己的虚函数。

    针对上述第(2)层意思作进一步说明,如果说Point3D确实除了覆盖基类Point2D的虚函数外,还自己定义了一个或者多个虚函数的情况,具体分析两个Class的虚函数表构成,如将Point2D和Point3D的定义修改如下:

class Point2D
{
public:
	//非virtual成员函数
public:
	//virtual函数
	virtual void drawpoint();
	
protected:
	float _x;
	float _y;
};

class Point3D : public Point3D
{
public:
	//非virtual成员函数
public:
	//virtual函数
	virtual void drawpoint();
	virtual void show();
	
private:
	float _z;
};
在上述定义中,我们只在Point3D中增加了一个虚函数,则Point2D和Point3D的虚函数表构成分别为:


上图关于Point2D和Point3D的虚函数表的构成可知新增加的虚函数virtual void show()是跟在基类的虚函数后面的。


四、多重继承

    其实在理解了单一继承的情况下,理解多重继承还是比较好理解的,无非就是在派生类的内存结构中多了几个基类部分,也就是N个基类部分+1个自身部分,这里的N就是派生列表中基类的个数,如以下这一个多重继承体系:

上述继承体系表示为:class Vertex2D : public Point2D, public Vertex,上述三个类的定义如下:

class Point2D
{
public:
	//非virtual成员函数
public:
	//virtual函数
	virtual void drawpoint();
	
protected:
	float _x;
	float _y;
};


class Vertex
{
public:
	//非virtual成员函数
public:
	//virtual函数
	virtual void drawvertex();
	
protected:
	Vertex* next;
};


class Vertex2D : public Point2D, public Vertex
{
public:
	//非virtual成员函数
public:
	//virtual函数
	void drawpoint();
	void drawvertex();
	virtual void show();
	
private:
	float mumble;
};
根据上述class定义,Point2D有虚函数接口,Vertex有虚函数接口,Vertex2D有覆盖和新增虚函数,则各class的内存模型如下:

上图中,Class Vertex有两个基类部分,而且分别从两个基类继承了两个虚函数表指针,而至于每个虚函数表指针所指虚函数表的结构这里不进行详细介绍,后期会专门更新一篇文章进行阐述。


五、虚拟继承

    理解虚拟继承,最核心的一个概念就是需要记住:从虚拟基类派生的派生类内存模型构成由不变部分和共享部分组成,而这个共享部分指的就是虚拟基类,不变部分又包括直接基类部分和自身部分。之所以有这样一个结构,是因为虚拟继承一般都是在至少有三层继承的情况下才能发挥实际作用,当然,比如刚刚介绍的单一两层继承体系结构也可以使用虚拟继承,只是没有什么实际意义。虚拟继承主要是为了解决多路继承情况下的成员重复的问题。(博友可以查阅其他专门介绍虚拟继承的文章进行进一步的了解)

    如果有以下虚拟继承结构:

其中Class Point2D是虚拟基类,具体继承关系为:

class Vertex  : virtual public Point2D

class Point3D  : virtual public Point2D

class Vertex3D  : public Vertex, public Point3D

各个Class定义如下:

class Point2D
{
public:
	//非virtual成员函数
public:
	//virtual函数
	virtual void drawpoint();
	
protected:
	float _x;
	float _y;
};

class Vertex : virtual public Point2D
{
public:
	//非virtual成员函数
public:
	//virtual函数
	virtual void drawpoint();
	
protected:
	Vertex* next;
};

class Point3D : virtual public Point2D
{
	public:
	//非virtual成员函数
public:
	//virtual函数
	virtual void drawpoint();
	
protected:
	float _z;
};
class Vertex3D : public Point3D, public Vertex
{
public:
	//非virtual成员函数
public:
	//virtual函数
	void drawpoint();
	void drawvertex();
	virtual void show();
	
private:
	float mumble;
};
根据以上定义,以及上面3中情况的分析,我们可以推断出Class Vertex3D的内存模型中应该是拥有 3个虚函数表指针,分别继承于Point3D和Vertex两个类,另外一个虚函数表指针是来自于共享部分,即Point 2D的虚函数表指针。





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值