当前位置: 首页 > news >正文

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

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

  • 多层继承的访问规则

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

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

一,多层继承

概念

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

A → B → C

C 间接继承了 A 的成员。

示例代码:

#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

二,多源继承

概念

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

class C : public A, public B

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

示例代码:

#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 子对象,从而引发 二义性问题

示例代码:

#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 子对象:

class B : virtual public A { ... };
class C : virtual public A { ... };

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

四、总结对比表

 

http://www.dtcms.com/a/478293.html

相关文章:

  • 双目三维重建-1相机标定
  • GIT 提示 remote: HTTP Basic: Access denied
  • 建设门户网站都需要什么成都网站设计新闻
  • 徐州贾汪区建设局网站资兴市住房和城乡建设局网站
  • 黄江仿做网站企业管理系统多少钱
  • 机器学习-推荐系统(下)
  • 「机器学习笔记13」无监督学习全面解析:从聚类算法到Python实战
  • 计算机视觉(opencv)——基于MediaPipe与机器学习的手势识别系统
  • 建设网站的请示如何做漂亮的网站
  • 【C++ 学习】单词统计器:从 “代码乱炖” 到 “清晰可品” 的复习笔记
  • STL分解:从定义到实战
  • 自己写算法(九)网页数字动画函数——东方仙盟化神期
  • 郑州市科协网站小程序可以用手机网站吗
  • 创建一个 Vue3项目
  • 使用远程模拟器开发调试安卓APP
  • Java外功精要(3)——Spring配置文件和mybatis
  • 深圳网站建设服务商万创网为女足世界杯创建一个网站
  • Vmware Workstation虚拟机不能拖动复制文件到宿主机的Bug原因探究过程
  • 嵌入式Linux开发环境学习(一)
  • 三种解法(数组、栈、快慢指针)全面解析——力扣234.回文链表全解析
  • linux 系统压力测试工具stress使用
  • 铜川做网站电话西安模板网站建设
  • 基于单片机大棚浇水灌溉控制系统Proteus仿真(含全部资料)
  • SQL Server 2019实验 │ 数据库和表的创建、修改与删除
  • 服装制造企业痛点解决方案:EFISH-SBC-RK3588 预测性维护方案
  • 怎么利用自媒体做网站优化招聘网站制作公司
  • 每天五分钟深度学习:基于dropout(随机失活)解决神经网络过拟合
  • 自然语言处理(NLP)之分词
  • 双向数据绑定是什么
  • 全链路智能运维中的业务交易粒度资源消耗追踪技术