本文主要是介绍10、多重继承、钻石继承、虚继承,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
10、多重继承、钻石继承、虚继承
- 多重继承
- 多重继承的内存布局
- 多重继承的类型转换
- 名字冲突问题
- 名字冲突问题解决方法
- 钻石继承(菱形继承)
- 钻石继承问题
- 虚继承
- 虚继承实现原理
多重继承
多重继承的内存布局
一个类可以同时从多个基类继承实现代码
- 子类对象内部包含多个基类子对象
- 按照继承表的顺序依次被构造,析构的顺序则与构造严格相反
- 各个基类子对象按照从低地址到高地址排列
多重继承的类型转换
将子类对象的指针,隐式转换为它的某种基类类型指针,编译器会根据各个基类子对象在子类对象中的位置,进行适当的偏移计算。以保证指针的类型与其所指向目标对象的类型一致
反之,将任何一个基类类型的指针静态转换为子类类型,编译器同样会进行适当的偏移计算。
无论在哪个方向上,重解释类型转换(reinterpret_cast)都不进行任何偏移计算
引用的情况与指针类似,因为引用的本质就是指针
名字冲突问题
如果在子类的多个基类中,存在同名的标识符,那么任何试图通过子类对象,或在子类内部访问该名字的操作,都将引发歧义
名字冲突问题解决方法
- 子类隐藏该标识符
- 通过作用域限定操作符
::
显式指明所属基类
钻石继承(菱形继承)
一个子类继承自多个基类,而这些基类又源自共同的祖先这样的继承结构称为钻石继承(菱形继承)
钻石继承问题
公共基类子对象,在汇聚子类对象中,存在多个实例
虚继承
解决钻石继承的问题
- 在继承表中使用virtual关键字
- 虚继承可以保证
- (1)公共虚基类子对象在汇聚子类对象中仅存一份实例
- (2) 公共虚基类子对象被多个中间子类子对象所共享
虚继承实现原理
汇聚子类对象中的每个中间子类子对象都持有一个指针,通过该指针可以获取 中间子类子对象的首地址 到 公共虚基类子对象的首地址的 偏移量
// 虚继承 -- 钻石继承问题的解决方法
// (1)公共虚基类子对象在汇聚子类对象中仅存一份实例
// (2)公共虚基类子对象被对个中间子类对象所共享
#include <iostream>
using namespace std;
#pragma pack(1)
class A{ // 人类
public:int m_a; // 年龄
};
class X:virtual public A{ // 学生类
public:int m_x;void setAge(/* X* this */int age){this->m_a = age; // (1)this(2)X中间子类子对象(3)指针1(4)偏移量(5)this+偏移量(6)公共虚基类子对象(7)m_a}
};
class Y:virtual public A{ // 教师类
public:int m_y;int getAge(/* Y* this */){return this->m_a; // (1)this(2)Y中间子类子对象(3)指针2(4)偏移量(5)this+偏移量(6)公共虚基类子对象(7)m_a}
};
class Z:public X,public Y{ // 汇聚子类 助教类
public:int m_z;void foo(){m_a = 20;}
};int main( void ){Z z; // |X中间子类对象|Y中间子类对象|m_z|A公共基类子对象| --> |指针1 m_x|指针2 m_y|m_z|m_a|// |m_a m_x|m_a m_y|m_z|cout << "汇聚子类对象z的大小: " << sizeof(z) << endl; // 32z.setAge(35); // setAge(&z,35) --> 实参类型是Z*(子类类型指针)cout << z.getAge() << endl; // getAge(&z) --> 实参类型Z*(子类类型指针)return 0;
}
这篇关于10、多重继承、钻石继承、虚继承的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!