024 - C++ 虚函数

news2024/11/14 1:03:24

本期我们学习的是 C++ 中的虚函数。

过去的几期,我们一直在讨论类、面向对象编程、继承这些内容,所有的这些内容,包括本期我们将要学习的虚函数,对整个面向对象的概念都非常重要。

虚函数能干什么呢?

虚函数允许我们在子类中重写方法。

假设我们有两个类 A 和 B,B 是 A 派生出来的,也就是 B 是 A 的子类。如果我们在 A 中创建一个方法,标记为 virtual,我们可以选择在 B 类中重写那个方法,让它做其他的事情。

像之前一样,我们通过一个例子来解释今天的知识点。

例子时间

oq7Q8h.png

我创建了两个类,一个是 Entity ,它唯一拥有的是一个名为 GetName 的公共方法,它会返回一个字符串,我们让它返回 “Entity”。

还有另外一个类 Player,它是 Entity 类的子集,我们增加了这个类的内容,存储了一个名字,它提供一个构造函数,允许我们指定一个名字;然后给它提供了一个叫 GetName 的方法,在这种情况下,它会返回这个名字,它的名字就是成员变量。

我们来看看如何使用上面这些设定。

oq7zoc.png

我们在主函数中创造了一个 Entity,然后打印 GetName();再创建一个 Player,将这个 Player 命名为 “ganlan”,同样打印 Player 的名字。

我们可以不删除这些对象,因为程序终止后,它们自然就会被 delete 了,在这种情况下使用 delete 没什么用。

我们运行程序,结果看起来就是那样的,第一行 “Entity” ,第二行 “ganlan”。

然而,如果我们使用多态的概念,那么到目前为止我们在这里写的所有内容都有问题了。

如果我们指向一个 Player,却把它当作一个 Entity,就会遇到一些问题。

看看下面的操作。

oq7N2m.png

我们创建一个名为 entity 的变量,它的类型为 Entity,它被赋值为 p,p 是上面的一个指向 Player 的指针,是一个 Player 类型,现在我却把它指向了 Entity,然后打印它的名字,你觉的结果是什么样呢?

oq70X0.png

出乎意外。

我们希望它还是Player,因为即使我们指的是这个 Entity,但它实际上是一个 Player。

可能更合适的例子是这个。

oq7vY5.png

我有一个 PrintName 函数,参数是一个 Entity。

现在我们有了一个函数,它可以接受任何 Entity 类型的参数,你可以看到,我们不会得到任何的编译错误。

当我们试图将 p 传递给函数时,因为 p 是一个 Entity,Player 是 Entity,在函数里面我们做的就是调用 GetName 方法,我们期望的是,在主函数中调用的部分,参数为 Entity 类型时,GetName 用于 Entity,而参数为 Player 类型时,GetName 用于 Player。

然而,运行代码之后你会发现它打印了两次 Entity。

为什么会这样呢?

发生这种情况的原因时,在我们声明函数时,我们的方法通常在类内部起作用。然后当调用方法的时候,会调用属于该类型的方法。

我们看这个 PrintName 函数,它的参数是 Entity,这意味着当我们调用 GetName 函数时,如果是在 Entity 里面,那么它会从 Entity 类中找这个叫做 GetName 的函数。

就是这样。

然而,我们希望 C++ 能意识到一点:我在这里传递的 Entity 实际上是 Player,所以,请调用 Player 中的 GetName 函数。

这时候,虚函数就该出现了。

虚函数引入了一种叫做 Dynameic Dispatch(动态联编)的东西,它通常通过 V 表(虚函数表)来实现编译。

V 表就是一个表,它包含基类中所有虚函数的映射,这样我们可以在它运行时,将它们映射到正确的覆写(overwrite)函数。

简单起见,现在你只需要知道,如果你想覆写一个函数,必须将基类中的基函数标记为虚函数。

我们回到代码中继续看一下。

oq7UYb.png

我在基类 Entity 类中 GetName 函数前面使用了 virtual 这个关键字,这可以告诉编译器,——嘿,为这个函数生成 V 表吧,这样,如果它被重写了,你可以指向正确的函数。

我们运行代码试试看。

oq7KdK.png

我们得到了期望的结果。

现在,我们可以做的另一件事:使用在 C++11 引入的覆写函数标记的关键字 override。

oq78s1.png

