025 - C++ 接口(纯虚函数)

news2024/11/19 12:35:16

上一期我们学习了虚函数,本期我们学习一种特殊的虚函数,纯虚函数。

C++ 纯虚函数本质上与其他语言中的抽象方法或接口相同,基本上,纯虚函数允许我们在基类中定义一个没有实现的函数,然后强制子类去实现该函数。

我们可以看一下之前关于虚函数的例子。

oqK315.png

你可以看到在 Entity 类中有一个虚函数 GetName,然后我们在 Player 类中重写了那个函数,在基类中,这个 GetName 函数有函数体,意味着在某个类中重写它只是一个可选项,即使不重写它,仍然是可以调用它的。

然而在某些情况下,提供这种默认实现是没有意义的,实际上我们可能想要强制子类为特定的函数提供自己的定义。

在面向对象编程中,创建一个类,只由未实现的方法组成,然后强制子类去实现它们的操作非常常见,这种类通常被称为接口。

因此,类中的接口只包含未实现的方法作为模板,由于这个接口实际上并不包含方法实现,我们实际上不可能实例化那个类。

纯虚函数

让我们来看看这个在 Entity 类中的 GetName 函数能不能搞成纯虚函数。

oqgf9T.png

在上面的代码中,我们依然是将 GetName 函数定义为虚函数,但等于0使它成为一个纯虚函数,这意味着它必须在一个子类中实现,如果你想实例化这个子类的话,确实需要做出一些改变。

首先,我们看一下 main 函数,可以看到现在不具有实例化 Entity 类的能力,我们必须给它一个子类来实现这个函数。

使用 Player 类。

oqgYxr.png

你可以看到 Player 类是可以正常工作的。

这只是因为我们在 Player 类中实现了那个 GetName 函数,你可以试试注释掉 Player 中的 GetName 函数,你会发现 Player 也不能进行实例化了。

本质上,你只能在实现了所有这些纯虚函数之后,才能够实例化,或者在更上层次的类中完成。比如,Player 类是另一个类(Entity 的子类)的子类,而这个类实现了 GetName 函数,那也是可以的。

纯虚函数必须被实现,才能创建这个类的实例。

让我们来看另外一个更好的例子。

oqgk0c.png

我们编写一个函数来打印这些类的类名,保证 obj 有GetClassName 函数。现在我们需要一个类型,可以提供 GetClassName 函数,这就是所谓的接口。

我们把问号的位置叫做 Printable,然后设置它。

oqgg4h.png

在上面,我们创建一个新类,叫 Printable,它只有这些内容,它会创建一个 public virtual 字符串函数,返回一个字符串,这个函数是纯虚函数。然后让 Entity 实现那个接口。

注意 Player 现在已经是一个 Entity 了,所以我们不需要实现 Printable 接口了。

还有就是,我虽然把 Printable 叫做接口 interface,但它其实只是一个类,所以还是叫 class 而 不是叫做 interface,因为它只不过有一个纯虚函数,仅此而已。

实际上,其他语言有 interface 关键字而不是叫做 class,C++ 是没有的,接口只是 C++ 的类而已。

现在所有的类都需要实现这个 GetClassName 函数了。

让我们继续在 Entity 类中添加一个 GetClassName 函数,

oqkCGD.png

我们无法实现实例化的问题已经解决了, 现在已经提供了那个功能。

然而,你可能会注意到,我们还没有为 Player 提供一个覆写函数,如果现在调用函数 Print 并运行,你可以看到打印了两次 Entity,因为我们还没有在 Player 中提供定义。

oqgybb.png

我们直接复制具体的代码并做一些修改,再次运行。

oqk5Io.png

可以看到,现在我们得到了正确的类名,所有的这些都来自一个 Print 函数。这个函数接受 Printable 作为参数,它并不关心具体是什么类。

比如,我们可以创建一个完全不同的类,比如 A,它是一个 Printable 类的子类,它必须有相应的函数。

oqguaK.png

我现在创建了一个全新的类,并且实现了 Printable 这个接口,即实现了这个函数,像之前那样调用打印,你会看到结果是正常的。

oqghk1.png

注意:这样的写法不推荐哈,容易造成内存泄露,不过作为测试是没有问题的。

最后的话

这就是纯虚函数整个的工作原理,它知道任何 Printable 的东西,它们都有一个 GetClassName 函数去调用,如果你不实现这个函数,你就不能实例化这个类。

这就是 C++ 中的接口,也就是 C++ 中的纯虚函数,它是非常有用的一个工具,可以被用在刚才的这个场景下,如果想要确保类都有一个特定的方法,那么可以将这个类作为参数放入一个通用的函数中,然后就可以调用这个方法或者做其他事情。

本期内容就是这些,下期再见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/492206.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uni-app获取手机号

