C++中多态的原理【精华】
虚函数表
通过一道题我们先感受一下编译器针对多态的处理
#include <iostream>
using namespace std;class Base
{
public:virtual void Func1(){cout << "Func1()" << endl;}
private:int _b = 1;char _c
};int main()
{cout << sizeof(Base) << endl;return 0;
}
在x64环境下,显示的结果是12字节

为什么是12字节呢?一个int就4字节,一个char就1字节,内存对齐一下也是8字节呀!为什么显示的结果是12字节呢? 我们调试代码,看看内部结构

通过调试我们发现Base创建的对象里面有一个指针_vfptr,如果我们计算sizeof的时候把这个指针算上的话刚刚好的12字节!
那么疑问来了,这个指针到底是什么?为什么会出现在对象里面?这个指针到底有什么作用?
这个指针我们叫做虚函数表指针(v代表virtual,f代表function)。一个含有虚函数的类中都至少都有一个虚函数表指针,因为虚函数的地址要被放到虚函数表中,虚函数表也简称虚表,。那么子类中这个表放了些什么呢?我们接着往下分析
#include <iostream>
using namespace std;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 _c;
};int main()
{cout << sizeof(Base) << endl;Base b;return 0;
}
通过监视窗口再来看:

我们发现这个指针指向一个数组(虚函数表),这个数组(表)里面存的就是虚函数的地址
知道了包含虚函数的类里面会出现一个指针,这个指针指向一个指针数组,数组里面保存的是类里面的虚函数,接下来我们看看多态的原理
文章目录
- 虚函数表
- 多态的原理
多态的原理
提示:这里可以添加本文要记录的大概内容:
class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }virtual void func(){}
private:int _a = 1;
};class Student : public Person {
public:virtual void BuyTicket() { cout << "买票-半价" << endl; }
private:int _b = 0;
};void Func(Person& p)
{p.BuyTicket();
}int main()
{Person p;Student s;Func(p);Func(s);return 0;
}
我们看一下父类的虚表指针

我们看到Person对象里面的_vfptr指向的指针数组里面有两个指针,说明保存的是两个地址,我们看看这两个地址是什么?

然后我们看一下_vfptr指针指向的数组里面保存的地址

再看一下子类的虚表指针

虚函数需要被重写,一开始子类会将虚函数进行直接拷贝,重写虚函数之后,虚函数的地址就发生改变了
那为什么多态的原理和指向的对象有关?和虚表有什么关系?

父类对象找到虚函数表的地址,在表里面找到虚函数的地址,因为这里是父类对象,直接调用父类对象的虚函数
子类对象赋值给父类对象,这样会产生“切片”,找到子类中父类的那一部分,寻找到虚函数表的地址,但是虚函数表里存的是子类重写的父类虚函数的地址,所以此时_vfptr指向的其实是子类的虚函数指针数组,自认而然掉用的是子类的虚函数
那为什么不使用指针和引用后,就不构成多态了呢?
#include <iostream>
#include <string>
#include <vector>
using namespace std;class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }virtual void func() {}
private:int _a = 1;
};class Student : public Person {
public:virtual void BuyTicket() { cout << "买票-半价" << endl; }
private:int _b = 0;
};void Func(Person p)
{p.BuyTicket();
}int main()
{Person p;Student s;Func(p);Func(s);return 0;
}

