Data语意学 继承与Data Member

单继承

在没有多态的情况下比较简单,只是把基类堆叠到派生类上边,组成一个新的类。注意基类的alignment造成的调整边界产生的内存使用并不会消失。

class A{
public:
    char a;
};
class B: public A{   //B的大小是8
public:
    int c;
};

加上多态后需要在object中导入一个vptr,加入的vptr可以放在尾部(与C struct有较好的兼容性),也可放在开头。

多重继承

对于一个多重派生对象,第一个base class的地址与其地址相同(像单一继承那样)。第二个和以后的base class地址需要加上介于中间的base class的大小才能计算出。

//class声明
class Point2d{};
class Point3d:public Point2d{};
class Vertex{};
class Vertex3d: public Point3d,public Vertex{};
//object 声明
    Vertex3d v3d;
    Vertex *pv;
    Point2d *p2d;
    Point3d *p3d;

Data语意学 继承与Data Member_第1张图片
如下的操作:

pv = &v3d;
//需要被转化为
pv = (Vertex*)( ( (char*) &v3d) + sizeof(Point3d) );//先取出v3d的地址,在加上point3d的大小,得到Vertex地址

------------------------------

Vertex3d *pv3d;
pv = pv3d;//pv是Vertex*类型
需要转化为
pv = pv3d 
    ? (Vertex*)( ( (char*) &v3d) + sizeof(Point3d) ) 
    : 0 ;
//因为pv3d是一个指针,有可能为0,需要对这种情况做出处理,而上边&v3d不可能为空。

虚拟继承

Class内含有一个或多个virtual base class subobjects ,将会被分割成一个共享区域和一个不变区域。不变区域拥有固定的offset,可直接存取。共享区域表现的就是virtual base class subobject 。这部分数据的位置在每次派生操作时会变化,所以只能通过间接存取。

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  Point3d,public Vertex{
public:
    float mumble;
};

Data语意学 继承与Data Member_第2张图片
如何存取共享部分?
在每一个derived class object中安插指向virtual base class的指针,通过指针完成存取。例如:

void Point3d::operator+=(const Point3d &rhs){
    _x += rhs._x;
    _y += rhs._y;
    _z += rhs._z;
}
//会被转化为
_vbcPoint2d->_x += rhs._vbcPoint2d -> _x;
_vbcPoint2d->_y += rhs._vbcPoint2d -> _y;
_z += rhs._z;


----------


//而一个derived class和一个base class 的实例转化:
Point2d *p2d = pv3d;
//转化为
Point2d *p2d = pv3d? pv3d->_vbcPoint2d : 0;

这样做有两个缺点:
1.每个对象必须对每一个virtual base class 背负一个额外的指针。
2.如果虚拟继承串链加长,将会经过多次间接存取,降低效率。

第一个问题有2种解决方法:
①引入virtual base class table,编译器安插指针,在table中找到virtual base class的指针。
②在virtual function table中放置virtual base class 的offset,可由负值索引得到。参考<图1>
用第二种方法的话

  _x += rhs._x;
  _y += rhs._y;
  _z += rhs._z;
  //会被转化为:
  (this + _vptr_Point3d[-1]) -> _x += (&rhs + rhs._vptr_Point3d[-1]) -> x_;
   (this + _vptr_Point3d[-1]) -> _y += (&rhs + rhs._vptr_Point3d[-1]) -> _y;
   _z += rhs.z;

Data语意学 继承与Data Member_第3张图片

第二个问题的解决方案是以空间换时间,每个derived class object 拷贝取得所有的nested virtual base class 指针。如图2

你可能感兴趣的:(C++)