继承与数据成员布局

派生类对象内存:自己的非静态数据成员+基类的数据成员,

           二者顺序并未强制规定。大部分编译器:基类成员先出现(虚基类除外)

1》非继承,对象布局

      继承与数据成员布局_第1张图片

1》仅单一继承,无多态时,对象布局

派生类对象成员布局:

1)  首先是基类成员

2)派生类成员

       继承与数据成员布局_第2张图片

3》继承+多态时,对象布局

虚函数额外的负担:

虚函数增加:

1,类中,存放虚函数地址的虚表;

2,每个对象,插入虚指针vptr,指向相应的虚表,提供执行期的链接

3,加强构造函数,,构造函数设定vptr的初值,使其指向类对应的虚表(可能在派生类,基类中的构造函数中都重新设置vptr)

4,加强析构函数,析构函数摸消指向类的相关的虚表的vptr

vptr的位置讨论:

1.C++早期,类对象尾端 

2.c++有了多重继承,虚继承后,类的首端,

    继承与数据成员布局_第3张图片
注:以下以虚指针放在基类的尾端为例。

1)单一继承并含虚函数

     继承与数据成员布局_第4张图片

上图看出:对于单一继承,

基类,派生类的对象的相同点:从相同的地址开始

差别:在于派生类对象比较大。

point3d p3d;

point2d*p=&p3d;

派生类对象指定给基类的指针或引用,不需要编译器调整地址。

2)多重继承(含虚函数)

  继承与数据成员布局_第5张图片
 对象布局如下:
     继承与数据成员布局_第6张图片
  说明:  

1,对多重派生类对象,将其地址指定给最左端的基类的指针,情况和单一继承相同,因为二者指向相同的地址。

2,对于第二个或后继的基类的地址指定操作,需要修改地址:加减中间基类对象

3)虚拟继承(含虚函数)

类含一个或多个虚基类时,可分割为:不变局部和共享局部

不变局部的数据:总有固定的偏移量(对象起始地址开始),直接存取

共享局部:    virtual基类部分,位置因为派生操作而变化,只可以间接存取

各家编译器的不同在于间接存取方法的不同.

下面均以此继承体系为例:

     继承与数据成员布局_第7张图片

一般策略:先安排好派生类的不变部分,在建立共享部分

对于如何存取共享部分(第二个问题):

cfront编译器(包括今天的编译器):在每一个派生类中安插一些指针,指向virtual基类,来获取virtual基类成员。如下图所示:

     继承与数据成员布局_第8张图片

对于如何安排好派生类的不变部分(第一个问题),2个解决方法:

1.  microsoft编译器引入virtual基类表,每个类对象若有virtual base class,编译器安插一个指针指向virtualbase class table。

2.  在virtual 函数表中放置虚基类的offset。如下图所示:

       继承与数据成员布局_第9张图片

以上参考自《inside C++ object model》


       

 


   


你可能感兴趣的:(继承与数据成员布局)