这个不是必须的,无论有没有这个关键字,程序都会正常工作,但是我还是建议你这样做。因为首先这会让你的程序更具有可读性,阅读程序的时候我们可以知道这实际上是一个覆写的函数;它还可以帮助我们预防 Bug 的发生,比如拼写错误之类的,如果这个时候函数名称不小心写成小写了,我们就会得到一个错误,因为在基类中没有这样的函数可以覆写,或者如果我们试图覆写一个非虚函数,它也会给我们一个错误,这是可以帮助我们解决问题的方法。

最后的话

这就是虚函数的本质,但是很遗憾的一点是,虚函数并不是没有额外的开销的,有两种与虚函数相关的运行时成本。

首先,我们需要额外的内存来存储 V 表,这样我们就可以分配到正确的函数,包括基类中要有一个成员指针指向 V 表;其次,每次我们调用虚函数时,我们需要遍历这个表来确定要映射到哪个函数,这些是额外的性能损失。

由于这些成本,很多人不喜欢使用虚函数,但是我使用的过程中,没有遇到开销特别大的情况。就我个人而言,我经常使用它,可能在一些嵌入式平台上,CPU性能很差的时候需要避免使用虚函数。除此之外,我们真的不能说因为它影响性能而不去使用,因为它的影响真的很小,小到几乎可以忽略不计。

这就是虚函数,如果你有什么想法,欢迎在评论区交流,下期见。

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

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

相关文章

关于C语言的一些笔记

文章目录 May4,2023常量问题基本数据类型补码printf的字符格式控制关于异或、异或的理解赋值运算i和i的区别关系运算符 摘自加工于C技能树 May4,2023 常量问题 //定义常量 const float PI; PI 3.14; //false ,这种声明变量是错误的,常量声明之后就不能修改&…

树脂塞孔有哪些优缺点及应用?

树脂塞孔的概述 树脂塞孔就是利用导电或者非导电树脂,通过印刷,利用一切可能的方式,在机械通孔、机械盲埋孔等各种类型的孔内进行填充,实现塞孔的目的。 树脂塞孔的目的 1 树脂填充各种盲埋孔之后,利于层压的真空下…

关于使用Notion的board做工作安排这件事

关于使用Notion的board做工作安排这件事 Created: May 4, 2023 5:39 PM 壹 最近想用一个工具来实现平时工作的记录、跟踪、留痕以及年终的统计,之前尝试过幕布、微软的todo、手机自带的备忘录等工具,但是还是不能够完全满足需求。之前也用过一段时间的…

SPSS如何进行回归分析之案例实训?

文章目录 0.引言1.线性回归分析2.曲线回归分析3.非线性回归分析4.Logistic回归分析5.有序回归分析6.概率回归分析7.加权回归分析 0.引言 因科研等多场景需要进行绘图处理,笔者对SPSS进行了学习,本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上…

Redis 实战篇:巧用 Bitmap 实现亿级海量数据统计

目录 二值状态统计判断用户登陆态SETBIT 命令GETBIT 命令第一步,执行以下指令,表示用户已登录。第二步,检查该用户是否登陆,返回值 1 表示已登录。第三步,登出,将 offset 对应的 value 设置成 0。 用户每个…

【web】HTTP工作原理及应用

