C++基础系列【14】继承与多态
博主介绍:程序喵大人
- 35- 资深C/C++/Rust/Android/iOS客户端开发
- 10年大厂工作经验
- 嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手
- 《C++20高级编程》《C++23高级编程》等多本书籍著译者
- 更多原创精品文章,首发gzh,见文末
- 👇👇记得订阅专栏,以防走丢👇👇
😃C++基础系列专栏
😃C语言基础系列
本文主要介绍下多态的概念。
继承与抽象类
多态是面向对象的核心知识点,在C++中意味着调用对象成员函数时,会根据对象的真实类型来执行不同的函数,从而产生不同的行为。
- 比如同样是人,不同人的声音不相同。
- 比如同样是公司,不同公司的经营业务也不同。
这就可以就多态来解释。
那怎么实现多态,看这段代码,先定义一个People类:
class People {
public:
virtual void Speak() { std::cout << "People Speak \n"; }
};
注意这里面的函数使用了virtual修饰,用virtual修饰的函数表示虚函数,带虚函数的类可以称之为父类,有父类自然可以派生出子类,子类可以覆盖父类的行为。
这里再定义两个类,一个男人类,一个女人类
class MalePeople : public People {
public:
void Speak() { std::cout << "MalePeople Speak \n"; }
};class FemalePeople : public People {
public:
void Speak() { std::cout << "FemalePeople Speak \n"; }
};
在MalePeople和FemalePeople使用了冒号,表示继承,冒号后面的public表示继承的权限。
所以上面的代码的含义是:
MalePeople以public权限继承了People,并覆盖父类People的Speak行为。
FemalePeople以public权限继承了People,并覆盖父类People的Speak行为。
再看一段使用多态的代码:
int main() {People *p1 = new People();People *p2 = static_cast<People *>(new MalePeople());People *p3 = static_cast<People *>(new FemalePeople());p1->Speak(); // People Speakp2->Speak(); // MalePeople Speakp3->Speak(); // FemalePeople Speakdelete p3;delete p2;delete p1;
}
p1、p2、p3都是People的实例,但是通过他们的实例调用相同的函数却产生了不同的行为,这就是多态。
注意两点,想要实现上述的多态行为:
- 父类相应的函数一定要使用
virtual修饰 - 一定要父类的指针或引用指向子类对象
继承权限
共有三种继承权限:
public继承
- 父类中所有
public成员在子类中为public属性 - 父类中所有
protected成员在子类中为protected属性 - 父类中所有
private成员在子类中不可访问
protected继承
- 父类中所有
public成员在子类中为protected属性 - 父类中所有
protected成员在子类中为protected属性 - 父类中所有
private成员在子类中不可访问
private继承
- 父类中所有
public成员在子类中为private属性 - 父类中所有
protected成员在子类中为private属性 - 父类中所有
private成员在子类中不可访问
大体可以理解为:
- 父类成员在子类中的访问权限不会高于指定的继承权限。
- 父类中的
private成员在子类中使用不可访问。
然而平时开发过程中一般都会使用public继承,其他的继承方式很少。
纯虚函数
在C++中,还有个纯虚函数的概念,就是在virtual修饰的基础上加个=0,比如:
class People {
public:
virtual void Speak() = 0;
};
这里的Speak就是纯虚函数,含有纯虚函数的类叫抽象类,同时规定抽象类不允许被实例化,只能通过子类实例化,举例:
int main() {People *p1 = new People(); // compile errorPeople *p2 = static_cast<People *>(new MalePeople());People *p3 = static_cast<People *>(new FemalePeople());
}
多继承
就是子类继承了多个父类,比如一个男子篮球运动员,那就可以定义两个父类,一个MalePeople类,一个BasketballPlayer类,那如果想要定义男子篮球运动员类,可以定义一个MaleBasketballPlayer类,继承MalePeople和BaskeballPlayer,代码如下:
class MalePeople {
public:
void Speak() { std::cout << "MalePeople Speak \n"; }
};class BasketBallPlayer {
public:
void Play() { std::cout << "Play Basketball \n"; }
};class MaleBasketBallPlayer : public MalePeople, public BasketBallPlayer {};
和单继承方式差不多,只是用相同的语法在后面再派生多个即可。
虚继承

