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 实例,二义性问题消失,内存占用也更小。

四、总结对比表

相关推荐
Full Stack Developme4 小时前
Python Redis 教程
开发语言·redis·python
立志成为大牛的小牛4 小时前
数据结构——十七、线索二叉树找前驱与后继(王道408)
数据结构·笔记·学习·程序人生·考研·算法
星空下的曙光4 小时前
Node.js crypto模块所有 API 详解 + 常用 API + 使用场景
算法·node.js·哈希算法
阳光雨滴4 小时前
使用wpf用户控件编程落石效果动画
c++·wpf
qq_4924484465 小时前
Jmeter设置负载阶梯式压测场景(详解教程)
开发语言·python·jmeter
小贾要学习5 小时前
【数据结构】C++实现红黑树
数据结构·c++
ID_180079054735 小时前
京东获取整站实时商品详情数据|商品标题|数据分析提取教程
java·开发语言
ajassi20005 小时前
开源 C++ QT QML 开发(十七)进程--LocalSocket
c++·qt·开源
StarPrayers.6 小时前
旅行商问题(TSP)(2)(heuristics.py)(TSP 的两种贪心启发式算法实现)
前端·人工智能·python·算法·pycharm·启发式算法