当前位置: 首页 > news >正文

【C++】多态原理剖析

目录

1.虚表指针与虚表 

 2.多态原理剖析


1.虚表指针与虚表 

🍪类的大小计算规则

  1. 一个类的大小,实际就是该类中成员变量之和,需要注意内存对齐
  2. 空类:编译器给空类一个字节来唯一标识这个类的对象

对于下面的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
  • 虚表存的是虚函数指针,不是虚函数,虚函数和普通函数一样的,都是存在代码段的,只是虚函数的指针存在虚表中,可以通过这个指针找到虚函数

  • 实例化对象中存的不是虚表,存的是虚表指针,通过这个指针可以找到虚表。

接下来执行三个操作

  1. Base增加一个虚函数func2和一个普通函数fun3。
  2. 增加一个派生类Derive去继承Base
  3. 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,所以虚函数的重写(语法层)也叫作覆盖(原理层),覆盖就是指虚表中虚函数的覆盖。

🍪派生类的虚表指针总结:

  1. 派生类对象中也有一个虚表指针,派生类继承的成员包括虚表指针,但需要注意基类和派生类的虚表不是同一份
  2. 基类中的虚函数,派生类继承之后放进了虚表,基类中的普通函数,派生类继承之后不会放进虚表
  3. 派生类自己新增的虚函数按其在派生类中的声明次序增加到派生类虚表的最后,如下图所示

派生类的虚表生成过程:

 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.虚表指针与虚表 &#x1f36a;类的大小计算规则 一个类的大小&#xff0c;实际就是该类中成员变量之和&#xff0c;需要注意内存对齐空类&#xff1a;编译器给空类一个字节来唯一标识这个类的对象 对于下面的Base类&#xff0c;它的…...

【Rust自学】20.4. 结语:Rust学习一阶段完成+附录

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 20.4.1. 总结 Rust初级学习之旅终于完成了&#xff01;恭喜&#xff01; 包括这篇文章&#xff0c;我们使用了110篇文章来学习Rust。 真…...

pytorch引用halcon写数据集

****加粗样式虽然啰嗦一点&#xff0c;但好歹halcon自己熟悉&#xff0c;不会忘记&#xff0c;用os 和 pil会导致脑子记得东西太多 import halcon as ha import torch from torch.utils.data import Datasetpath0 rE:\BaiduNetdiskDownload\cell class MyDataset(Dataset):de…...

让文物“活”起来,以3D数字化技术传承文物历史文化!

文物&#xff0c;作为不可再生的宝贵资源&#xff0c;其任何毁损都是无法逆转的损失。然而&#xff0c;当前文物保护与修复领域仍大量依赖传统技术&#xff0c;同时&#xff0c;文物管理机构和专业团队的力量相对薄弱&#xff0c;亟需引入数字化管理手段以应对挑战。 积木易搭…...

aarch64 Ubuntu20.04 安装docker

安装 docker 依赖项&#xff1a;sudo apt-get update sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release添加 Docker GPG 密钥&#xff1a;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 服务交互&#xff0c;可以发送 GET、POST 等各种请求类型&#xff0c;并处理响应。该库广泛用于 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、定位对比&#xff1a;感知与规划的全维覆盖 2.2、数据与技术特性对比 2.3、技术协同&#xff1a;构建全栈研发生态 2.4、应用场景与评估体系 2.5、总结与展望 3、参考文献 1、引言 随着自动驾驶技术向全栈化迈进&#xff0c;Motional 团…...

[LUA ERROR] bad light userdata pointer

Cocos2d项目&#xff0c;targetSdkVersion30&#xff0c;在 android 13 设备运行报错: [LUA ERROR] bad light userdata pointer &#xff0c;导致黑屏。 参考 cocos2dx 适配64位 arm64-v8a 30 lua 提示 bad light userdata pointer 黑屏-CSDN博客的方法 下载最新的Cocos2dx …...

【Java八股】JVM