普通的继承就是非虚继承,如图, 非虚继承时,显然D会继承两次A,内部就会存储两份A的数据浪费空间,而且还有二义性,D调用A的方法时,由于有两个A,究竟时调用哪个A的方法呢,编译器也不知道,就会报错,所以有了虚继承,解决了空间浪费以及二义性问题。

在虚拟继承下,只有一个共享的基类子对象被继承,而无论该基类在派生层次中出现多少次。共享的基类子对象被称为虚基类。在虚继承下,基类子对象的复制及由此而引起的二义性都被消除了。
如何使用虚继承?
在继承的时候使用virtual关键字,代码如下:
struct Base {
virtual void Func() { printf("Base Func\n"); }
};struct BaseA : virtual public Base {
virtual void Func() { printf("BaseA Func\n"); }
};struct BaseB : virtual public Base {
virtual void Func() { printf("BaseB Func\n"); }
};struct Derive : public BaseB, public BaseA {
void Func() override { printf("Derive Func \n"); }
};
注意,为了易于观察,上面所有的父类都没有定义析构函数,正常父类的析构函数一定要设置成virtual。
练习
- 多态只有这一种方式吗?
- 为什么一定要通过指针或引用方式才能达到多态的目的?
- 为什么析构函数一定要设置成virtual?
- 构造函数可以为虚函数吗?
- 多态的原理是怎么样的?
- 不同继承方式下,类对象的布局是什么结构?
码字不易,欢迎大家点赞,关注,评论,谢谢!
C++训练营
专为校招、社招3年工作经验的同学打造的1V1 C++训练营,量身定制学习计划、每日代码review,简历优化,面试辅导,已帮助多名学员获得offer!训练营介绍
相关文章:
C++基础系列【14】继承与多态
博主介绍:程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章,首发gzh,见文末👇…...
DeepSeek-R1 大模型本地部署指南
文章目录 一、系统要求硬件要求软件环境 二、部署流程1. 环境准备2. 模型获取3. 推理代码配置4. 启动推理服务 三、优化方案1. 显存优化技术2. 性能加速方案 四、部署验证健康检查脚本预期输出特征 五、常见问题解决1. CUDA内存不足2. 分词器警告处理3. 多GPU部署 六、安全合规…...
在conda环境下,安装Pytorch和CUDA
系统 : Ubuntu20.04 显卡:NVIDIA GTX1650 显卡驱动已经装好(命令 nvidia-smi 查看显卡配置) (主要看一下第一行的参数,最大支持的CUDA版本为12.4 ) Aanconda 版本(安装指南)(似乎…...
Java里int和Integer的区别?
大家好,我是锋哥。今天分享关于【Java里int和Integer的区别?】面试题。希望对大家有帮助; Java里int和Integer的区别? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Java 中,int 和 Integer 都是用来表…...
【第13章:自监督学习与少样本学习—13.4 自监督学习与少样本学习的未来研究方向与挑战】
凌晨三点的实验室里,博士生小张盯着屏幕上的训练曲线——他设计的跨模态少样本学习模型在医疗影像诊断任务上突然出现了诡异的性能断崖。前一秒还在92%的准确率高位运行,下一秒就暴跌到47%。这个看似灾难性的现象,却意外揭开了自监督学习与少样本学习技术深藏的核心挑战… 一…...
【NLP】文本预处理
目录 一、文本处理的基本方法 1.1 分词 1.2 命名体实体识别 1.3 词性标注 二、文本张量的表示形式 2.1 one-hot编码 2.2 word2vec 模型 2.2.1 CBOW模式 2.2.2 skipgram模式 2.3 词嵌入word embedding 三、文本数据分析 3.1 标签数量分布 3.2 句子长度分布 3.3 词…...
deepseek r1从零搭建本地知识库10:嵌入模型和知识库建设
一、嵌入模型(Embedding Model)是什么? 1. 定义 嵌入模型是一种将文本、图像、音频等非结构化数据转化为**低维稠密向量(Dense Vector)**的算法模型,这些向量(通常几百到几千维)能够…...
Linux-文件IO
1.open函数 【1】基本概念和使用 #include <fcntl.h> int open(const char *pathname,int flags); int open(const char *pathname,int flags,mode_t mode); 功能: 打开或创建文件 参数: pathname //打开的文件名 f…...
3d pose 学习笔记2025
目录 champ nlf 3dpose 2025 55个关键点 推理代码: 要设置环境变量: 依赖项metrabs 渲染代码: tram4d 脚也不是特别好 GVHMR脚对不齐 推理代码: multiperson 2023年 genhmr还没开源: champ https://zhuanlan.zhihu.com/p/700326554 nlf 3dpose 2025 55个关键点…...
LC-随机链表的复制、排序链表、合并K个升序链表、LRU缓存
随机链表的复制 为了在 O(n) 时间复杂度内解决这个问题,并且使用 O(1) 的额外空间,可以利用以下技巧: 将新节点插入到原节点后面:我们可以将复制节点插入到原节点后面。例如,如果链表是 A -> B -> C,…...
静态页面在安卓端可以正常显示,但是在ios打开这个页面就需要刷新才能显示全图片
这个问题可能有几个原因导致,我来分析一下并给出解决方案: 首要问题是懒加载实现方式的兼容性问题。当前的懒加载实现可能在 iOS 上不够稳定。建议修改图片懒加载的实现方式: // 使用 Intersection Observer API 实现懒加载 function initLazyLoading() {const imageObserver…...
四元数如何用于 3D 旋转(代替欧拉角和旋转矩阵)【ESP32指向鼠标】
四元数如何用于 3D 旋转(代替欧拉角和旋转矩阵) 在三维空间中,物体的旋转可以用 欧拉角、旋转矩阵 或 四元数 来表示。 四元数相比于欧拉角和旋转矩阵有 计算更高效、避免万向锁、存储占用少 等优点,因此广泛用于 游戏开发、机器…...
JavaScript 内置对象-日期对象
在JavaScript中,处理日期和时间是一个常见的需求。无论是显示当前时间、计算两个日期之间的差异,还是格式化日期字符串,Date 对象都能提供强大的支持。本文将详细介绍 Date 对象的使用方法,包括创建日期实例、获取和设置日期值、以…...
本地大模型编程实战(19)RAG(Retrieval Augmented Generation,检索增强生成)(3)
文章目录 准备创建矢量数据库对象创建 LangGraph 链将检索步骤转化为工具定义节点构建图 见证效果qwen2.5llama3.1MFDoom/deepseek-r1-tool-calling:7b 总结代码参考 上一篇文章我们演练了一个 用 langgraph 实现的 RAG(Retrieval Augmented Generation,检索增强生成) 系统。本…...
DeepSeek与ChatGPT:AI语言模型的全面对决
DeepSeek与ChatGPT:AI语言模型的全面对决 引言:AI 语言模型的时代浪潮一、认识 DeepSeek 与 ChatGPT(一)DeepSeek:国产新星的崛起(二)ChatGPT:AI 界的开拓者 二、DeepSeek 与 ChatGP…...
2024年年终总结
2024年终于过去了,这绝对是我人生中最惨痛的一年!被小人欺骗、被庸人耽误、被自己蠢到!不由的让我想起了22年那次算命,算命先生说我十年低谷期,如果从15年进创业公司开始,24年是最后一年,果然应…...
利用 Valgrind 检测 C++ 内存泄露
Valgrind 是一款运行在 Linux 系统上的编程工具集,主要用于调试和分析程序的性能、内存使用等问题。其中最常用的工具是 Memcheck,它可以帮助检测 C 和 C 程序中的内存管理错误,如内存泄漏、使用未初始化的内存、越界访问等。 安装 这里我以…...
Python中的HTTP客户端库:httpx与request | python小知识
Python中的HTTP客户端库:httpx与request | python小知识 在Python中,发送HTTP请求和处理响应是网络编程的基础。requests和httpx是两个常用的HTTP库,它们都提供了简洁易用的API来发送HTTP请求。然而,httpx作为新一代的HTTP客户端…...
【Python】Python入门基础——环境搭建
学习Python,首先需要搭建一个本地开发环境,或是使用线上开发环境(各类练习网站),这里主要记录本地开发环境的配置。 目录: 一、下载和安装python解释器 官网下载地址:Download Python | Pytho…...
2025 pwn_A_childs_dream
文章目录 fc/sfc mesen下载和使用推荐 fc/sfc https://www.mesen.ca/docs/ mesen2安装,vscode安装zg 任天堂yyds w d 左右移动 u结束游戏 i崩溃或者卡死了 L暂停 D658地方有个flag 发现DEEE会使用他。且只有这个地方,maybe会输出flag,应…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
