C++ 中的继承
目录
前言
一、继承的概念及定义
二、基类和派生类对象赋值转换
三、继承中的作用域
四、派生类的默认成员函数
五、继承与友元
六、继承与静态成员
七、复杂的菱形继承及菱形虚拟继承
(一)单继承与多继承
(二)菱形继承
(三)菱形虚拟继承
八、继承的总结和反思
结语
前言
在C++ 编程世界里,继承是一项极为关键的特性,它为代码的复用和层次化设计提供了强大支持。掌握继承机制,对于编写高效、可维护的C++ 代码至关重要。今天,就让我们一起深入探究C++ 中的继承。
一、继承的概念及定义
继承是面向对象程序设计实现代码复用的重要手段。它允许我们在保持原有类特性的基础上进行扩展,产生新的类,即派生类。这体现了面向对象程序设计的层次结构,从简单到复杂逐步构建。
定义格式上,以 class Student : public Person 为例, Person 是基类(父类), Student 是派生类(子类) , public 是继承方式。继承方式有 public 、 protected 和 private 三种,不同继承方式会改变基类成员在派生类中的访问权限。
比如,基类的 public 成员在 public 继承下,在派生类中仍是 public 成员;但在 protected 继承下,就变为派生类的 protected 成员 。
二、基类和派生类对象赋值转换
派生类对象和基类对象之间存在特殊的赋值转换关系。派生类对象可以赋值给基类的对象、指针或引用,这就像把派生类中属于基类的那部分“切”出来进行赋值,形象地称为切片。例如:
Student sobj;Person pobj = sobj; Person* pp = &sobj; Person& rp = sobj;
然而,基类对象不能直接赋值给派生类对象。不过,基类的指针或引用可以通过强制类型转换赋值给派生类的指针或引用,但这种转换需要谨慎,若基类是多态类型,可借助 RTTI (运行时类型信息)的 dynamic_cast 来确保安全转换。
三、继承中的作用域
在继承体系中,基类和派生类都有各自独立的作用域。当子类和父类存在同名成员时,子类成员会屏蔽父类对同名成员的直接访问,这种现象称为隐藏(重定义) 。比如:
class Person {protected:int _num = 111; };class Student : public Person {protected:int _num = 999; public:void Print() {cout << "Person::_num: " << Person::_num << endl;cout << "Student::_num: " << _num << endl;}};
在 Student 类的 Print 函数中,通过 Person::_num 明确访问父类的 _num 成员,避免混淆。实际编程中,应尽量避免在继承体系里定义同名成员,以免造成代码理解和维护上的困难。
四、派生类的默认成员函数
当我们定义派生类时,即便没有显式编写,编译器也会自动生成一些默认成员函数,主要包括以下几个方面:
1. 构造函数:派生类的构造函数必须调用基类的构造函数来初始化基类的那部分成员。若基类没有默认构造函数,就需在派生类构造函数的初始化列表中显式调用合适的基类构造函数。
2. 拷贝构造函数:派生类的拷贝构造函数要调用基类的拷贝构造函数,完成基类成员的拷贝初始化。
3. 赋值运算符函数:派生类的 operator= 必须调用基类的 operator= 来完成基类成员的复制。
4. 析构函数:派生类的析构函数在被调用完成后,会自动调用基类的析构函数,以清理基类成员,确保对象资源的正确释放,遵循先派生类后基类的清理顺序。
五、继承与友元
友元关系在继承体系中是不能自动继承的。也就是说,基类的友元不能访问子类的私有和保护成员。
父亲的朋友不是你的朋友
你需要和他成为朋友才可以访问(见注释)
例如:
class Student;class Person {public:friend void Display(const Person& p, const Student& s);protected:string _name; };class Student : public Person {//public://friend void Display(const Person& p, const Student& s);protected:int _stunNum; };void Display(const Person& p, const Student& s) {cout << p._name << endl;cout << s._stunNum << endl;}
这里 Display 函数作为 Person 类的友元,能访问 Person 类的保护成员,但对于 Student 类,它并不具备天然访问其保护成员的权限。
六、继承与静态成员
若基类定义了 static 静态成员,那么在整个继承体系中,无论派生出多少个子类,都只会存在一个该静态成员的实例。例如:
class Person {public:Person() { ++_count; }public:static int _count; };int Person::_count = 0;class Student : public Person {};
Person 类中的 _count 静态成员,在 Student 类及其他派生类中都是共享的,可通过类名或对象来访问。
七、复杂的菱形继承及菱形虚拟继承
(一)单继承与多继承
单继承是指一个子类只有一个直接父类,关系简单明了。
而多继承则是一个子类有两个或以上直接父类,这种情况虽然增加了代码复用的灵活性,但也引入了一些复杂问题。
(二)菱形继承
菱形继承是多继承的一种特殊情况。以 class Assistant : public Student, public Teacher 为例, Student 和 Teacher 都继承自 Person ,这样 Assistant 中就会出现 Person 成员的两份拷贝,导致数据冗余和二义性问题。比如在访问 Assistant 对象中来自 Person 的成员时,编译器无法明确确定访问的是哪一个 Person 成员。
数据冗余和二义性: Assistant 中就会出现 Person 成员的两份拷贝
(三)菱形虚拟继承
为解决菱形继承的数据冗余和二义性问题,引入了虚拟继承。在 Student 和 Teacher 继承 Person 时使用虚拟继承(如 class Student : virtual public Person ),
就能确保在 Assistant 对象中只存在一份 Person 成员的拷贝。虚拟继承通过虚基表指针和虚基表来管理基类成员的存储和访问,有效解决了上述问题,但也增加了一定的实现复杂度。
原理图
示例代码
下图是菱形虚拟继承的内存对象成员模型:这里可以分析出D对象中将A放到的了对象组成的最下面,这个A同时属于B和C,那么B和C如何去找到公共的A呢?这里是通过了B和C的两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。
八、继承的总结和反思
继承在C++ 中是把双刃剑。它极大地促进了代码复用,构建了清晰的类层次结构,但也带来了一些问题。多继承衍生出的菱形继承和复杂的底层实现,让代码复杂度和维护难度上升,这也是许多其他面向对象语言(如Java)不采用多继承的原因。
在实际编程中,我们要谨慎选择继承和组合。继承是“is - a”关系,每个派生类对象都是一个基类对象;组合是“has - a”关系,一个类包含另一个类的对象。优先考虑对象组合,因为它耦合度低,代码维护性好,更符合“黑箱复用”原则;而继承适用于需要体现类之间层次关系,或实现多态的场景。
结语
C++ 的继承机制丰富而复杂,深入理解它的各个方面,从基本概念到复杂应用,能让我们在编程时更得心应手,编写出结构良好、高效且易于维护的代码。希望通过这篇博客,大家能对C++ 继承有更透彻的认识,在后续编程实践中灵活运用。
相关文章:
C++ 中的继承
目录 前言 一、继承的概念及定义 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 五、继承与友元 六、继承与静态成员 七、复杂的菱形继承及菱形虚拟继承 (一)单继承与多继承 (二)菱形继承 …...
【中间件】brpc_基础_用户态线程上下文
文章目录 context介绍1 简单介绍2 主要功能2.1 上下文结构定义2.2 上下文切换实现2.3 协程栈管理2.4 平台兼容性处理2.5 性能优化 3 关键代码逻辑示例3.1 上下文初始化 (bthread_make_fcontext)3.2 上下文切换 (bthread_jump_fcontext) 4 与 BRPC 其他模块的协作5 性能与稳定性…...
蟋蟀的叫声,大自然的温度计
夏夜草丛中,蟋蟀的鸣叫声此起彼伏。有趣的是,它们的叫声频率竟然与气温有关!根据图片中的公式: 气温 ( X 8 ) 5 9 \text{气温} \frac{(X 8) \times 5}{9} 气温9(X8)5 只需记录蟋蟀在 15 秒内的鸣叫次数( X X X…...
文献总结:TPAMI端到端自动驾驶综述——End-to-End Autonomous Driving: Challenges and Frontiers
端到端自动驾驶综述 1. 文章基本信息2. 背景介绍3. 端到端自动驾驶主要使用方法3. 1 模仿学习3.2 强化学习 4. 测试基准4.1 真实世界评估4.2 在线/闭环仿真测试4.3 离线/开环测试评价 5. 端到端自动驾驶面临的挑战5.1 多模态输入5.2 对视觉表征的依赖5.3 基于模型的强化学习的世…...
二极管反向恢复的定义和原理
二极管的反向恢复定义 二极管的反向恢复是指二极管从正向导通状态切换到反向阻断状态时,电流从正向变为负向并最终回到零所需的时间。具体过程如下: 正向导通:当二极管正向偏置时,电流可以顺利通过,此时二极管处于导…...
# 基于词袋模型(BoW)的猫狗图像分类实践
基于词袋模型(BoW)的猫狗图像分类实践 在计算机视觉领域,图像分类是一项基础且重要的任务。本文将介绍如何使用词袋模型(Bag of Words, BoW)结合支持向量机(SVM)实现猫狗图像分类。通过详细的代…...
Vscode+git笔记
1.U是untracked m是modify modified修改了的。 2.check out 查看观察 3 status changed 暂存区 4.fetch v 取来拿来 5.orangion 起源代表远程分支 git checkout就是可以理解为进入的意思。...
生成式 AI 的未来
在人类文明的长河中,技术革命始终是推动社会跃迁的核心引擎。从蒸汽机解放双手,到电力点亮黑夜,再到互联网编织全球神经网络,每一次技术浪潮都在重塑人类的生产方式与认知边界。而今天,生成式人工智能(Generative AI)正以一种前所未有的姿态登上历史舞台——它不再局限于…...
进程间通信(IPC)
进程间通信(IPC)是操作系统中非常重要且基础的概念,涉及到不同进程之间如何交换数据和同步操作。下面我会一个一个地详细讲解这几种常见的IPC方式:管道(包含匿名管道和有名管道)、消息队列、共享内存、信号量、Socket通信,内容尽量用通俗易懂的语言,并结合具体原理、优…...
C语言奇幻指南:宏、头文件与变量的秘密世界
🌟 C语言奇幻指南:宏、头文件与变量的秘密世界 🌟 一、写一个“比小”宏:三目运算符的魔法 目标:定义一个宏,返回两个参数中较小的值。 代码: #define MIN(a, b) ((a) < (b) ? (a) : (b))…...
【开源免费】二维码批量识别-未来之窗——C#-仙盟创梦IDE
二维码批量识别工具,借助先进图像识别技术,能快速准确读取大量二维码信息。适用于物流与供应链管理,如库存盘点和货物追踪;可用于资产管理,像固定资产盘点与设备巡检;还能助力数据收集与市场调研࿰…...
n8n工作流自动化平台的实操:解决中文乱码
解决问题: 通过ftp读取中文内容的文件,会存在乱码,如下图: 解决方案 1.详见《安装 iconv-lite》 2.在code节点,写如下代码: const iconv require(iconv-lite);const items $input.all(); items.forEa…...
MCP 探索:MCP 集成的相关网站 Smithery、PulseMCP 等
简简单单 Online zuozuo :本心、输入输出、结果 文章目录 MCP 探索:MCP 集成的相关网站 Smithery、PulseMCP 等前言一、MCP 集成基础二、利用热门资源平台集成三、集成常见 MCP 服务四、管理集成的 MCP 能力五、集成示例借鉴六、数据交互与安全管理MCP 探索:MCP 集成的相关网…...
linux的时间轮
时间轮:高效管理海量定时任务的利器 1. 引言:为什么需要时间轮? 在许多应用场景中,我们都需要管理大量的定时任务,例如: 网络连接的超时检测。分布式系统中的心跳检测。缓存条目的过期淘汰。需要延迟执行…...
《操作系统真象还原》第十二章(2)——进一步完善内核
文章目录 前言可变参数的原理实现系统调用write更新syscall.h更新syscall.c更新syscall-init.c 实现printf编写stdio.h编写stdio.c 第一次测试main.cmakefile结果截图 完善printf修改main.c 结语 前言 上部分链接:《操作系统真象还原》第十二章(1&#…...
MIT6.S081-lab8前置
MIT6.S081-lab8前置 注:本部分除了文件系统还包含了调度的内容。 调度 调度涉及到保存寄存器,恢复寄存器,就这一点而言,和我们的 trap 很像,但是实际上,我们实现并不是复用了 trap 的逻辑,我…...
Java从入门到精通 - Java语法
Java 语法 此笔记参考黑马教程,仅学习使用,如有侵权,联系必删 文章目录 Java 语法01 变量详解1. 变量里的数据在计算机中的存储原理1.1 二进制1.2 十进制转二进制的算法1.3 计算机中表示数据的最小单元总结1.4 字符在计算机中是如何存储的呢…...
【CF】Day50——Codeforces Round 960 (Div. 2) BCD
B. Array Craft 题目: 思路: 有点意思的构造 首先题目告诉我们 y < x,这是一个重要的条件 我们先来考虑简单情况,假如可以放0进去,那么我们只需要在 y ~ x 之间全放 1 ,其余都是 0 即可,但…...
MySQL 日期加减函数详解
MySQL 日期加减函数详解 1. DATE_ADD 函数 基本语法 DATE_ADD(date, INTERVAL expr unit)功能 在指定日期/时间上添加一个时间间隔 参数说明 date:要处理的日期/时间值(可以是DATE, DATETIME或TIMESTAMP类型)expr:要添加的间…...
NV189NV195美光固态闪存NV197NV199
NV189NV195美光固态闪存NV197NV199 在存储技术持续迭代的2025年,美光固态闪存NV189、NV195、NV197、NV199系列凭借其差异化的性能定位,正在重新定义数据存储的边界。本文将从技术参数、场景适配、行业价值等维度,为不同领域的专业人士提供深度…...
C语言-回调函数
回调函数 通过函数指针调用函数,而这个被调用的函数称为回调函数 回调函数是C语言中一种强大的机制,允许将函数作为参数传递给其他函数,从而在特定时机由后者调用。它的核心在于函数指针的使用 以下是回调函数的使用例子 先创建好一个函数…...
启发式算法-蚁群算法
蚁群算法是模拟蚂蚁觅食行为的仿生优化算法,原理是信息素的正反馈机制,蚂蚁通过释放信息素来引导同伴找到最短路径。把问题的元素抽象为多条路径,每次迭代时为每只蚂蚁构建一个解决方案,该解决方案对应一条完整的路径,…...
DeepSeek与MySQL:开启数据智能新时代
目录 一、引言:技术融合的力量二、DeepSeek 与 MySQL:技术基石2.1 DeepSeek 技术探秘2.2 MySQL 数据库深度解析 三、DeepSeek 与 MySQL 集成:从理论到实践3.1 集成原理剖析3.2 集成步骤详解 四、应用案例:实战中的价值体现4.1 电商…...
Modbus 通讯协议(超详细,简单易懂)
目录 一、协议中的寄存器定义 二、协议概述 三、使用串口的Modbus 报文帧 编辑 3.1、Modbus ASCII 模式 3.2、Modbus RTU 模式 3.3、功能码概要 3.4、Modbus 报文分析 四、什么是RS-485 RS-232? 一、协议中的寄存器定义 阅读 Modbus 协议时会发现它的概念别扭…...
单细胞测序试验设计赏析(一)
单细胞测序试验设计赏析(一) 单细胞测序试验设计中,单细胞测序技术通常会结合其它的技术来共同说明问题,或者结合年龄、性别等临床数据,进行分层分析说明问题以下以发表文章来进行一定的分析。 Single-cell RNA seque…...
ES6入门---第二单元 模块三:对象新增、
一:对象简洁语法: 1、变量简洁 <script>let name Strive;let age 18;let json {name, //name:name,age //age:age};console.log(json);</script> 2、函数简洁 let json {name, //name:name,age, //age:age/* showA:functi…...
多元随机变量协方差矩阵
主要记录多元随机变量数字特征相关内容。 关键词:多元统计分析 二元随机变量(X, Y) 说明:可以理解变量中的 X为身高、Y为体重 总体协方差 σ X Y c o v ( X , Y ) E [ ( X − μ X ) ( Y − μ Y ) ] E ( X Y ) − μ X μ Y \sigma_{XY}cov(X, Y)E[…...
计算机网络-同等学力计算机综合真题及答案
计算机网络-同等学力计算机综合真题及答案 (2003-2024) 2003 年网络 第二部分 计算机网络(共 30 分) (因大纲变动因此 2004 年真题仅附真题,不作解析。) 一、填空题(共 10 分&#…...
[案例二] 菜单条制作(Menuscript)与工具条制作(Toolbar)
最近五一正好毕业论文盲审,抽时间研究一下菜单条制作(Menuscript)与工具条制作(Toolbar)的制作,在NX二次开发中唐康林老师已经讲的很详细了,在这里只对视频中的内容进行总结,并且根据自己的想法进行补充。在里海博主的直播教学中发现一个很有趣的NX图标工具,本人大概做了一…...
bellard.org : QuickJS 如何使用 qjs 执行 js 脚本
参阅上一篇:Fabrice Bellard(个人网站:bellard.org)介绍 Fabrice Bellard(个人网站:bellard.org)是计算机领域最具影响力的程序员之一,其贡献跨越多个技术领域并持续推动开…...
计组复习笔记 3
前言 继续做例题。昨天做到第一个就把我难住了。可恶。 4.1 地址码越长,操作码越短。因为两者加起来是指令字,指令字的大小一般是固定的。扩展编码按照操作码从短到长进行编码。算了先放一下。我先看一下别的复习资料。等会儿再看这个题。 鼓励自己 …...
GCD 深入解析:从使用到底层实现
前言 Grand Central Dispatch (GCD) 是 Apple 基于 C 语言开发的一套完整的并发编程框架。它不仅仅是一个简单的线程管理工具,而是一个高度优化的并发编程解决方案。GCD 的设计理念是将并发编程的复杂性封装在框架内部,为开发者提供简单易用的接口。本文…...
JavaScript中的AES加密与解密:原理、代码与实战
前言 关于有js加密、js解密,js业务相关,找jsjiami官网站长v。 另外前段时间做了个单子跑单了,出售TEMU助手。eller点kuajingmaihuo点com的全自动化助手,可以批量合规,批量实拍图,批量资质上传等。 一、A…...
计算机组成原理实验(7) 堆指令部件模块实验
实验七 堆指令部件模块实验 一、实验目的 1、掌握指令部件的组成方式。 2、熟悉指令寄存器的打入操作,PC计数器的设置和加1操作,理解跳转指令的实现过程。 二、实验要求 按照实验步骤完成实验项目,掌握数据打入指令寄存器IR1、PC计数器的…...
Windows系统下Node.js环境部署指南:使用nvm管理多版本
Windows系统下Node.js环境部署指南:使用nvm管理多版本 一、Node.js介绍二、为什么需要nvm?三、安装前的准备工作1. 本次环境说明2. 卸载现有Node.js(如有) 三、nvm-windows安装步骤1. 下载安装包2. 安装过程3. 验证安装 四、使用n…...
数据结构*队列
队列 什么是队列 是一种线性的数据结构,和栈不同,队列遵循“先进先出”的原则。如下图所示: 在集合框架中我们可以看到LinkedList类继承了Queue类(队列)。 普通队列(Queue) Queue中的方法 …...
C语言蓝桥杯真题代码
以下是不同届蓝桥杯C语言真题代码示例,供参考: 第十三届蓝桥杯省赛 C语言大学B组 真题:卡片 题目:小蓝有很多数字卡片,每张卡片上都是数字1-9。他想拼出1到n的数列,每张卡片只能用一次,求最大的…...
Sharding-JDBC分库分表中的热点数据分布不均匀问题及解决方案
引言 在现代分布式应用中,使用Sharding-JDBC进行数据库的分库分表是提高系统性能和扩展性的常见策略。然而,在实际应用中,某些特定的数据(如最新订单、热门商品等)可能会成为“热点”,导致这些部分的数据处…...
Dagster中的Ops与Assets:数据管道构建的两种选择
Dagster是一个强大的数据编排平台,它提供了多种工具来帮助数据工程师构建可靠的数据管道。在Dagster中,Ops和Assets是两种核心概念,用于定义数据处理逻辑。本文将全面介绍Ops的概念、特性及其使用方法,特别补充了Op上下文和Op工厂…...
thonny提示自动补全功能
THONNY IDE 自动补全功能配置 在 Thonny IDE 中启用和优化自动补全功能可以显著提升编程体验。为了确保该功能正常工作,需要确认几个设置选项。 配置自动补全 Thonyy IDE 的自动补全默认情况下是开启的。如果发现自动补全未按预期运行,可以通过调整首选…...
PyTorch_阿达玛积
阿达玛积指的是矩阵对应位置的元素相乘,可以使用乘号运算符,也可以使用mul函数来完成计算。 代码 import torch import numpy as np # 1. 使用 mul 函数 def test01():data1 torch.tensor([[1, 2], [3, 4]])data2 torch.tensor([[5, 6], [7, 8]])dat…...
蓝桥杯 摆动序列
摆动序列 原题目链接 题目描述 如果一个序列的奇数项都比前一项大,偶数项都比前一项小,则称为一个摆动序列。 即对于任意整数 i(i ≥ 1)满足: a₂ᵢ < a₂ᵢ₋₁,a₂ᵢ₊₁ > a₂ᵢ 小明想知道&…...
AI 与生物技术的融合:开启精准医疗的新纪元
在科技飞速发展的今天,人工智能(AI)与生物技术的融合正在成为推动医疗领域变革的重要力量。精准医疗作为现代医学的重要发展方向,旨在通过深入了解个体的基因信息、生理特征和生活方式,为患者提供个性化的治疗方案。AI…...
三、shell脚本--运算符与表达式:让脚本学会“思考”
一、算术运算符:加减乘除取模 在我们写shell脚本时,做点基本的数学运算还是经常需要的。常用的算术运算符跟我们平时学的一样: : 加- : 减* : 乘 (小提示:有时候在某些命令里可能需要写成 \*)/ : 除 (在 Shell 里通常是取整数部分…...
c++ 指针参数传递的深层原理
指针参数传递的深层原理 理解为什么可以修改指针指向的内容但不能直接修改指针本身,需要深入理解指针在内存中的表示方式和函数参数传递机制。 1. 指针的内存表示 指针本质上是一个变量,它存储的是另一个变量的内存地址。在内存中: 假设有…...
【查看.ipynp 文件】
目录 如何打开 .ipynb 文件? 如果确实是 .ipynp 文件: .ipynp 并不是常见的 Jupyter Notebook 文件格式。通常,Jupyter Notebook 文件的扩展名是 .ipynb(即 Interactive Python Notebook)。如果你遇到的是 .ipynb 文…...
C++ 简单工厂模式详解
简单工厂模式(Simple Factory Pattern)是最简单的工厂模式,它不属于GoF 23种设计模式,但它是工厂方法模式和抽象工厂模式的基础。 概念解析 简单工厂模式的核心思想是: 将对象的创建逻辑集中在一个工厂类中 客户端不…...
ubuntu使用apt安装软件
1、使用apt list |grep jdk查看要安装的软件 此处以jdk为例 2、执行名称:安装指定版本的软件 sudo apt install openjdk-11-jdk...
TFT(薄膜晶体管)和LCD(液晶显示器)区别
TFT(薄膜晶体管)和LCD(液晶显示器)是显示技术中常见的术语,二者既有联系又有区别。以下是它们的核心区别和关系: 1. 基本概念 LCD(液晶显示器) LCD是一种利用液晶材料特性控制光线通…...
【文献阅读】中国湿地随着保护和修复的反弹
一、研究背景 滨海湿地是全球最具生态价值的生态系统之一,广泛分布在河口、潮间带、泻湖和盐沼等地带,在调节气候、水质净化、生物栖息以及防止海岸侵蚀等方面发挥着关键作用。然而,近年来滨海湿地正面临严峻威胁,全球估计约有50%…...