C++之多层继承、多源继承、菱形继承

本文将通过三个经典示例程序,带你彻底理解:

  • 多层继承的访问规则

  • 多源继承的构造与析构顺序

  • 菱形继承中的二义性问题

一,多层继承

概念

多层继承指 一个类继承另一个派生类,形成继承链,例如:

复制代码
A → B → C

C 间接继承了 A 的成员。

示例代码:

cpp 复制代码
#include <iostream>
using namespace std;

class A
{
public:
    A() { cout << "A" << endl; }
    ~A() { cout << "~A" << endl; }
public:
    void fun_A_public() { cout << "fun_A_public" << endl; }
protected:
    void fun_A_protected() { cout << "fun_A_protected" << endl; }
private:
    void fun_A_private() { cout << "fun_A_private" << endl; }
};

class B : public A
{
public:
    B() { cout << "B" << endl; }
    ~B() { cout << "~B" << endl; }
public:
    void fun_B_public() { cout << "fun_B_public" << endl; }
protected:
    void fun_B_protected() { cout << "fun_B_protected" << endl; }
private:
    void fun_B_private() { cout << "fun_B_private" << endl; }
};

class C : public B
{
public:
    C() { cout << "C" << endl; }
    ~C() { cout << "~C" << endl; }
public:
    void fun_C_public() { cout << "fun_C_public" << endl; }
protected:
    void fun_C_protected() { cout << "fun_C_protected" << endl; }
private:
    void fun_C_private() { cout << "fun_C_private" << endl; }
};

int main()
{
    // 1. 在类外部通过类对象只能访问public成员
    // 2. 对基类成员的访问由继承方式和原访问权限共同决定
    //  (1)只有基类的public成员,以public形式继承,那么派生来的对象在类外部才可以访问
	//  (2)除此之外的情况,派生来的对象在类外部都无法访问
    C c;
    c.fun_A_public();
    c.fun_B_public();
    c.fun_C_public();

    return 0;
}
  1. 在类的内部,只能访问基类的public、protected成员,private无法访问
  2. 如果是多层继承的的话,那么子类对基类成员的访问,只看其直接父类中成员访问权限
  3. 父类成员在子类中存在的的访问权限,是由继承方式和原成员访问权限共同决定

理解方法:

  1. 如果看子类内部是否能访问,那么将继承关系的代码改为单继承来看。
  2. 如果看子类外部是否能访问,那么将继承关系的代码改为单个类来看
  3. 在改代码时,将父类中的代码复制到子类中,然后按照继承方式修改父类成员访问权限

运行结果:

结果分析

  1. 构造顺序: A → B → C

  2. 析构顺序: ~C → ~B → ~A

  3. 访问权限:

    • 类外部只能访问最终类对象中 public继承下来的public成员

    • 类内部可访问基类的 publicprotected,不能访问 private

二,多源继承

概念

多源继承(或称"多重继承")是指一个派生类从多个基类继承:

cpp 复制代码
class C : public A, public B

这种设计可以让子类同时拥有多个基类的功能,但也可能带来复杂性。

示例代码:

cpp 复制代码
#include <iostream>
using namespace std;

class A
{
public:
    A(int n) { cout << "A" << endl; }
    ~A() { cout << "~A" << endl; }
};

class B
{
public:
    B(int n) { cout << "B" << endl; }
    ~B() { cout << "~B" << endl; }
};

// 多源继承:构造顺序由继承列表顺序决定,而不是初始化列表顺序
class C : public A, public B
{
public:
    C(int n) : B(n), A(n)
    {
        cout << "C" << endl;
    }
    ~C() { cout << "~C" << endl; }
};

int main()
{
    C c(5);
    return 0;
}

输出结果:

结果分析

  1. 构造顺序

    由继承列表顺序决定:A → B → C

    即使初始化列表写成 B(n), A(n),也无效。

  2. 析构顺序

    与构造相反:~C → ~B → ~A

  3. 注意点

    • 构造顺序只与 类定义时的继承顺序 有关;

    • 初始化列表顺序不会改变这一点;

    • 若多个基类含有同名成员,会产生访问二义性。

三,菱形继承

概念

菱形继承是一种特殊的多重继承结构:

D 同时继承 BC,而 BC 又继承自 A

这会导致 D 中出现两个 A 子对象,从而引发 二义性问题

示例代码:

cpp 复制代码
#include <iostream>
using namespace std;

class A
{
public:
    A() { cout << "A" << endl; }
    ~A() { cout << "~A" << endl; }

    void fun_A() { cout << "fun_A" << endl; }
};

class B : public A
{
public:
    B() { cout << "B" << endl; }
    ~B() { cout << "~B" << endl; }

    void fun() { cout << "fun_B" << endl; }
};

class C : public A
{
public:
    C() { cout << "C" << endl; }
    ~C() { cout << "~C" << endl; }

    void fun() { cout << "fun_C" << endl; }
};

class D : public B, public C
{
public:
    D() { cout << "D" << endl; }
    ~D() { cout << "~D" << endl; }
};

int main()
{
    D d;
    d.B::fun_A();  // 明确指定作用域

    // d.fun_A(); // 错误:二义性,D 中存在两个 A 子对象
    cout << sizeof(D) << endl;

    return 0;
}

运行结果:

结果分析

  1. D 拥有 两个独立的 A 子对象(来自 B 和 C)。

  2. 调用 fun_A() 时会出现二义性错误 ,需指定作用域:d.B::fun_A()

  3. 内存中 D 的大小包含了两个 A 子对象的空间。

解决办法:虚继承

通过在 BC 中使用 虚继承 ,可以让 D 只保留一个共享的 A 子对象:

cpp 复制代码
class B : virtual public A { ... };
class C : virtual public A { ... };

此时 D 中只有一个 A 实例,二义性问题消失,内存占用也更小。

四、总结对比表

相关推荐
_wyt0018 分钟前
多重背包问题详解
c++·背包dp
段一凡-华北理工大学41 分钟前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
Ljwuhe1 小时前
C++——多态
开发语言·c++
越甲八千1 小时前
STL stack为何没有迭代器
c++
心平气和量大福大2 小时前
C#-WPF-Window主窗体
开发语言·c#·wpf
CV-Climber2 小时前
检索技术的实际应用
人工智能·算法
hhzz2 小时前
Tiger AI Platform平台中增加人脸识别功能
图像处理·人工智能·算法·计算机视觉·大模型
从零开始的代码生活_3 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法
云小逸3 小时前
【C++ 第七阶段:模板、泛型编程与工程综合详解】
开发语言·c++
TsingtaoAI3 小时前
3D高斯泼溅技术发展及其在具身智能领域的应用综述
人工智能·算法·ai·具身智能·高斯泼溅