【C++】多态原理剖析
目录
1.虚表指针与虚表
2.多态原理剖析
1.虚表指针与虚表
🍪类的大小计算规则
- 一个类的大小,实际就是该类中成员变量之和,需要注意内存对齐
- 空类:编译器给空类一个字节来唯一标识这个类的对象
对于下面的Base类,它的大小应该是类中成员变量之和,一个int成员,一个char成员,根据结构体内存对齐规则,sizeof(Base) = 8byte
class Base
{
public:virtual void func1(){cout << "func1()" << endl;}
private:int _b = 1;char _ch;
};
成员函数为虚函数

成员函数是普通函数

但是代码的运行结果为sizeof(Base) = 12byte,与上面的分析结果不一致
Base类中的成员函数使用virtual修饰,可以推断包含虚函数的类大小计算规则和包含普通函数的类大小计算规则可能存在差异
我们创建一个Base对象,进行进一步分析

从监视窗口,可以发现,实例化的Base对象成员构成,除了两个成员变量外,还有一个数组指针,而数组成员又是指针类型,所以准确来说,_vfptr是一个指针数组指针
🍪虚表指针和虚表
虚表指针:对象中的这个指针叫做虚函数表指针(v--virtual,f--function)。
虚表:一个含有虚函数的类中至少有一个虚函数表指针,因为虚函数的地址要被放到虚函数表(虚表)中
📖Note:
- 虚函数表本质是一个存虚函数指针的指针数组,一般这个数组最后面放了一个nullptr
虚表存的是虚函数指针,不是虚函数,虚函数和普通函数一样的,都是存在代码段的,只是虚函数的指针存在虚表中,可以通过这个指针找到虚函数
实例化对象中存的不是虚表,存的是虚表指针,通过这个指针可以找到虚表。

接下来执行三个操作
- Base增加一个虚函数func2和一个普通函数fun3。
- 增加一个派生类Derive去继承Base
- Derive中重写func1
class Base
{
public:virtual void func1(){cout << "func1()" << endl;}virtual void func2(){cout << "func2()" << endl;}// 普通函数void func3(){cout << "func3()" << endl;}
private:int _b = 1;char _ch;
};class Derive : public Base
{
public:virtual void func1(){cout << "Derive::func1()" << endl;}
private:int _d = 2;
};


从监视窗口可以发现
1️⃣基类的虚表指针值_vfptr != 派生类的虚表指针值_vfptr
2️⃣基类的普通函数func3不会存入虚表之中,继承之后也不会存入派生类的虚表
3️⃣派生类中对func1完成了重写,d的虚表中存的是重写的Derive::func1,所以虚函数的重写(语法层)也叫作覆盖(原理层),覆盖就是指虚表中虚函数的覆盖。
🍪派生类的虚表指针总结:
- 派生类对象中也有一个虚表指针,派生类继承的成员包括虚表指针,但需要注意基类和派生类的虚表不是同一份
- 基类中的虚函数,派生类继承之后放进了虚表,基类中的普通函数,派生类继承之后不会放进虚表
派生类自己新增的虚函数按其在派生类中的声明次序增加到派生类虚表的最后,如下图所示


派生类的虚表生成过程:

2.多态原理剖析
基于上面创建的基类Base和派生类Derive,执行以下代码,观察执行结果

🍪分析:
- func3是基类Base中的定义的普通函数
- func1是基类Base中定义的虚函数,且派生类完成了对func1的重写,构成多态
🍪普通函数的调用,只与调用函数的对象的类型有关
前两次对func3的调用都是Base*类型的指针进行调用

🍪多态调用,与函数调用者指向的整个对象有关
- 第一次对func1的调用:ptr指向的是一个Base对象,对虚函数func1的调用需要到_vfptr指向的虚表中查找func1函数的地址进行调用,最终调用的是Base类中的函数func1
- 第二次对func1的调用:ptr指向的是Derive对象中Base的切片,对虚函数func1的调用仍然需要到_vfptr指向的虚表中查找func1函数的地址进行调用,但是这一次,_vfptr指向的虚表中,func1函数的地址已经更改成了Derive类中重写的func1函数地址,所以最终调用的是Derive中重写的func1函数

