调用基类的纯虚函数,如何知道纯虚函数会调用哪个派生类(子类)中的实现。
在 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…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...