调用基类的纯虚函数,如何知道纯虚函数会调用哪个派生类(子类)中的实现。
在 C++ 中,调用基类的纯虚函数实际上是通过运行时多态性来决定调用哪一个派生类的实现。这种机制是通过虚函数表(vtable)和虚函数指针(vptr)实现的。下面我们来详细探讨一下这个过程。
虚函数表和虚函数指针
-
虚函数表(vtable):
- 每个包含虚函数的类(包括纯虚函数)都会有一个虚函数表。虚函数表是一个指针数组,每个指针指向类的虚函数的具体实现。
- 虚函数表是编译器在编译时生成的,并且对于同一个类的所有对象是共享的。
-
虚函数指针(vptr):
- 每个对象有一个指向其类的虚函数表的指针,称为虚函数指针(vptr)。
- 当一个对象被创建时,其 vptr 被初始化为指向该对象所属类的虚函数表。
当调用一个虚函数时,程序会通过对象的 vptr 找到相应的 vtable,并在 vtable 中找到该函数的地址,然后进行调用。这种机制允许程序在运行时根据对象的实际类型调用适当的函数实现,这就是多态性。
调用纯虚函数的过程
假设你有一个基类 Base 和几个派生类 Derived1 和 Derived2,基类 Base 定义了一个纯虚函数 doSomething。以下是如何知道调用哪个派生类实现的步骤:
对于 obj2->doSomething(),类似的过程会发生,但它的 vptr 指向 Derived2 的 vtable,最终调用 Derived2 中 doSomething 的实现。
运行时确定派生类的实现
这是因为 C++ 的多态性允许基类指针(或引用)指向派生类对象。调用虚函数时,实际调用的函数实现是通过对象的动态类型(即它真正的派生类类型)来确定的。这种类型是在运行时决定的,而不是编译时。
代码示例
下面是一个完整的代码示例,展示了上述过程:
-
定义类和函数:
class Base { public:virtual void doSomething() = 0; // 纯虚函数 };class Derived1 : public Base { public:void doSomething() override {std::cout << "Derived1 implementation" << std::endl;} };class Derived2 : public Base { public:void doSomething() override {std::cout << "Derived2 implementation" << std::endl;} }; -
实例化派生类对象:
Base* obj1 = new Derived1(); Base* obj2 = new Derived2(); -
调用虚函数:
obj1->doSomething(); // 调用 Derived1 的实现 obj2->doSomething(); // 调用 Derived2 的实现
决定调用哪个派生类实现的过程
当你调用 obj1->doSomething() 时,以下过程发生:
-
查找 vptr:
obj1是指向Derived1对象的基类指针。- 程序通过
obj1找到它的 vptr,该 vptr 指向Derived1的 vtable。
-
查找 vtable:
- 程序查找
Derived1的 vtable,这个表包含doSomething的地址。
- 程序查找
-
调用函数:
- 程序通过 vtable 获取
doSomething的地址,然后调用这个地址处的函数,即Derived1中doSomething的实现。
- 程序通过 vtable 获取
对于 obj2->doSomething(),类似的过程会发生,但它的 vptr 指向 Derived2 的 vtable,最终调用 Derived2 中 doSomething 的实现。
运行时确定派生类的实现
这是因为 C++ 的多态性允许基类指针(或引用)指向派生类对象。调用虚函数时,实际调用的函数实现是通过对象的动态类型(即它真正的派生类类型)来确定的。这种类型是在运行时决定的,而不是编译时。
代码示例
下面是一个完整的代码示例,展示了上述过程:
#include <iostream>class Base {
public:virtual void doSomething() = 0; // 纯虚函数
};class Derived1 : public Base {
public:void doSomething() override {std::cout << "Derived1 implementation" << std::endl;}
};class Derived2 : public Base {
public:void doSomething() override {std::cout << "Derived2 implementation" << std::endl;}
};int main() {Base* obj1 = new Derived1();Base* obj2 = new Derived2();obj1->doSomething(); // 输出: Derived1 implementationobj2->doSomething(); // 输出: Derived2 implementationdelete obj1;delete obj2;return 0;
}
在这个示例中,通过基类指针调用 doSomething 时,程序根据实际的派生类类型调用相应的实现,这展示了 C++ 中的运行时多态性。
通过调试查看
如果你使用调试器(如 gdb),你可以在调用虚函数前设置断点,并逐步查看调用过程。你会看到程序通过 vptr 查找 vtable,然后调用适当的函数实现。这是验证多态行为的一个好方法。
总结
- vptr 和 vtable: vptr 指向对象的 vtable,通过它们在运行时决定调用哪个派生类的实现。
- 多态性: 基类指针或引用调用虚函数时,实际调用的是派生类的实现,这通过动态绑定实现。
- 调试和分析: 使用调试器可以更深入地观察这种运行时行为。
相关文章:
调用基类的纯虚函数,如何知道纯虚函数会调用哪个派生类(子类)中的实现。
在 C 中,调用基类的纯虚函数实际上是通过运行时多态性来决定调用哪一个派生类的实现。这种机制是通过虚函数表(vtable)和虚函数指针(vptr)实现的。下面我们来详细探讨一下这个过程。 虚函数表和虚函数指针 虚函数表&a…...
塑造卓越企业家IP:多维度视角下的策略解析
在构建和塑造企业家IP的过程中,我们需要从多个维度进行考量,以确保个人品牌能够全面、立体地展现企业家的独特魅力和价值。以下是从不同角度探讨如何做好一个企业家IP的策略。 一、从个人特质出发 深入了解自我:企业家需要清晰地认识到自己的…...
Rust 跨平台-Android 和鸿蒙 OS
1. 安装 rustup rustup 是 Rust 的安装和版本管理工具 $ curl --proto https --tlsv1.2 https://sh.rustup.rs -sSf | sh 该命令会安装 rusup 和最新的稳定版本的 Rust;包括: rustc Rust 编译器,用于将 Rust 代码编译成可执行文件或库。 ca…...
Typora导出为Word
文章目录 一、场景二、安装1、网址2、解压并验证 三、配置四、重启Typora 一、场景 在使用Typora软件编辑文档时,我们可能需要将其导出为Word格式文件 当然我们可以直接在菜单里进行导出操作 文件-> 导出-> Word(.docx) 如果是第一次导出word文件࿰…...
数据库被后台爆破如何解决?
在数字化时代,数据库安全成为企业与组织不容忽视的关键环节。其中,“后台爆破”攻击,即通过自动化工具尝试大量的用户名和密码组合,以非法获取数据库访问权限,是常见的安全威胁之一。本文将详细介绍如何识别、防御并解…...
php7.4源码安装dbase7.1.1扩展
安装PHP开发工具 首先,你需要安装PHP开发工具,包括php-devel(或php7.4-devel,取决于你的PHP版本)和其他编译工具。 bash sudo yum install php7.4-devel gcc make 注意:如果你使用的是不同的PHP版本&#…...
OkHttp的源码解读1
介绍 OkHttp 是 Square 公司开源的一款高效的 HTTP 客户端,用于与服务器进行 HTTP 请求和响应。它具有高效的连接池、透明的 GZIP 压缩和响应缓存等功能,是 Android 开发中广泛使用的网络库。 本文将详细解读 OkHttp 的源码,包括其主要组件…...
08:结构体
结构体 1、为什么需要结构体2、如何定义结构体3、怎么使用结构体变量3.1、赋值和初始化3.2、结构体变量的输出 1、为什么需要结构体 为了表示一些复杂的事物,而普通的基本类型无法满足实际要求。什么叫结构体 把一些基本类型数据组合在一起形成的一个新的数据类型&…...
喜讯!安全狗荣获“2023年网络安全技术支撑优秀单位”称号
6月6日,由中共厦门市委网络安全和信息化委员会办公室(以下简称“厦门市委网信办”)主办的2023年网络安全技术支撑优秀单位颁奖仪式在厦门成功举行。 作为国内云原生安全领导厂商,安全狗受邀出席此次活动。 会上,安全狗…...
android里面json操作
1.读取assets下面xzhd/aikit/pck.json String json = null; try { InputStream is = activity.getAssets().open(aikitPathInData+"xzhd/aikit/pck.json"); int size = is.available(); byte[] buffer = new byte…...
MATLAB的.m文件与Python的.py文件:比较与互参
simulink MATLAB的.m文件与Python的.py文件:比较与互参相似之处**1. 基本结构****2. 执行逻辑****3. 可读性和维护性** 差异性**1. 语法特性****2. 性能和应用****3. 开发环境** 互相学习的可能性结论 MATLAB的.m文件与Python的.py文件:比较与互参 在编…...
武汉星起航:自运营团队精准把握亚马逊红利,引领跨境电商新潮流
在全球化的浪潮下,跨境电商行业蓬勃发展,为众多企业带来了前所未有的机遇。武汉星起航电子商务有限公司便是其中的佼佼者,其自运营团队凭借对亚马逊平台的深入了解和丰富的运营经验,成功抓住了亚马逊的流量红利,为公司…...
嵌入式计算器模块实现
嵌入式计算器模块规划 计算器混合算法解析 上面我们的算法理论已经完善, 我们只用给一个混合运算式, 计算器就可以帮助我们计算出结果. 但是存在一个痛点, 每次计算算式,都要重新编译程序, 所以我们想到了, 利用单片机, 读取用户输入的按键, 组成算式, 输入给机器, 这样我们就…...
tomcat定时重启
Tomcat定时重启(linux) 1. 编写脚本 在tomcat的bin目录下,使用vim restart.sh,编写restart.sh脚本,插入一下内容,最后并保存! #!/bin/bash# 初始化全局环境变量 . /etc/profilecd /usr/loca…...
构建LangChain应用程序的示例代码:48、如何使用非文本生成工具创建多模态代理
多模态输出:图像和文本 这个示例展示了如何使用非文本生成工具来创建多模态代理。 本例仅限于文本和图像输出,并使用UUID在工具和代理之间传输内容。 本例使用Steamship生成和存储生成的图像。生成的内容默认受到身份验证保护。 您可以在这里获取Ste…...
【笔记】记录一次全新的Java项目部署过程
记录一次全新的Java项目部署过程 环境:CentOS7一、初始环境准备 yum install wget -y yum install vim -y yum install net-tools -y mkdir /data mkdir /data/html mkdir /data/backend一、安装JDK 17 安装JDK17# 下载rpm wget https://download.oracle.com/java/17/latest/…...
达梦数据库系列—14. 表空间的备份和还原
目录 1、表空间备份 2、表空间还原 3、表空间恢复 4、增量还原恢复 1、表空间备份 表空间只能在联机状态下进行备份。 BACKUP TABLESPACE TBS BACKUPSET /dm/backup/dm_bak/ts_bak_01; 完全备份 BACKUP TABLESPACE TBS FULL BACKUPSET /dm/backup/dm_bak/ts_full_bak_01…...
奔驰G350升级原厂自适应悬挂系统有哪些作用
奔驰 G350 升级自适应悬挂系统后,可根据行车路况自动调整悬架高度和弹性,从而提升驾乘的舒适性和稳定性。 这套系统的具体功能包括: • 多种模式选择:一般有舒适、弯道、运动及越野等模式。例如,弯道模式在过弯时能为…...
一个启动脚本例子
一、全部代码 #!/bin/bash DATE$(date %Y%m%d)SOURCE"abc.jar" TARGET"backup/abc.jar.jew.$DATE"if [ -f "$SOURCE" ]; thencp "$SOURCE" "$TARGET" firm -f abc.jar mv abc_1.jar abc.jarpidNumps -ef | grep $SOURCE |…...
grpc学习golang版( 六、服务器流式传输 )
系列文章目录 第一章 grpc基本概念与安装 第二章 grpc入门示例 第三章 proto文件数据类型 第四章 多服务示例 第五章 多proto文件示例 第六章 服务器流式传输 第七章 客户端流式传输 第八章 双向流示例 文章目录 一、前言二、定义proto文件三、拷贝任意文件进项目四、编写serve…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