因为指针和引用是指向子类对象切割出来的父类对象的那一部分
不使用指针和引用后,直接将子类传递给父类,切割出来的子类对象中父类的那一部分,成员拷贝给父类,但是不会拷贝虚表指针
相关文章:
C++中多态的原理【精华】
虚函数表 通过一道题我们先感受一下编译器针对多态的处理 #include <iostream> using namespace std;class Base { public:virtual void Func1(){cout << "Func1()" << endl;} private:int _b 1;char _c };int main() {cout << sizeof(B…...
亿赛通电子文档安全管理系统 Update.jsp SQL注入
目录 0x01 漏洞介绍 0x02 影响产品 0x03 语法特征 0x04 漏洞复现页面 0x05 漏洞修复建议 0x01 漏洞介绍 亿赛通电子文档安全管理系统是国内最早基于文件过滤驱动技术的文档加解密产品之一,保护范围涵盖终端电脑(Windows、Mac、Linux系统平台&#…...
神经网络中的反向传播:综合指南
塔曼纳 一、说明 反向传播是人工神经网络 (ANN) 中用于训练深度学习模型的流行算法。它是一种监督学习技术,用于调整网络中神经元的权重,以最小化预测输出和实际输出之间的误差。 在神经网络中,反向传播是计算损失函数…...
协同创新、奔赴未来——“华为云杯”2023人工智能创新应用大赛华丽谢幕
9月27日,在苏州工业园区管理委员会、华为云计算技术有限公司的指导下,由SISPARK(苏州国际科技园)、华为(苏州)人工智能创新中心联合主办,东北大学工业智能与系统优化国家级前沿科学中心、浙江大…...
介绍Node.js中fs模块 代码和注释。
Node.js中的fs模块提供了一些用于文件系统操作的API,包括文件读写、目录操作等。 读取文件 使用fs.readFile()方法可以读取文件内容。该方法的第一个参数是文件路径,第二个参数是可选的选项对象,第三个参数是回调函数。回调函数的第一个参数…...
【QT 读取JSON】 深入浅出 使用QT内置的QJson模块解析Json文件 匠心之作
目录 0 引言1 Json数据分析2 解析Json数据 🙋♂️ 作者:海码007📜 专栏:QT专栏💥 标题:【QT 读取JSON】 使用QT内置的QJson模块解析Json文件❣️ 寄语:人生的意义或许可以发挥自己全部的潜力&…...
初识javaweb2 tomcat
如果是tomcat启动成功却无法通过localhost:8080进入页面,先去查看是否是端口号被占用, 再用命令中断占用的进程,如果简单的命令窗口无法中断,切换到管理员身份运行即可 netstat -ano|findstr "8080" 查看那个进程占用了…...
使用OPENROWSET :在一个数据库中查询另一个数据库的数据
当你需要在一个数据库中查询另一个数据库的数据时,SQL Server提供了多种方法来实现这一目标。一种常见的方法是使用链接服务器(Linked Server),另一种方法是使用 OPENROWSET 函数。本篇博客将重点介绍如何使用 OPENROWSET 函数在当…...
基于STM32设计的智慧农业管理系统(ESP8266+腾讯云微信小程序)
一、项目介绍 基于STM32设计的智慧农业控制系统(ESP8266+腾讯云微信小程序) 1.1 项目背景 随着人们对食品安全和生态环境的日益重视,智慧农业逐渐成为一个备受关注的领域。智能化管理可以提高农业生产效率,减少资源浪费,改善生态环境。因此,基于物联网技术的智慧农业管理系…...
Flutter视图原理之三棵树的建立过程
目录 三棵树的关系树的构建过程1.updateChild函数(element的复用)2.inflateWidget函数3.mount函数3.1 componentElement的实现3.2 RenderObjectElement的实现3.2.1 attachRenderObject函数 4.performRebuild函数 总结三棵树创建流程 三棵树的关系 Flutt…...
详细解析冒泡排序,JS如何基本实现的。
目录 冒泡排序是什么: 使用冒泡排序是为了什么: DEMO示例: 冒泡排序是什么: 冒泡排序(Bubble Sort)是一种简单的比较排序算法,它通过多次遍历待排序的元素,比较相邻元素的大小,如果它们的顺序不正确就交换它们&…...
如何消除CSDN博文代码中自动添加的行号
哪里有自定义目录标题 编写CSDN博文,使用代码块的linux命令行,预览时没有代码行号,但发布文章后自动添加了行号。 git clone https://github.com/mikel-brostrom/yolo_tracking.git cd yolo_tracking pip install -v -e .为什么预览和发布的…...
定制效果在线定制印刷系统源码 DIY在线定制系统源码 云印刷定制系统源码手机、PC端实时互通
支持各类产品的在线定制,无论是水杯雨伞U盘还是T恤衬衫四件套,均可轻松进行定制 独创制作间概念,同一套模板可以重复对应不同制作间 手机、PC端实时互通,客户可通过任意途径进行图片上传、编辑,一方修改另一方即时可见…...
算法|每日一题|同积元组|哈希统计
1726.同积元组 原题地址: 力扣每日一题:同积元组 给你一个由 不同 正整数组成的数组 nums ,请你返回满足 a * b c * d 的元组 (a, b, c, d) 的数量。其中 a、b、c 和 d 都是 nums 中的元素,且 a ! b ! c ! d 。 class Solution …...
最新AI创作系统ChatGPT网站H5源码V2.6.4+搭建部署教程+支持GPT4.0+支持ai绘画(Midjourney)/支持Prompt预设应用
一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统AI绘画系统,支持OpenAI GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署…...
最新!两步 永久禁止谷歌浏览器 Google Chrome 自动更新
先放效果图: CSDN这个问题最火的大哥的用了没用 像他这样连浏览器都打不开 为什么要禁止chrome自动更新 看到很多搞笑的大哥,说为啥要禁止; 我觉得最大的原因就是chromedriver跟不上chrome的自动更新,导致我们做selenium爬虫的…...
在Java中线程和进程的区别
在Java中,线程和进程的区别与一般的操作系统环境下类似,但在Java语言层面上也有一些特点。下面是在Java中线程和进程的区别: 定义:在Java中,进程是指一个正在运行的应用程序实例,而线程是进程中的执行单元。…...
【高危安全通告】Oracle 10月月度安全漏洞预警
近日,安全狗应急响应中心关注到Oracle官方发布安全公告,共披露出在Oracle Weblogic中存在的6个高危漏洞。 漏洞描述 CVE-2023-22069:Oracle Weblogic 远程代码执行漏洞 Oracle WebLogic Server存在远程代码执行漏洞,该漏洞的CVS…...
卷王问卷考试系统SurveyKing,开源调查问卷和考试系统源码
卷王问卷考试系统/SurveyKing是一个功能最强大的开源调查问卷和考试系统,可以快速部署,并适用于各行业。该系统提供了在线表单设计、数据收集、统计和分析等功能,支持20多种题型,多种创建问卷方式和多种问卷设置。 无论您是需要进…...
uniapp开发微信小程序,webview内嵌h5,h5打开pdf地址,解决方案
根据公司要求,让我写一个h5,后续会嵌入到合作公司的微信小程序的webview中,如果是自己公司微信小程序,可以采取先下载下来pdf,然后通过wx.openDocument,进行单纯的预览操作,这个可以根据这个老哥…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
