3.3 多重继承
1> 多重继承的内存布局
– 子类对象中的多个基类子对象,按照继承表的顺序依次被构造,析构的顺序则与构造严格相反,各个基类子对象按照从低地址到高地址排列
#include <iostream> using namespace std; class A { public: A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } int m_a; }; class B { public: B() { cout << "B()" << endl; } ~B() { cout << "~B()" << endl; } int m_b; }; class C { public: int m_c; C() { cout << "C()" << endl; } ~C() { cout << "~C()" << endl; } }; class D : public A, public B, public C { // 汇聚子类 public: D() { //【A();】 //【B();】 //【C();】 //【int m_d;】 cout << "D()" << endl; } ~D() { cout << "~D()" << endl; // ~C() // ~B() // ~A() // .... } int m_d; }; // 以上代码模拟类的设计者(c++标准类/第三方类/自己设计的类...) // ----------------------------------------------------------- // 以下代码模拟类的使用者(用户) int main( void ) { D d; // |A基类子对象|B基类子对象|C基类子对象|m_d|--->|m_a|m_b|m_c|m_d| cout << "汇聚子类对象d的大小:" << sizeof(d) << endl; // 16 D* pd = &d; cout << "整个汇聚子类对象首地址 D* pd: " << pd << endl; cout << "A基类子对象首地址: " << &d.m_a << endl; cout << "B基类子对象首地址: " << &d.m_b << endl; cout << "C基类子对象首地址: " << &d.m_c << endl; cout << "D类自己的成员&m_d: " << &d.m_d << endl; return 0; } // d.~D();
执行结果: $./a.out A() B() C() D() 汇聚子类对象d的大小:16 整个汇聚子类对象首地址 D* pd: 0x7fff153e2c10 A基类子对象首地址: 0x7fff153e2c10 B基类子对象首地址: 0x7fff153e2c14 C基类子对象首地址: 0x7fff153e2c18 D类自己的成员&m_d: 0x7fff153e2c1c ~D() ~C() ~B() ~A()
2> 多重继承的类型转换
– 将多重继承的子类对象的指针,隐式转换为它的基类类型,编译器会根据各个基类子对象在子类对象中的内存位置,进行适当的偏移计算。
以保证指针的类型与其所指向目标对象的类型一致
– 反之,将任何一个基类类型的指针静态转换为子类类型,编译器同样会进行适当的偏移计算
– 无论在哪个方向上,重解释类型转换(reinterpret_cast)都不进行任何偏移计算
// 多重继承的 类型转换 #include <iostream> using namespace std; class A { public: int m_a; }; class B { public: int m_b; }; class C { public: int m_c; }; class D : public A, public B, public C { // 汇聚子类 public: int m_d; }; // 以上代码模拟类的设计者(c++标准类/第三方类/自己设计的类...) // ----------------------------------------------------------- // 以下代码模拟类的使用者(用户) int main( void ) { D d; // |A基类子对象|B基类子对象|C基类子对象|m_d|--->|m_a|m_b|m_c|m_d| cout << "汇聚子类对象d的大小:" << sizeof(d) << endl; // 16 D* pd = &d; cout << "整个汇聚子类对象首地址 D* pd: " << pd << endl; cout << "A基类子对象首地址: " << &d.m_a << endl; cout << "B基类子对象首地址: " << &d.m_b << endl; cout << "C基类子对象首地址: " << &d.m_c << endl; cout << "D类自己的成员&m_d: " << &d.m_d << endl; cout << "-------------隐式转换-----------------" << endl; A* pa = pd; cout << "D* pd--->A* pa:" << pa << endl; B* pb = pd; cout << "D* pd--->B* pb:" << pb << endl; C* pc = pd; cout << "D* pd--->C* pc:" << pc << endl; cout << "-------------static_cast-----------------" << endl; D* p1 = static_cast<D*>(pa); cout << "A* pa--->D* p1:" << p1 << endl; D* p2 = static_cast<D*>(pb); cout << "B* pb--->D* p2:" << p2 << endl; D* p3 = static_cast<D*>(pc); cout << "C* pc--->D* p3:" << p3 << endl; cout << "-------------reinterpret_cast-----------------" << endl; pa = reinterpret_cast<A*>(pd); cout << "D* pd--->A* pa:" << pa << endl; pb = reinterpret_cast<B*>(pd); cout << "D* pd--->B* pb:" << pb << endl; pc = reinterpret_cast<C*>(pd); cout << "D* pd--->C* pc:" << pc << endl; return 0; } // d.~D();
执行结果: $./a.out 汇聚子类对象d的大小:16 整个汇聚子类对象首地址 D* pd: 0x7fff24830cd0 A基类子对象首地址: 0x7fff24830cd0 B基类子对象首地址: 0x7fff24830cd4 C基类子对象首地址: 0x7fff24830cd8 D类自己的成员&m_d: 0x7fff24830cdc -------------隐式转换----------------- D* pd--->A* pa:0x7fff24830cd0 D* pd--->B* pb:0x7fff24830cd4 D* pd--->C* pc:0x7fff24830cd8 -------------static_cast----------------- A* pa--->D* p1:0x7fff24830cd0 B* pb--->D* p2:0x7fff24830cd0 C* pc--->D* p3:0x7fff24830cd0 -------------reinterpret_cast----------------- D* pd--->A* pa:0x7fff24830cd0 D* pd--->B* pb:0x7fff24830cd0 D* pd--->C* pc:0x7fff24830cd0
3> 名字冲突问题
– 如果在子类的多个基类中,存在同名的标识符,那么任何试图通过子类对象,或在子类内部访问该名字的操作,都将引发歧义。
– 解决方法: 通过作用域限定操作符“::”显式指明所属基类; 另外的方法就是 子类定义同名标识符, 隐藏基类的该标识符
// 多重继承的 名字冲突的问题 #include <iostream> using namespace std; class A { // 老师类 public: int m_a; int m_c; // 工资 }; class B { // 学生类 public: int m_b; int m_c; // 成绩 }; class D : public A, public B { // 助教类 public: int m_d; // int m_c; // 在业务上毫无意义, 仅仅就是将基类的m_c隐藏 void foo() { A::m_c = 8000; // } }; // 以上代码模拟类的设计者(c++标准类/第三方类/自己设计的类...) // ----------------------------------------------------------- // 以下代码模拟类的使用者(用户) int main( void ) { D d; // |A基类子对象|B基类子对象|m_d| --> |m_a m_c|m_b m_c|m_d| cout << "汇聚子类对象d的大小:" << sizeof(d) << endl; // 20 d.B::m_c = 100; // return 0; }
执行结果: $./a.out 汇聚子类对象d的大小:20

浙公网安备 33010602011771号