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++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性
- C++ Custom Control控件向父窗体发送对应的消息