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

C++多态实现原理详解

阅读引言: 我想象了一下, 假如人有突然问我什么是多态, 我该如何给别人说清楚呢?所以写下这篇文章, 希望大家看完有所收获。

①. 开胃小菜

先看这样一个开胃小菜

这里我有点小小的疑惑, 大小为啥是1。

在C++中,结构体(struct)A的对象a的大小为1的原因可能是因为编译器对结构体进行了内存对齐。默认情况下,C++编译器会将结构体的起始地址与最大成员的对齐要求进行对齐。在这个例子中,结构体A是空的,没有任何成员,所以编译器将其大小设置为1字节,以满足内存对齐的要求。

结构体对齐, 大小为1, 1是不是能被任意的地址整除, 这是结构体对齐的知识。

②. 多态常见的一个小小面试题

假设使用上面的类实例化出一个类对象, 使用sizeof求该对象的大小?

结果为12个字节,这里使用的是32位环境。


为什么多出了四个字节呢?这多出来的四个字节是啥?为什么需要这个四个字节的空间, 用来干什么?


1,因为当一个类中出现虚函数的时候, 无论是自己本身的还是继承来的, 都会多出四个字节的空间, 这四个字节的空间其实是一个指针, 专业名词叫做虚函数表指针, 用来指向虚函数表。虚函数表指针(vptr)、虚函数表后面会介绍。

2, 这多出来的四个字节就是一个指针, 指向虚函数表, 这是编译器载编译期间帮我们做的, 伪代码如下。

3, 因为需要直到虚函数表的内存地址, 才能通过指针访问到虚函数, 虚函数表中的内容其实就是虚函数的入口地址。

③, 虚函数指针虚函数表

虚函数指针: 本质就是一个指针变量, 用来保存虚函数表的地址

虚函数表: 本质是内存中的一段连续空间, 空间内的每一项都是一个函数指针, 用来保存虚函数的入口地址。

内存布局: 

需要注意的是, 虚函数表属于类, 然后需要直到虚函数指针被赋值的时机是载钩爪函数中, 这是编译器默默为我们做的。

④. 多态的理解

代码层面上: 

多态存在的条件: 类中必须存在虚函数, 调用虚函数的方式必须使用虚函数表指针, 找到虚函数表, 接着调用里面的虚函数。换句话说就是必须是指针或引用调用的虚函数才是多态, 而静态创建的对象出现不了多态。

表现形式上看多态: 

第一条: 子类中重写父类中的虚函数是由要求的, 也就是函数的返回值、函数名、参数列表都需要相同, 但是这里有一个小小的特殊情况, 就是当基类中的虚函数返回的值基类指针或者引用的时候, 允许派生类中的函数的返回值返回派生类的指针或者引用。