一、浏览器工作 浏览器输入网址后,从DNS服务器中查找对应的IP,并返回客户端浏览器,然后通过ip地址去访问服务器。(操作系统中host文件存了一些对应的IP地址,浏览器拿到域名会先从host文件中查找ip,如果找…

重工业生产VR虚拟现实数字化互动展示为后续招商引资打好基础和口碑

智慧工业厂区已经是当今城市规划和发展的重要焦点。华锐视点运用数字孪生,三维虚拟仿真和3D可视化打造的智慧园区管理平台,不仅提升了工业厂区吸引力,而且促进工业厂区可持续发展,给予了园区互联网先进技术发展的基础,…

Noah-MP陆面过程模型建模方法与站点、区域模拟实践技术

查看原文:Noah-MP陆面过程模型建模方法与站点、区域模拟实践技术 目标: 了解陆表过程的主要研究内容以及陆面模型在生态水文研究中的地位和作用;熟悉模型的发展历程,常见模型及各自特点;理解Noah-MP模型的原理&#…

[笔记]Windows使用OpenVpn构建虚拟局域网

文章目录 前言一、Windows Openvpn方案1.1 openvpn server windows端安装目录结构服务端安装复制服务端配置文件修改服务端配置文件配置8080允许通过防火墙启动服务端 1.2 openvpn client windows端安装复制服务端生成的配置文件到客户端的config启动客户端 二、连通测试三、常…

数字孪生可视化平台开发 打通现实与虚拟世界

大数据时代背景下,数字孪生技术被应用到智慧建设中,数字孪生是指在虚拟世界中1:1构建一个与现实世界的物体、场景和其他方面都完全相同的孪生景象。数字孪生可视化平台是一种基于虚拟现实技术的数字化模型,通过将真实世界中的物体或场景数字化…

Ubuntu---mysql出现ERROR1698(28000):Access denied for user root@localhost错误解决方法

查看mysql版本: 安装完成后,登录mysql的时候就出现了如下错误: 因为安装的过程中没让设置密码,可能密码为空,但无论如何都进不去mysql。 下面是处理过程: Step1:修改mysqld.cnf配置文件 在ubun…

ModuleNotFoundError: No module named ‘mmcv._ext‘

mmsegmentation使用pyinstaller打包出现问题 mmsegmentation是商汤开源的语义分割框架,里面包含了大量SOTA模型,十分适合从事语义分割工作的小白学习。 最近想将mmsegmentation打包成exe进行使用,但是遇到了一个问题,在打包的过…

server2012 安装mysql5.6.50.0 msi

1. 安装包下载(包括依赖插件) 下载地址 提取码:pb8z 2.安装依赖插件:NDP452-KB2901907-x86-x64-AllOS-ENU.exe 3. 开始安装mysql5.6 双击 mysql-installer-community-5.6.50.0 安装,接受用户许可协议。 选择安装类型: 1)Developer Defaul…

得物直播低延迟探索 | 得物技术

1.背景 直播的时效性保证了良好的用户体验,根据经验在交易环节,延迟越低转化效果也会越好。传统的直播延迟问题已经成为了一个不容忽视的问题,高延迟不仅破坏了用户的观看体验,也让主播难以实时获取到用户的反馈。为了进一步优化…

【计算机网络(二)】DNS协议

什么是DNS DNS(DOMAIN NAME SYSTEM)是一个域名系统,是万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串 DNS 工作流程 客户端发送域名解析请求到本地域名服务器 发…

ESP32(二):GPIO

一.创建例程 打开命令面板&#xff1a;ctrlshiftp&#xff0c;输入&#xff1a;esp-idf:example&#xff1b;选择hello_world工程&#xff0c;点击 Create project using example hello_world&#xff0c;选择保存工程&#xff1b;工具使用代码&#xff1a; #include <stdi…

关于软件卸载

卸载软件 想必大家以前都这样删过软件的吧&#xff1a;把桌面上的图标直接拉进垃圾站 然而想卸载也必然也是因为空间占满了吧 所以今天决定介绍几个卸载的方法和工具。 我也是第一次尝试&#xff0c;毕竟我要毕业了&#xff0c;某些软件我忍他们很久了 浅浅地尝试几个 &am…

压测工具Jmeter

腾讯下载地址&#xff1a;https://mirrors.cloud.tencent.com/apache/jmeter/ index of /apache/jmeter/binaries/xxx.zip 这是windows系统使用 index of /apache/jmeter/binaries/xxx.tgz 这是linux系统使用 安装需要java环境 进到解压文件的bin目录下&#xff0c;双击 jmeter…

【Zynq7010 ebaz4205矿渣变废为宝(此教程包含如何更改PL侧的电路,使得能够正常使用PL侧的资源)】

一、时钟 时钟部分的电路图如下图所示&#xff0c;如果想用PL侧的晶振的话&#xff0c;需要手动焊接一个50MHZ的晶振&#xff0c;并将R1372和L29用0欧姆电阻连通。也可以加上一坨锡连通。我使用的是订书器钉。将订书器钉截取一部分&#xff0c;可以很好的替代0欧姆电阻。 ​ 50…

CTFshow misc PNG隐写入门赛

目录 One PieNG 1 One PieNG 2 One PieNG 3 One PieNG 4 One PieNG 5 One PieNG 6 One PieNG 7 One PieNG 8 One PieNG 9 One PieNG 10 One PieNG 11 One PieNG 12 One PieNG 13 One PieNG 14 One PieNG 15 One PieNG 16 One PieNG 17 One PieNG 18 One Pie…