JVM 1. jvm内存区域分为哪些部分 线程私有的&#xff1a;程序计数器、虚拟机栈、本地方法栈 程序计数器&#xff1a;指示当前线程执行到的字节码文件的行号&#xff0c;是线程切换后保证线程能恢复到正确的执行位置的关键 虚拟机栈&#xff1a;用于存储方法调用的数据&…...

集成学习(一):从理论到实战(附代码)

一、引言 在机器学习领域&#xff0c;打造一个独立、强大的算法是解决问题的关键。然而&#xff0c;集成学习提供了一种不同的视角&#xff1a;通过组合多个“弱”学习器来创建一个更强大的模型。本文探讨集成学习的思想、方法及其应用。 二、机器学习 vs 集成学习思想 传统…...

Netty:高性能网络应用框架的深度解析

引言 Netty 是由 JBoss 提供的一个开源的 Java NIO 客户端/服务器框架&#xff0c;它用以快速开发网络应用程序&#xff0c;如协议服务器和客户端。它的设计目标是提供异步事件驱动的网络应用程序框架&#xff0c;支持高效的网络通信和数据处理。Netty 在性能、可扩展性、安全…...

神经网络常见激活函数 3-ReLU函数(修正线性单元)

文章目录 ReLU函数求导函数和导函数图像优缺点pytorch 中的 ReLU 函数tensorflow 中的ReLU函数 ReLU 修正线性单元 &#xff08;Rectified Linear Unit&#xff09; 函数求导 ReLU函数 ReLU ⁡ max ⁡ ( 0 , x ) { x x ≥ 0 0 x < 0 \begin{aligned} \operatorname{ReL…...

Android开发获取缓存,删除缓存

Android开发获取缓存&#xff0c;删除缓存 app设置中往往有清理缓存的功能。会显示当前缓存时多少&#xff0c;然后可以点击清理缓存 直接上代码&#xff1a; object CacheHelper {/*** 获取缓存大小* param context* return* throws Exception*/JvmStaticfun getTotalCache…...

如何通过PHP接入DeepSeek的API

想知道如何通过PHP接入DeepSeek的API。看起来他对之前的Python步骤比较熟悉&#xff0c;但这次想用PHP实现。 首先&#xff0c;我需要回顾一下DeepSeek API的文档&#xff0c;确认它支持哪些方法和参数。假设用户已经配置了环境变量&#xff0c;比如API密钥&#xff0c;接下来…...

一种基于Leaflet.Legend的图例动态更新方法

目录 前言 一、场景再现 1、需求描述 2、核心方法介绍 3、存在的问题 二、问题解决 1、重复解决办法 2、图例不展示解决办法 3、成果展示 三、总结 前言 在当今数字化时代&#xff0c;地理信息系统&#xff08;GIS&#xff09;技术已经广泛应用于各个领域&#xff0c;…...

Spring Boot: 使用 @Transactional 和 TransactionSynchronization 在事务提交后发送消息到 MQ

Spring Boot: 使用 Transactional 和 TransactionSynchronization 在事务提交后发送消息到 MQ 在微服务架构中&#xff0c;确保消息的可靠性和一致性非常重要&#xff0c;尤其是在涉及到分布式事务的场景中。本文将演示如何使用 Spring Boot 的事务机制和 TransactionSynchron…...

LQB(2)-python-枚举

前言 python中的枚举一般有两个说法&#xff0c;一个是枚举算法&#xff08;暴力求解法&#xff0c;算法层面&#xff09;&#xff0c;一个是遍历使用enumerate()函数或者enum模块创建&#xff08;&#xff09;。 暴力求解法在之前的博文里面讲过了&#x1f447;&#xff0c;…...

MongoDB开发规范

分级名称定义P0核心系统需7*24不间断运行&#xff0c;一旦发生不可用&#xff0c;会直接影响核心业务的连续性&#xff0c;或影响公司名誉、品牌、集团战略、营销计划等&#xff0c;可能会造成P0-P2级事故发生。P1次核心系统这些系统降级或不可用&#xff0c;会间接影响用户使用…...

为什么DeepSeek服务器繁忙?