#include <iostream> 
using namespace std; 
class A{};
class B:public A{}; 
class Base{ 
public: virtual void func(void){cout << "Base func" << endl; } virtual A* foo(void){cout << "Base foo" << endl; } 
}; class Derived: public Base{ void func(void) { cout <<"Derived func" << endl; }B* foo(void){                       //允许返回子类的指针或者引用,构成虚函数的覆盖条件 					cout << "Derived foo" << endl; }
}; int main(void){ Derived d1;Base *pd1 = &d1; pd1->func();Base& pd2 = d1;pd2.foo();return 0; 
} 

总结一下虚函数覆盖的条件: 

  • 只有类中的成员函数才能声明为虚函数,而全局函数、静态成员函数、构造函数都不能被声明为虚函数

  • 只有在基类中以virtual关键字声明的虚函数,才能作为虚函数被子类覆盖,而与子类中的virtual关键字无关

  • 虚函数在子类中的版本和基类中版本要具有相同的函数名,即函数名、参数表、常属性一致

  • 如果基类虚函数返回基本类型的数据,那么子类中的版本必须返回相同类型的数据;如果基类虚函数返回类类型指针(A)或引用(A&),那么允许子类中的版本返回其子类类型指针(B)或引用(B&)

我们来重点看一下第三句话

简单的看一下实现的原理 

当一个基类中存在虚函数的时候, 派生类机会从基类那里将其继承过来, 当派生类中函数满足基类中虚函数的覆写条件的时候, 就会将自己的虚函数表原先基类中的虚函数地址给替换成自己的函数地址, 这样, 不同的派生类只要是满足了虚函数的调用条件, 调用虚函数的时候, 调用的就是自己虚函数表中的那个自己实现的函数, 从而实现了多态。

从上面我们可以看出, 多态的实现其实就是将继承过来的虚函数表中原先的函数地址, 换成了自己的函数地址。

⑤, 问题

简单讲一下什么是多重继承, 就是一个类继承了多个基类。

在C++中,当进行多重继承时,子类中会有多个虚函数表指针,并且也会有多个虚函数表

首先,我们来理解虚函数表指针和虚函数表的概念。在C++中,如果一个类定义了至少一个虚函数,那么这个类就会拥有一个虚函数表(vtable),它存储了该类所有虚函数的地址。而虚函数表指针(vptr)是指向这个虚函数表的指针,它存在于每个拥有虚函数的类的实例中。

在多重继承的场景中,每个含有虚函数的基类都会为子类贡献一个虚函数表和对应的虚函数表指针。因此,如果一个子类从两个或多个含虚函数的基类继承而来,那么它就会拥有与这些基类数量相同的虚函数表指针。这些虚函数表指针的顺序与继承的顺序一致。

至于虚函数表的数量,如果子类没有新增虚函数,那么多重继承的子类会将全部基类的虚函数表继承下来。如果子类新增了虚函数,则这些新的虚函数会被添加到继承的第一个基类的虚函数表中,除非存在虚函数的重写,这种情况下新的虚函数会覆盖掉基类原有的虚函数

综上所述,在C++多重继承的情况下,子类中的虚函数表指针数量等于其含虚函数的基类数量,而虚函数表的数量则取决于子类是否新增了虚函数以及是否重写了继承自基类的虚函数。

好了, 以上就是全部内容, 图片资源部分来自网络, 如有侵权, 请联系我, 将其删除。

相关文章:

C++多态实现原理详解

阅读引言&#xff1a; 我想象了一下&#xff0c; 假如人有突然问我什么是多态&#xff0c; 我该如何给别人说清楚呢&#xff1f;所以写下这篇文章&#xff0c; 希望大家看完有所收获。 ①. 开胃小菜 先看这样一个开胃小菜 这里我有点小小的疑惑&#xff0c; 大小为啥是1。 在C…...

[数据集][目标检测]交通灯检测数据集VOC+YOLO格式2600张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2600 标注数量(xml文件个数)&#xff1a;2600 标注数量(txt文件个数)&#xff1a;2600 标注…...

关于测试用例

目录 一 测试用例介绍 二 写用例的好处 三 不适合写用例的情况 一 测试用例介绍 测试用例由测试来写&#xff0c;编写时间在需求评审和设计评审&#xff08;如有&#xff09;结束后&#xff0c;需求提测前&#xff0c;用例依赖需求文档来编写。一般包含用例标题&#xff0c…...

一起长锈:3 类型安全的Rust宏(从Java与C++转Rust之旅)

讲动人的故事,写懂人的代码 故事梗概:在她所维护的老旧Java系统即将被淘汰的危机边缘,这位在编程中总想快速完事的女程序员,希望能转岗到公司内部使用Rust语言的新项目组,因此开始自学Rust;然而,在掌握了Rust编程知识之后,为了通过Rust项目组的技术面试,使得转岗成功而…...

《金融研究》:普惠金融改革试验区DID工具变量数据(2012-2023年)

数据简介&#xff1a;本数据集包括普惠金融改革试验区和普惠金融服务乡村振兴改革试验区两类。 其中&#xff0c;河南兰考、浙江宁波、福建龙岩和宁德、江西赣州和吉安、陕西铜川五省七地为普惠金融改革试验区。山东临沂、浙江丽水、四川成都三地设立的是普惠金融服务乡村振兴…...

Prompt|Kimi高阶技巧,99%的人都不知道

大家好&#xff0c;我是无界生长。 今天分享一条咒语&#xff0c;轻松让Kimi帮你生成流程图&#xff0c;学会了的话&#xff0c;点赞收藏起来吧&#xff01; 效果展示 我们演示一下让kimi帮忙绘制 关注微信公众号“无界生长”的流程图&#xff0c;最终效果图如下所示 效果还不…...

采购管理软件:采购自动化提高效率的5种方式

在采购领域&#xff0c;手动数据输入和耗时的文书工作的时代已经落后了。采购自动化正在改变游戏规则&#xff0c;使企业能够简化流程、降低成本并提高效率。 以下是采购自动化帮助企业提高效率的5种方法。 采购管理软件,采购自动化管理,8Manage SRM,高亚科技 减少手动流程和…...

Android App开机启动

清单文件 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"><uses-permission android:name"andro…...

服务器直连电脑(盒子直连电脑)电脑需要设置为固定ip才能访问盒子

文章目录 现象盒子设置为固定ip&#xff0c;pc设置成固定ip&#xff08;以太网网卡&#xff0c;realtak那个&#xff0c;不是tap-windows那个&#xff0c;tap-windows不用管&#xff09;&#xff0c;在pc上用ip搜索工具搜索&#xff0c;可以搜到盒子ip。盒子设置为固定ip&#…...

【设计模式】之代理模式(两种)

系列文章目录 &#xff08;其他设计模式可以参考 &#x1f449;&#x1f449;&#x1f449;&#xff09;设计模式_小杰不秃头的博客 &#x1f60a;&#x1f604;&#x1f61b; 前言 今天继续给大家介绍23种设计模式中的代理模式&#xff0c;熟悉Spring的小伙伴都知道&#xf…...

【工具篇】-什么是.NET

“.NET"&#xff1a;.NET Core是由Microsoft开发&#xff0c;目前在.NET Foundation(一个非营利的开源组织)下进行管理。.NET Core是用C#和C编写的&#xff0c;并采用MIT协议作为开源协议。 简单来说&#xff1a;就是开发框架。 .NET 又称 .NET 平台或 .NET 框架&#xf…...

OmniReader Pro mac激活版:智慧阅读新选择,开启高效学习之旅

在追求知识的道路上&#xff0c;一款优秀的阅读工具是不可或缺的。OmniReader Pro作为智慧阅读的新选择&#xff0c;以其独特的功能和卓越的性能&#xff0c;为您开启高效学习之旅。 OmniReader Pro具备高效的文本识别和处理技术&#xff0c;能够快速准确地提取文档中的关键信息…...

Stable Diffusion学习记录

文章目录 前言电脑配置推荐环境搭建下载地址安装步骤步骤一&#xff0c;打开下载的秋叶整合包&#xff0c;路径秋叶整合包/sd-wenui-aki步骤二&#xff0c;打开下载好的sd-webui-aki-v4.8.7解压包 Stable Diffusion软件配置&#xff0c;插件安装&#xff0c;模型下载Stable Dif…...

安装openssh-server,提供远程ssh

安装openssh-server&#xff0c;提供远程ssh 1.检查自己是否安装了openssh-server dpkg -l | grep ssh如果输出内容有openssh-server&#xff0c;说明已经安装过了&#xff0c;可以跳过下一步 2.安装openssh-server 由于ubuntu自带ssh客户端&#xff0c;只需要安装openssh-se…...

华纳云:选择数据库服务器你需要注意的5个原则

选择数据库服务器时&#xff0c;有几个关键原则需要注意&#xff0c;以确保选择的服务器能够满足你的需求并提供可靠的性能和安全性。 1. 性能需求 考虑你的应用程序对性能的需求&#xff0c;包括处理能力、内存、存储和网络带宽等方面。根据应用程序的负载和预期的并发访问量&…...

Linux动态库与静态库解析

文章目录 一、引言二、C/C源文件的编译过程三、静态库1、静态库的定义和原理2、静态库的优缺点3、静态库的创建和使用a、创建静态库b、使用静态库 四、动态库1、动态库的定义和原理2、动态库的优缺点3、动态库的创建和使用示例a、创建动态库b、使用动态库 五、动静态库的比较 一…...

后端的一些科普文章

后端开发一般有4个方面 后端开发流程 1阶段 域名认证 是每一个计算机在网络上有一个ip地址&#xff0c;可以通过这个地址来访问102.305.122.5&#xff08;举例&#xff09;&#xff0c; 但是这个公网ip地址&#xff0c;比较难记忆&#xff0c;所以大家使用域名来更好的记忆…...

【Android学习】日期和时间选择对话框

实现功能 实现日期和时间选择的对话框&#xff0c;具体效果可看下图(以日期为例) 具体代码 1 日期对话框 1.1 xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android&quo…...

在Linux上使用Selenium驱动Chrome浏览器无头模式

大家好&#xff0c;我们平时在做UI自动化测试的时候&#xff0c;经常会用到Chrome浏览器的无头模式&#xff08;无界面模式&#xff09;&#xff0c;并且将测试代码部署到Linux系统中执行&#xff0c;或者平时我们写个爬虫爬取网站的数据也会使用到&#xff0c;接下来和大家分享…...

Feign 第一次调用为什么会很慢?

feign调用的大致过程&#xff1f; Feign进行远程调用的&#xff0c;这里面包括&#xff0c;注册中心、负载均衡、FeignClient之间的关系&#xff0c;微服务通过不论是eureka、nacos也好注册到服务端&#xff0c;Feign是靠Ribbon做负载的&#xff0c;而Ribbon需要拿到注册中心的…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...