第三章数据成员与继承及指向成员的指针
一、非多态继承
1.派生类中每个基类的子对象都要保持其完整性,即每个子对象都与独立对象内存布局相同,都会经过alignment(会造成代码膨胀)
class Concrete1{ public: //…… private: int val; char bit1; }; class Concrete2:public Concrete1{ public: //…… private: char bit2; }; class Concrete3:public Concrete2{ public: //…… private: char bit3; };
2.对象拷贝的内容根据指针类型决定,如下列代码只拷贝子对象Concrete1的内容(不论指针实际指向哪里)
Concrete1 *pc1_1,*pc1_2;
*pc1_2=*pc1_1;
二、多重继承
1.自然多态:类体系中基类和派生类的对象都是从相同地址开始,如上图所示。
2.多态地址转换:①多重继承中一般第一条继承链的对象是自然多态,基类指向派生类时只需简单赋值即可。
②多重继承中的其余继承链均不满足自然多态需要将指针进行转换。如下图,基类Vertex到最终派生类Vertex3d需要进行地址转换。并且当实现多态的是指针时还需要测试条件(测试是不是空指针,引用不需要,引用不能绑定到nullptr)
Vertex3d v3d; Vertex *pv; Point2d *p2d; Point3d *p3d; //第一继承链,直接拷贝地址 p2d=&v3d; p3d=&v3d; //引用 pv=&v3d; //转换为 pv=(Vertex*)(((char*)&v3d)+sizeof(Point3d)); //指针 Vertex3d *pv3d; pv=pv3d; //转化 pv=pv3d?(Vertex*)(((char*)&v3d)+sizeof(Point3d)) :0;
三、虚拟继承
1.传统虚拟继承模型:在每个派生类中添加一个指向基类子对象的指针
造成的问题①每一个对象针对每一个虚基类都要产生一个指针。(类对象的内存不固定随虚基类的数量变化)
②访问层次增加(如果有多层虚拟派生,则访问需要经过多次指向虚基类的指针)
2.现代虚拟继承模型:
(1)解决第二个问题:将指向虚基类的指针放入到所有派生类对象当中。(空间换时间)
(2)解决第一个问题:
①Microsoft引入虚基类表。类中增加一个指向虚基类表,表中存放真正的指向虚基类的指针。
②在虚函数表中放置虚基类的偏移offset。Sun编译器虚函数表中正值索引代表虚函数,负值索引代表虚基类的偏移。
四、指向成员的指针
1.形式: T Class::*x。其中T为类型,Class为类名,x为类Class的成员。
2.使用:object.*x 代表访问对象object的成员x
3.取类成员的地址:&Class::x 返回值为成员x在类对象中的偏移量offset
4.作用可以用来确定对象在内存中的排列顺序或者内存的布局 &Class::x > &Class::y 代表x排列在y之前(若x和y在同一访问域则代表y声明在x声明之前)
5.访问效率:未经过编译器优化时效率低于直接存取(多了一层指针的访问具有间接性)。