登录微信公众平台拿到自己的AppID(小程序ID)和AppSecret(小程序密钥) 微信公众平台 1.获取手机号首先要先登录拿到code,用code去获取session_key 2.获取 code需要知道自己的AppID(小程序ID)和AppSecret(小程序密钥) 3.解密 uni.login({success: (loginRes) > {…

提取Windows中系统自带的图标资源

写应用程序,如果想使用Windows下的图标,可以使用Visual Studio中的图标,比如VS2008的ImageLibrary(笔者已经打包上传到CSDN),也可以使用Windows系统自带的图标。 Windows系统自带了不少高质量的图标资源&a…

2019临沂中考数学解析

一、选择 考点: 绝对值:数轴上某个数与原点的距离叫做这个数的绝对值。 其中距离一定是非负的,即大于等于0 考点: 两直线平行,同位角相等邻补角: 指两条直线相交后所得的有一个公共顶点且有一条公共边的两…

一篇SEO指南:新手如何从零开始优化自己的网站

在如今的数字时代,拥有一个优化良好的网站对于任何企业或个人来说都是至关重要的。但是,对于SEO新手来说,如何从零开始优化自己的网站可能是一项看似艰巨的任务。在本文中,我们将为您提供一份SEO指南,帮助您了解从零开…

C++之STL顺序容器

目录 一、STL容器简介 二、顺序容器 一、STL容器简介 STL容器是一个通用的数据结构,可以处理不同数据类型,包含基本的数据结构如链表、堆栈、队列等。可以分为顺序容器、关联容器、 容器适配器、特殊容器。本篇博客将简要介绍一下STL容器中的顺序容器…

Mysql 学习(八)单表查询方法 一

单表访问方法 前面几节我们了解 innodb 的底层数据结构的设计,究其本源我们其实是为了更好的理解如何查询,并且如何使得查询语句更加快速的问题,这节我们就来好好讲一讲首先我们先来创建一个表 CREATE TABLE index_value_table (id INT NOT…

Redis --- 哨兵、分片集群

一、Redis哨兵 Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。 1.1、哨兵原理 集群结构和作用 哨兵的结构如图: 哨兵的作用如下: 监控:Sentinel 会不断检查您的master和slave是否按预期工作 自动故障…

mysql 排名与排序

MySQL 8.0 版本新增 两个排名函数 分别是 ROW_NUMBER() 与 RANK() 用法 SELECT ROW_NUMBER() OVER(ORDER BY id) AS rowNo, name FROM users; SELECT RANK() OVER(ORDER BY score DESC) AS rankNo, name, score FROM students;后面跟 OVER()括号里…

惠普星 TP01-055ccn电脑重装系统步骤

如果你的惠普星 TP01-055ccn电脑出现了系统问题,或者你想更换一个全新的微软操作系统,自己有不清楚相关的重装系统步骤怎么办?别担心,你可以参考以下的惠普星 TP01-055ccn电脑重装系统步骤来执行。 ​ 惠普星 TP01-055ccn电脑怎…

第1章 .Net7 Areas实现

1 集成路由匹配模式 var builder WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); var app builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { …

【LeetCode】376. 摆动序列

376. 摆动序列 思路 首先,我们可以将摆动序列分为两种: 「上升摆动序列」,当且仅当该序列是摆动序列,且最后一个元素呈上升趋势。如序列 [1,3,2,4] 即为「上升摆动序列」。 「下降摆动序列」,当且仅当该序列是摆动序…

深度解读:《数字孪生世界白皮书(2023)》全方位剖析

2023年初,中国信息通信研究院发布了《数字孪生城市产业图谱研究报告(2022)》,报告中提出我国数字孪生产业四阶段体系,2020年到2030年是我国数字孪生产业增长期,当前数字孪生市场需求和技术均处于高速发展阶…

腹部肿瘤内科专家朱利明:化疗也能“订制”,晚期结直肠癌不再“无药可救”

肠癌是发生在结肠和直肠的癌症,近二三十年来发病率快速上升。就在近期,“日本女大胃王菅原初代患肠癌病逝”的消息登上热搜,一时引发网友关注热议。 “人生有哲学三问:我是谁?我从哪里来?我到哪里去&#x…

window下sql-server备份后,拷贝到centos上

一.window下sql-server management 打开本地数据库,点备份 二.拷贝到centos下对应目录 mkdir -p /var/opt/mssql/backup 三.在 Linux 上还原数据库 下列步骤使用 sqlcmd 工具。 如果尚未安装 SQL Server 工具,请按照以下步骤安装: ●(1)用…

DJ5-3/4 中断处理程序和设备驱动程序

目录 5.3 中断机构和中断处理程序 5.3.1 中断简介 5.3.2 中断处理程序 5.4 设备驱动程序 5.4.1 设备驱动程序概述 5.4.2 设备驱动程序的处理过程 5.4.3 对 I/O 设备的控制方式 5.3 中断机构和中断处理程序 5.3.1 中断简介 1、中断和陷入 -- CPU 外部事件和内…

基于C++的通讯管理系统

1、系统需求 通讯录是一个可以记录亲人、好友信息的工具。本教程主要利用C来实现-个通讯录管理系统 系统中需要实现的功能如下: ●添加联系人:向通讯录中添加新人,信息包括(姓名、性别、年龄、联系电话、家庭住址)最多记录1000人 ●显示联系人:显示通讯录中所有联系…

手把手教你搭建ROS阿克曼转向小车之(增量式PID代码实现)

在上一篇文章中我们已经成功的把编码器的反馈值给计算出来,这篇文章将会讲解怎么使用反馈回来的速度值进行PID计算,从而闭环控制电机的速度。 PID算法介绍 1.开环控制系统 开环控制系统(open-loop control system)是指被控对象的输出(被控制量)对控制器…

【软件开发】从单机到分布式

从单机到分布式 1.单台服务器应用 问题:由于流量越来越大出现服务器性能问题。 2.应用服务器和数据库服务器分离 对架构增加了一台服务器,应用和数据库分别部署到不同的服务器上,对于开发和测试没有任何影响,只需要应用服务器新…

画了个 MSP430F149的最小系统板 开源出来了

使用MSP430F149单片机设计的一个最小系统板,包含晶振电路、复位电路、CH340串口和BSL下载电路、按键和LED电路等,使用了Type-C接口作为供电和串口通信,另外引出了JTAG接口,所有IO口都引出了。 板载了3个按键和LED,可以…

项目范围说明书如何编写?

范围说明书是一份定义了项目范围的所有要素以及假设、项目要求和验收标准的文件。项目范围说明书将作为主要工具,供利益相关者和团队成员参考,并作为准确衡量项目成功的准则。 项目范围说明书是范围管理计划的一部分,包含了管理项目范围的所…