相关文章:
【C++】多态原理剖析
目录 1.虚表指针与虚表 2.多态原理剖析 1.虚表指针与虚表 🍪类的大小计算规则 一个类的大小,实际就是该类中成员变量之和,需要注意内存对齐空类:编译器给空类一个字节来唯一标识这个类的对象 对于下面的Base类,它的…...
【Rust自学】20.4. 结语:Rust学习一阶段完成+附录
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 20.4.1. 总结 Rust初级学习之旅终于完成了!恭喜! 包括这篇文章,我们使用了110篇文章来学习Rust。 真…...
pytorch引用halcon写数据集
****加粗样式虽然啰嗦一点,但好歹halcon自己熟悉,不会忘记,用os 和 pil会导致脑子记得东西太多 import halcon as ha import torch from torch.utils.data import Datasetpath0 rE:\BaiduNetdiskDownload\cell class MyDataset(Dataset):de…...
让文物“活”起来,以3D数字化技术传承文物历史文化!
文物,作为不可再生的宝贵资源,其任何毁损都是无法逆转的损失。然而,当前文物保护与修复领域仍大量依赖传统技术,同时,文物管理机构和专业团队的力量相对薄弱,亟需引入数字化管理手段以应对挑战。 积木易搭…...
aarch64 Ubuntu20.04 安装docker
安装 docker 依赖项:sudo apt-get update sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release添加 Docker GPG 密钥:curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyr…...
JAVA:CloseableHttpClient 进行 HTTP 请求的技术指南
1、简述 CloseableHttpClient 是 Apache HttpComponents 提供的一个强大 HTTP 客户端库。它允许 Java 程序与 HTTP/HTTPS 服务交互,可以发送 GET、POST 等各种请求类型,并处理响应。该库广泛用于 REST API 调用、文件上传和下载等场景。 2、特性 Close…...
Mac上搭建k8s环境——Minikube
1、在mac上安装Minikube可执行程序 brew cask install minikub 安装后使用minikube version命令查看版本 2、安装docker环境 brew install --cask --appdir/Applications docker #安装docker open -a Docker #启动docker 3、安装kubectl curl -LO https://storage.g…...
经典排序算法复习----C语言
经典排序算法复习 分类 交换类 冒泡快排 分配类 计数排序基数排序 选择类 选择排序 堆排序 归并类 归并排序 插入类 直接插入排序 希尔排序 折半插入排序 冒泡排序 基于交换。每一轮找最大值放到数组尾部 //冒泡排序 void bubSort(int* arr,int size){bool sorte…...
自动驾驶数据集三剑客:nuScenes、nuImages 与 nuPlan 的技术矩阵与生态协同
目录 1、引言 2、主要内容 2.1、定位对比:感知与规划的全维覆盖 2.2、数据与技术特性对比 2.3、技术协同:构建全栈研发生态 2.4、应用场景与评估体系 2.5、总结与展望 3、参考文献 1、引言 随着自动驾驶技术向全栈化迈进,Motional 团…...
[LUA ERROR] bad light userdata pointer
Cocos2d项目,targetSdkVersion30,在 android 13 设备运行报错: [LUA ERROR] bad light userdata pointer ,导致黑屏。 参考 cocos2dx 适配64位 arm64-v8a 30 lua 提示 bad light userdata pointer 黑屏-CSDN博客的方法 下载最新的Cocos2dx …...
【Java八股】JVM
JVM 1. jvm内存区域分为哪些部分 线程私有的:程序计数器、虚拟机栈、本地方法栈 程序计数器:指示当前线程执行到的字节码文件的行号,是线程切换后保证线程能恢复到正确的执行位置的关键 虚拟机栈:用于存储方法调用的数据&…...
集成学习(一):从理论到实战(附代码)
一、引言 在机器学习领域,打造一个独立、强大的算法是解决问题的关键。然而,集成学习提供了一种不同的视角:通过组合多个“弱”学习器来创建一个更强大的模型。本文探讨集成学习的思想、方法及其应用。 二、机器学习 vs 集成学习思想 传统…...
Netty:高性能网络应用框架的深度解析
引言 Netty 是由 JBoss 提供的一个开源的 Java NIO 客户端/服务器框架,它用以快速开发网络应用程序,如协议服务器和客户端。它的设计目标是提供异步事件驱动的网络应用程序框架,支持高效的网络通信和数据处理。Netty 在性能、可扩展性、安全…...
神经网络常见激活函数 3-ReLU函数(修正线性单元)
文章目录 ReLU函数求导函数和导函数图像优缺点pytorch 中的 ReLU 函数tensorflow 中的ReLU函数 ReLU 修正线性单元 (Rectified Linear Unit) 函数求导 ReLU函数 ReLU max ( 0 , x ) { x x ≥ 0 0 x < 0 \begin{aligned} \operatorname{ReL…...
Android开发获取缓存,删除缓存
Android开发获取缓存,删除缓存 app设置中往往有清理缓存的功能。会显示当前缓存时多少,然后可以点击清理缓存 直接上代码: object CacheHelper {/*** 获取缓存大小* param context* return* throws Exception*/JvmStaticfun getTotalCache…...
如何通过PHP接入DeepSeek的API
想知道如何通过PHP接入DeepSeek的API。看起来他对之前的Python步骤比较熟悉,但这次想用PHP实现。 首先,我需要回顾一下DeepSeek API的文档,确认它支持哪些方法和参数。假设用户已经配置了环境变量,比如API密钥,接下来…...
一种基于Leaflet.Legend的图例动态更新方法
目录 前言 一、场景再现 1、需求描述 2、核心方法介绍 3、存在的问题 二、问题解决 1、重复解决办法 2、图例不展示解决办法 3、成果展示 三、总结 前言 在当今数字化时代,地理信息系统(GIS)技术已经广泛应用于各个领域,…...
Spring Boot: 使用 @Transactional 和 TransactionSynchronization 在事务提交后发送消息到 MQ
Spring Boot: 使用 Transactional 和 TransactionSynchronization 在事务提交后发送消息到 MQ 在微服务架构中,确保消息的可靠性和一致性非常重要,尤其是在涉及到分布式事务的场景中。本文将演示如何使用 Spring Boot 的事务机制和 TransactionSynchron…...
LQB(2)-python-枚举
前言 python中的枚举一般有两个说法,一个是枚举算法(暴力求解法,算法层面),一个是遍历使用enumerate()函数或者enum模块创建()。 暴力求解法在之前的博文里面讲过了👇,…...
MongoDB开发规范
分级名称定义P0核心系统需7*24不间断运行,一旦发生不可用,会直接影响核心业务的连续性,或影响公司名誉、品牌、集团战略、营销计划等,可能会造成P0-P2级事故发生。P1次核心系统这些系统降级或不可用,会间接影响用户使用…...
Vue3 图片标框功能实现方案
基于 Vue3 组合式 API 的图片标框(画框、标注、选框)完整实现,核心逻辑封装在 GetBoxes 组件里,复制就能用 一、功能说明 ✅ 在图片上鼠标拖拽画矩形框 ✅ 实时显示框坐标(x, y, width, height) ✅ 支持多…...
微信小程序3D开发框架技术对比:XR-Frame与threejs-miniprogram
随着微信小程序逐步支持3D渲染与AR能力,开发者面临两个主要官方方案:自研的XR-Frame和适配Three.js的threejs-miniprogram。本文将从架构设计、渲染机制、功能集成、开发模式及适用场景等维度进行技术分析,为技术选型提供参考。一、XR-Frame&…...
Sora 2原生接入Unity 6.0:5步完成神经渲染管线嵌入,实测帧率提升47%(附GitHub认证插件)
更多请点击: https://kaifayun.com 第一章:Sora 2与Unity整合 Sora 2作为新一代AI视频生成引擎,其开放API设计天然支持与实时3D引擎的深度协同。Unity 2023.2版本通过URP(Universal Render Pipeline)与C# Job System提…...
电容损坏深度诊断,从外观到 ESR精准区分容衰与漏电
在 PCB 故障中,电容损坏占比超 40%,是当之无愧的 “头号杀手”。很多工程师仅靠 “鼓包漏液” 判断电容好坏,殊不知80% 的电容损坏是隐性的—— 外观平整但容值衰减、ESR 升高、轻微漏电,导致供电不稳、系统重启、噪声增大&#x…...
毕业设计 yolov11骨折检测医疗辅助系统(源码+论文)
文章目录 0 前言1 项目运行效果2 课题背景2.1 研究背景2.2 国内外研究现状2.3 研究意义 3 设计框架(骨折检测系统设计框架说明)3.1. 系统架构图3.2. 技术选型3.2.1 核心组件3.2.2 辅助工具 3.3. 核心模块设计3.3.1 YOLO模型训练模块训练流程图关键伪代码…...
【DeepSeek架构评审功能深度解密】:20年架构师亲授3大避坑指南与5步落地 checklist
更多请点击: https://kaifayun.com 第一章:DeepSeek架构评审功能全景概览 DeepSeek架构评审功能是一套面向大模型系统设计与工程落地的自动化分析框架,聚焦于模型结构合理性、计算图优化潜力、内存访问模式、算子兼容性及部署约束等多维度评…...
长期使用Token Plan套餐在项目开发中的成本观察
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 长期使用Token Plan套餐在项目开发中的成本观察 在AI驱动的项目开发中,成本控制与预算管理是团队负责人必须面对的现实…...
为Claude Code配置稳定API源并解决访问限制
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 为Claude Code配置稳定API源并解决访问限制 Claude Code 作为一款强大的 AI 编程辅助工具,其原生服务在某些情况下可能…...
手把手教你用Mind+和Blynk,让手机轻松遥控掌控板(含自建服务器避坑指南)
从零搭建物联网控制平台:Mind与Blynk深度整合实战 当你第一次尝试用手机控制硬件设备时,那种"隔空取物"的奇妙感总会让人兴奋不已。想象一下,躺在沙发上就能调节书桌上的智能台灯亮度,或者在外出时随时查看家中的温湿度…...
16个分片+2副本:pg_shard的master_create_worker_shards最佳实践
16个分片2副本:pg_shard的master_create_worker_shards最佳实践 【免费下载链接】pg_shard ATTENTION: pg_shard is superseded by Citus, its more powerful replacement 项目地址: https://gitcode.com/gh_mirrors/pg/pg_shard pg_shard作为PostgreSQL的分…...
