【C++ | 抽象类】纯虚函数 和 抽象基类,为什么需要抽象基类
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 抽象基类 和 纯虚函数 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰:
本文未经允许,不得转发!!!
目录
- 🎄一、概述
- 🎄二、纯虚函数
- 🎄三、抽象基类
- 🎄四、为什么需要抽象类
- 🎄五、总结
🎄一、概述
在生活中,有时会使用到比较抽象的词语,例如下面这个场景:
A:帮我把那个“东西”拿过来。
B:你是说,桌面的那个杯子吗?
A:是的。
这个场景中的“东西”就属于抽象的词语。而在C++编程中,有时也会出现这样抽象的语法。例如,我们可能会定义一个“动物”基类,但代码中不会定义一个“动物”的实例,而是将“动物”基类派生出“狗”、“猫”等派生类,再使用派生类去实例化。
本文主要介绍下面几个内容:
1、什么是纯虚函数?
2、什么是抽象基类?
3、为什么需要抽象基类?
🎄二、纯虚函数
上篇文章:【C++ | 虚函数】虚函数详解 及 例子代码演示(包含虚函数使用、动态绑定、虚函数表、虚表指针),我们详细地介绍了虚函数以及C++怎样实现虚函数的,但有一个也是很重要的知识点没在上篇文章介绍,这个知识点就是 纯虚函数。
纯虚函数:本质上也是虚函数,在虚函数的函数原型的分号前加上=0
就可以将一个虚函数说明为纯虚函数。
下面代码声明了一个虚函数 eat:
virtual void eat() =0;
纯虚函数的特点:
1、纯虚函数声明就是在函数原型分号前加=0
;
2、纯虚函数允许只有声明,没有定义(实现);
3、纯虚函数可以没有定义,也可以有定义,但纯虚函数的定义只能在类外。
4、只有虚函数可以加=0
,非虚函数加=0
会编译报错:error: initializer specified for non-virtual method
🌰举例子
// g++ 24_pure_virtual.cpp
#include <iostream>
using namespace std;class CAnimal{
public:// 1、纯虚函数声明就是在函数原型分号前加`=0`// 2、纯虚函数允许只有声明,没有定义(实现);virtual void eat() =0; virtual void run() =0;
};// 3、纯虚函数的定义只能在类外。
inline void CAnimal::run()
{cout << "Animal run" << endl;
}int main ()
{}
🎄三、抽象基类
抽象基类:英文名称是abstract base class
,缩写为ABC
。抽象基类是包含了至少一个纯虚函数
的基类,在代码中只能用来做基类,不能用来实例化对象。
抽象基类虽然不能实例化对象,但可以定义抽象基类的指针或引用,以此来管理其派生类对象。
抽象基类的特点:
1、抽象基类至少有一个纯虚函数;
2、抽象基类不能创建对象;
3、抽象基类要求派生类必须重写纯虚函数,以此来规范派生类的接口(函数);
4、派生类必须重写抽象基类中的所有纯虚函数
,否则也是抽象类,无法实例化对象。
5、抽象基类的纯虚函数一般没有定义,即使有定义也没法创建对象去调用。
🌰举例子
// g++ 24_pure_virtual2.cpp
#include <iostream>
using namespace std;class CAnimal{
public:virtual void eat() =0; // 纯虚函数,本类是抽象基类virtual void run() =0;
};class CCat : public CAnimal{
public:// 没有重写基类的所有纯虚函数,本类是抽象类virtual void eat(){cout << "cat eat" << endl;}
};class CDog : public CAnimal{
public:// 重写基类的所有纯虚函数,本类不是抽象类virtual void eat(){cout << "dog eat" << endl;}virtual void run(){cout << "dog run" << endl;}
};// 纯虚函数的定义只能在类外。
inline void CAnimal::run()
{cout << "Animal run" << endl;
}int main ()
{//CAnimal animal; // 报错:error: cannot declare variable ‘animal’ to be of abstract type ‘CAnimal’//CCat cat; // 报错:error: cannot declare variable ‘cat’ to be of abstract type ‘CCat’CDog dog;CAnimal *pAnimal = &dog;pAnimal->run();pAnimal->CAnimal::run(); // 指定调用基类的run
}
运行结果:
🎄四、为什么需要抽象类
之前一直在想,很多代码明明使用普通类也可以,为什么需要定义抽象类呢?
需要定义抽象基类的几个原因:
- 1、将接口与实现分离。接口是软件产品最有价值的资源,设计接口比实现接口需要耗费更昂贵的成本。因此,要将接口保护起来,以免在针对客户需求修改实现的时候,程序员不小心把接口破坏掉。
我们将一些必要的接口(函数)定义在抽象类,要求派生类必须按照这个格式去重写,如果不重写就休想创建对象。也就是说,抽象类将具体实现延迟到子类中,提供代码重用性和一定程度的设计约束。 - 2、避免某些基类被实例化是不合理的。例如“形状”这个基类,被实例化之后反而会让人相当费解,所以干脆将“形状”这个类定义为抽象类,由它派生出正方形,三角形等子类。
- 3、提示作用,当我们看到抽象基类就会知道其派生类一定会重写纯虚函数,而且也会去找抽象类的指针或引用,看看是否实现多态。其次,看到抽象类也知道它不会定义对象,也就不会去代码里找抽象类的对象了。
🎄五、总结
本文介绍了C++的纯虚函数、抽象基类,以及怎样使用它们,最后介绍了需要抽象基类的原因。
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
参考:
《C++ primer》
《C++ primer plus》
C++为什么要定义抽象基类?
为什么需要抽象类和接口?
为什么使用抽象类?有什么好处?
相关文章:

【C++ | 抽象类】纯虚函数 和 抽象基类,为什么需要抽象基类
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
DP(7) | 打家劫舍① | Java | LeetCode 198, 213, 337 做题总结(未完)
打家劫舍问题 来源于代码随想录:https://programmercarl.com/0198.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8D.html#%E6%80%9D%E8%B7%AF ① 确定dp数组(dp table)以及下标的含义 dp[i]:考虑下标i(包括i)以内的房…...

人工智能算法工程师(中级)课程17-模型的量化与部署之剪枝技巧与代码详解
大家好,我是微学AI,今天给大家介绍一下人工智能算法工程师(中级)课程17-模型的量化与部署之剪枝技巧与代码详解。模型剪枝是深度学习领域中一项关键的技术,旨在减少神经网络中的冗余权重,从而降低计算成本和内存占用,同…...
JavaScript 实例:掌握编程技巧
JavaScript 实例:掌握编程技巧 JavaScript 是一种广泛使用的编程语言,它为网页添加交互性,是现代网络开发的重要组成部分。本文将通过一系列实例,帮助您更好地理解和掌握 JavaScript 的核心概念和编程技巧。 基础实例:变量和数据类型 首先,让我们从最基础的开始。Java…...

自己做小项目时,配置的Maven需要用阿里云私服加速Jar包的下载
在我的IDEA中,maven配置在了这个地址,然后我需要去这个地址下找到settings.xml的maven配置文件来配置以下的阿里云私服地址来加速jar包的下载!【不然就是下N年很慢!】...
Linux笔记之time命令测量命令的执行时间
Linux笔记之time命令测量命令的执行时间 在Linux中,time命令用于测量命令的执行时间。这对于分析和优化脚本或程序的性能非常有用。time命令会显示三个主要时间指标: real: 从命令开始到结束的实际时间(也称为挂钟时间)。user: …...

