您的位置:首页 > 编程语言 > C语言/C++

Data语意学 继承与Data Member

2015-10-28 23:55 323 查看

单继承

在没有多态的情况下比较简单,只是把基类堆叠到派生类上边,组成一个新的类。注意基类的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;




如下的操作:

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;
};




如何存取共享部分?

在每一个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;




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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++