致敬DeepSeek 用户层面 用户数量激增&#xff1a;DeepSeek 免费且功能强大&#xff0c;对普通用户和开发者都极具吸引力124。尤其是在新功能推出、新模型上线或相关热门活动期间&#xff0c;大量用户会在短时间内涌入9。例如春节期间&#xff0c;DeepSeek 的用户量达到四千万7。…...

律所录音证据归集工具:基于PyQt6与多线程的自动化音频管理解决方案

在律所日常工作中&#xff0c;音频证据的整理与归集是一个高频且复杂的任务。面对大量的案件录音文件&#xff0c;如何实现快速且准确的分类与存档&#xff0c;成为了律所提高效率、降低出错率的关键。本文将通过技术角度解析一款名为律所录音证据归集工具的项目&#xff0c;详…...

【含开题报告+文档+PPT+源码】基于SpringBoot+Vue旅游管理网站

开题报告 本论文探讨了一款采用现代Web开发技术构建的台州市旅游综合信息与服务平台的设计与实现。该系统基于SpringBoot框架&#xff0c;以其轻量级、快速开发和强大的企业级应用支持能力为核心后端技术支撑&#xff0c;结合Vue.js前端框架及ElementUI组件库&#xff0c;为用…...

unity碰撞的监测和监听

1.创建一个地面 2.去资源商店下载一个火焰素材 3.把procedural fire导入到自己的项目包管理器中 4.给magic fire 0 挂在碰撞组件Rigidbody , Sphere Collider 5.创建脚本test 并挂在magic fire 0 脚本代码 using System.Collections; using System.Collections.Generic; usi…...

DeepSeek-R1 32B Windows+docker本地部署

最近国产大模型DeepSeek兴起&#xff0c;本地部署了一套deepseek同时集成Open WebUI界面,给大家出一期教程。 软件&#xff1a;Ollama、docker、Open WebUI 一、用Ollama下载模型 首先我们需要安装Ollama&#xff0c;它可以在本地运行和管理大模型。 到Ollama官网 https://ol…...

C++11新特性之unique_ptr智能指针

本节继续介绍智能指针&#xff0c;不了解的读者可以先阅读——C11新特性之shared_ptr智能指针-CSDN博客 1.介绍 unique_ptr是C11标准提供的另一种智能指针。与shared_ptr不同的是&#xff0c;unique_ptr指针指向的堆内存无法同其他unique_ptr共享&#xff0c;也就是每一片堆内…...

Vue与Konva:解锁Canvas绘图的无限可能

前言 在现代Web开发中&#xff0c;动态、交互式的图形界面已成为提升用户体验的关键要素。Vue.js&#xff0c;作为一款轻量级且高效的前端框架&#xff0c;凭借其响应式数据绑定和组件化开发模式&#xff0c;赢得了众多开发者的青睐。而当Vue.js邂逅Konva.js&#xff0c;两者结…...

python绘图之柱状堆积图的绘制

本节来学习用python来绘制柱状堆积图. 使用的库为matplotlib.pyplot,numpy 代码如下 # 导入必要的库 import matplotlib.pyplot as plt # 用于绘图 import numpy as np # 用于数值计算# 模拟一些数据 x [数值{}.format(i) for i in range(10)] # 创建一个包含10个元素的列…...

剪辑学习整理

文章目录 1. 剪辑介绍 1. 剪辑介绍 剪辑可以干什么&#xff1f;剪辑分为哪些种类&#xff1f; https://www.bilibili.com/video/BV15r421p7aF/?spm_id_from333.337.search-card.all.click&vd_source5534adbd427e3b01c725714cd93961af 学完剪辑之后如何找工作or兼职&#…...

DeepSeek从入门到精通:全面掌握AI大模型的核心能力

文章目录 一、DeepSeek是什么&#xff1f;性能对齐OpenAI-o1正式版 二、Deepseek可以做什么&#xff1f;能力图谱文本生成自然语言理解与分析编程与代码相关常规绘图 三、如何使用DeepSeek&#xff1f;四、DeepSeek从入门到精通推理模型推理大模型非推理大模型 快思慢想&#x…...