《基于 CDC、Spark Streaming、Kafka 实现患者指标采集》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...
重要的单元测试
👽System.out.println(“👋🏼嗨,大家好,我是代码不会敲的小符,目前工作于上海某电商服务公司…”); 📚System.out.println(“🎈如果文章中有错误的地方,恳请大家指正&…...
什么是diff算法?
Diff算法,全称为Difference算法,是一种用于比较和查找两个对象(如文本、源代码、数据结构或任何形式的字符串)之间差异的算法。它在多个领域有着广泛的应用,包括但不限于前端开发、版本控制系统、协同编辑工具等。以下…...

BUUCTF逆向wp [MRCTF2020]Transform
第一步 查壳。该题为64位。 第二步 进入主函数,跟进dword_40F040,它应该与关键字符串有关 分析一下: 初始化和输入 sub_402230(argc, argv, envp); 这行可能是一个初始化函数,用于设置程序环境或处理命令行参数。具体功能不明,…...
前端下载文件流 出现乱码 解决方案
1. 后端返回文件格式不是 utf-8 解决方案:后端加 2. 若添加 utf-8 后依旧乱码 请求配置中添加 responseType: arraybuffer, export function downMode() {return http.request({url: baseUrl downTemplate,method: get,responseType: arraybuffer,}); }下载 con…...

Linux/Windows 系统分区
1. Windows 系统 1.1 系统分区 系统分区也叫做磁盘分区,即分盘; 举个例子,好比家里有一个大柜子,把衣服,鞋子,袜子都放在里面,由于没有隔断,找的时候非常麻烦,找是能找…...

C/C++ xml库
文章目录 一、介绍1.1 xml 介绍1.2 xml 标准1.3 xml 教程1.4 xml 构成 二、C/C xml 库选型2.1 选型范围2.2 RapidXML2.3 tinyxml22.4 pugixml2.5 libxml 五、性能比较5.1 C xml 相关的操作有哪些5.2 rapidxml、Pugixml、TinyXML2 文件读取性能比较 六、其他问题6.1 version和 e…...

UniVue@v1.5.0版本发布:里程碑版本
前言 以后使用UniVue都推荐使用1.5.0以后的版本,这个版本之后,更新的速度将会放缓。 希望这个框架能够切实的帮助大家更好的开发游戏,做出一款好游戏!本开源项目采用的开源协议为MIT协议,完全开源化,以后也…...

在 Windows 上开发.NET MAUI 应用_2.生成你的第一个应用
先决条件 Visual Studio 2022 17.8 或更高版本,并安装了 .NET Multi-platform App UI 工作负载。 可参考上一篇文章:http://t.csdnimg.cn/n38Yy 创建应用 1.启动 Visual Studio 2022。 在开始窗口中,单击“创建新项目”以创建新项目&#…...

配置SMTP服务器的要点是什么?有哪些限制?
配置SMTP服务器安全性如何保障?如何高效配置服务器? SMTP作为电子邮件发送的核心协议,其配置对于确保邮件的成功传递和安全至关重要。AokSend将详细介绍配置SMTP服务器的关键要点,帮助读者建立一个高效、安全的邮件发送系统。 配…...
图形渲染基础-Unity渲染管线介绍
Unity中的渲染管线渲染场景主要分为三个阶段 剔除(Culling) 剔除摄像机不可见对象(视锥体剔除Frustum Culling)和被遮挡对象(遮挡剔除Occlusion Culling)。 渲染(Rendering) 将可见…...
junit mockito service
service类单元测试可以有两种方式 1、使用Autowired启用上下文的Bean走业务逻辑,适用于debug调试 2、使用InjectMocks不启用上下文依懒的Bean采用打桩的形式 打桩注意:service通常业务逻辑复杂,Bean的依懒层次可能很深,初用者常…...
k8s学习——升级后的k8s使用私有harbor仓库
升级后的k8s使用了第三方的容器管理器,安装了nerdctl工具来替代docker进行镜像管理。但是使用docker build打包并上传至harbor仓库的镜像,在部署过程中始终拉不下来,报错证书错误。通过journalctl -xe |grep kubelet 或 journalctl -xe |grep…...

Blender4.2版本正式上线,新版本的5个主要功能!
Blender刚刚推出了备受瞩目的 Blender 4.2 版本,这款软件专为那些在视觉特效、动画制作、游戏开发和可视化设计领域工作的艺术家们量身打造。作为最新的长期稳定更新,Blender 4.2 不仅稳定可靠,还引入了备受期待的“Eevee Next”实时渲染引…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...