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成员。

    • 类内部可访问基类的 public 与 protected,不能访问 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 同时继承 B 和 C,而 B、C 又继承自 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 子对象的空间。

解决办法:虚继承

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

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

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

四、总结对比表

相关推荐
开开心心就好1 小时前
Windows视频播放器推荐,精简版体积更小
java·服务器·开发语言·eclipse·pdf·ocr·音视频
开开心心就好1 小时前
A3的PDF怎么切成A4?拖一下分割线就行
服务器·开发语言·python·算法·pdf·ocr·tornado
小黄人软件1 小时前
python 模块(Module)与包(Package)的区别,python xxx.py、python -m xxx 和 import xxx 三者的区别
开发语言·python
PHP实战开发录1 小时前
PHP中文文件名为什么乱码
开发语言·php
沫璃染墨1 小时前
从零入门计算机网络系列(五):UDP套接字编程实战——从核心API到客户端与服务器通信
linux·网络·c++·vscode·网络协议·udp
闻缺陷则喜何志丹1 小时前
详细设计说明书的内容要求
算法·测试·存储
阿里嘎多学长1 小时前
2026-10-13 GitHub 热点项目精选
开发语言·程序员·github·代码托管
和裕1 小时前
定制纸箱刀卡、平卡、隔档分别是什么?结构与适用场景区别全解析
大数据·运维·网络·人工智能·算法
巧克力味的桃子1 小时前
复杂网络能控性鲁棒性研究进展
开发语言·网络·php
普通人62 小时前
php处理百度编辑器有误html
开发语言·编辑器·html·php·1024程序员节