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

 

posted @ 2025-05-07 20:20  靖意风  Views(18)  Comments(0)    收藏  举报