【C++学习手札】一文带你认识C++虚函数(内层剖析)

news2024/12/22 6:19:06

                                        食用指南:本文在有C基础的情况下食用更佳  

                                       🍀本文前置知识: C++初识继承

                                       ♈️今日夜电波:No title —REOL

                                                                1:02 ━━━━━━️💟──────── 4:03
                                                                    🔄   ◀️   ⏸   ▶️    ☰ 

                                      💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍 


目录

✅虚函数的概念

⭕虚函数的结构

定义

内层结构(重要)

☑如何查看类的内层结构

✔虚函数的应用案例


 ✅虚函数的概念

        C++面向对象中的多态性是指同一种类型的对象在不同的情况下表现出不同的行为。这种多态性可以通过虚函数来实现。在C++中,虚函数是指在基类中声明的函数,在派生类中可以被重写,从而实现不同的行为。当使用基类指针或引用调用虚函数时,实际调用的是派生类中重写的函数,而不是基类中的函数。 通过使用虚函数,可以实现运行时多态性,即在程序运行时才确定调用哪个函数,而不是在编译时确定。这种多态性可以提高程序的灵活性和可扩展性,使得程序更加易于维护和扩展。

      简而言之,就是用父类型别的指针指向其子类,然后通过父类的指针调用实际子类的成员函数。

        🌰

class Animal
	 {
 public:
	 void sleep(void)
		 {
		 cout << "animal 动物在睡觉" << endl;
		 }
	 };

 class Cat :public Animal
 {
 public:
	 void sleep(void)
		 {
		 cout << "Cat 猫在睡觉!! 喵喵" << endl;
		 }
	 };
 void test01()
 {
	 //用基类(指针或引用) 保存 子类对象(向上转换)
		 Animal * p = new Cat;
	 p-> sleep();//调用的是基类的sleep
	
		 Cat cat;  Animal & ob = cat;
	 ob.sleep();//调用的是基类的sleep
 }

        在这个例子中,我们想实现的功能是什么呢?我们用的是父类的指针指向了子类的空间,想要调用其中的成员函数,但是事实真的如我们所愿吗?请看以下运行结果:

         可以看到我们实际上调用的都是父类中的成员函数,而这也是C++继承在作祟。对此,我们使用虚函数!(仅仅只是加了一个 virtual)

class Animal
	 {
 public:
	 virtual void sleep(void)
		 {
		 cout << "animal 动物在睡觉" << endl;
		 }
	 };

运行结果又是如何呢?如下:

         这是什么原因呢?这就要提到虚函数的结构了!

虚函数的结构

        定义

virtual 函数(包涵返回值、参数等等(就是在前面多加了个virtual))

        内层结构(重要)

        我们使用Develop Command Prompt for VS 2022 打开相应的类结构,如下为加了virtual的父类Animal

        vfptr是虚函数指针 指向的是虚函数表(vftable)
        vftable表存放的是 vfptr做保存的函数入口地址

         一图让你明白~

         当函数前加了virtual后会自动生成一个vfptr指针以及一个vftable,虚函数指针会指向这个虚函数表,而函数表中通常储存着虚函数入口的地址。而这些地址的存储也是有一定的规则的,他们通过序号以及当前的虚指针相对于虚基类的首地址的偏移量。当其中有多个虚函数时,以便找到相应的函数。

         重要的来了,那为啥当我们在父类指针中定义了虚函数,而在子类中就能实现用父类指针就可以访问子类的成员函数了呢?

        这是因为:当虚函数涉及到继承的时候 子类 会继承 父类的(虚函数指针vfptr 虚函数表vftable),编译器会将虚函数表中的函数入口地址 更新 成子类的 同名(返回值、参数都同)的函数入口地址。如果基类指针、引用 访问虚函数的时候 就会 间接的调用 子类的虚函数。

        二图让你明白~

        

 看到这里,相信你的好奇心起来了,如何查找类的结构呢?别急~接下来就分享给你(*╹▽╹*)


如何查看类的内层结构

        1、首先在你的任务栏中搜索        Develop Command Prompt for VS 2022   (2022是版本,你可以根据自己的版本变更)

         2、打开后回到你的VS执行以下操作

         3、回到 Develop Command Prompt for VS 2022,输入以下命令

        如果你的文件是在E盘 你首先得先进入E盘 所以输入 E: 如果是C盘则C:以此类推

在进入所在盘后,进入到对应的路径 cd + 路径 如下:

         4、输入对应的操作  

        cl /d1 reportSingleClassLayout+类名 类所在程序名.cpp

         如下:


虚函数的应用案例

        (基类指针、引用 作为函数的参数)

         🌰

#include <iostream>

using namespace std;

 class Base {
 public:
	 virtual void sleep(void)
		 {
		 cout << "父亲在睡觉" << endl;
		 }
	
};

 class Son1 :public Base
 {
 public:
	 void sleep(void)
		 {
		 cout << "Son1在安静的睡觉" << endl;
		 }
	 };
 class Son2 :public Base
 {
 public:
	 virtual void sleep(void)
		 {
		 cout << "Son2在轻度的睡觉" << endl;
		 }
	 };
 class Son3 :public Base
 {
 public:
	 virtual void sleep(void)
		 {
		 cout << "Son3在雨声般的睡觉" << endl;
		 }
	 };
 class Son4 :public Base
 {
 public:
	 virtual void sleep(void)
		 {
		 cout << "Son4在鼾声如雷" << endl;
		 }
	 }; 
	 //以基类指针作为函数的参数 函数可以操作该基类派生出的任意子类对象
		 void sleepFun(Base & ob)
		 {
		 ob.sleep();
		 }
		 
		 int main(int argc, char* argv[])
		 {
		 Son1 ob1;
		 Son2 ob2;
		 Son3 ob3;
		 Son4 ob4;
		 sleepFun(ob1);
		 sleepFun(ob2);
		 sleepFun(ob3);
		 sleepFun(ob4);
		 return 0;
		}

        运行结果如下:


                感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!  

                                 

                                                                 给个三连再走嘛~      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/894028.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无涯教程-Perl - use函数

描述 此函数将MODULE导出的所有功能(或仅LIST引用的功能)导入当前包的名称空间。有效等效于- BEGIN { require "Module.pm"; Module->import(); }也用于在当前脚本上强加编译器指令(编译指示),尽管从本质上讲它们只是模块。 请注意,use语句在编译时进行判断。在…

【网络】网络层——IP协议

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《网络》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 网络层中&#xff0c;IP协议首部和有效载荷组成的完整数据称为数据报。 IP协议 &#x1f349;TCP和IP的…

文件批量管理,如何将文件进行一一复制备份并删除原文件里的文件

您是否经常需要对大量的文件进行复制备份和删除操作&#xff1f;是时候拥有一款高效的文件批量管理工具了&#xff01;我们的一键批量管理软件为您提供了简单而强大的解决方案&#xff0c;让您轻松地进行文件复制备份并删除原文件&#xff0c;让存储空间得到高效整理&#xff0…

为什么浙大MBA项目提前批面试要控制优秀人数比例?

大家好&#xff01;时间来到八月份&#xff0c;不知道今年浙大MBA项目的提前批面试你是否已经申请参加过&#xff1f;从剩余批次来看&#xff0c;留给考生做选择的时间确实不是很多了&#xff0c;仅剩的几个批次中&#xff0c;只有杭州第五批目前时间上还算充裕&#xff0c;其余…

Talk | ACL‘23 杰出论文奖上海交通大学吴蔚琪:预训练语言模型对本体知识的记忆与理解

本期为TechBeat人工智能社区第523期线上Talk&#xff01; 北京时间8月17日(周四)20:00&#xff0c;上海交通大学硕士研究生—吴蔚琪的Talk已准时在TechBeat人工智能社区开播&#xff01; 她与大家分享的主题是: “预训练语言模型对本体知识的记忆与理解”&#xff0c;分享了预训…

八股文之八大排序(C++)

目录 1.直接插入排序 2.希尔排序 3.简单选择排序 4.堆排序 5.冒泡排序 6.快速排序 7.归并排序 8.基数排序&#xff08;桶排序&#xff09; 9.主函数 10.画图总结 1.直接插入排序 int ai[] 为需要排序的数组 start 为起始位置&#xff0c;要求 start>1 ,因为 ai[0…

python基础4——类、异常处理、常用模块

文章目录 一、类二、python异常处理三、自定义模块3.1 保留模块测试代码3.2 添加模块使用说明 四、内置模块4.1 os标准库4.2 os.path类4.3 sys库4.4 platform库4.5 glob库4.6 random库4.7 subprocess库4.8 pickle库4.9 JSON库4.10 time库4.11 datetime库4.12 urllib库4.12.1 re…

Unity Android 之 使用 HanLP 进行句子段落的分词处理(包括词的属性处理)的简单整理

Unity Android 之 使用 HanLP 进行句子段落的分词处理&#xff08;包括词的属性处理&#xff09;的简单整理 目录 Unity Android 之 使用 HanLP 进行句子段落的分词处理&#xff08;包括词的属性处理&#xff09;的简单整理 一、简单介绍 二、实现原理 三、注意事项 四、效…

水泥厂人员定位方案

水泥厂人员定位方案可以采用不同的技术和策略。以下是一个常见的水泥厂人员定位方案的步骤&#xff1a; 1.选择合适的定位技术&#xff1a;根据水泥厂的需求和运营环境&#xff0c;选择适合的定位技术&#xff0c;例如基于UWB&#xff08;Ultra-Wideband&#xff09;、RFID&am…

无涯教程-Perl - undef函数

描述 此函数未定义EXPR的值。用于标量,列表,哈希,函数或类型范围。在带有诸如undef $hash {$key}之类的语句的哈希上使用&#xff1b;实际上将指定键的值设置为未定义的值。 如果要从哈希中删除元素,请使用delete函数。 语法 以下是此函数的简单语法- undef EXPRundef返回…

windows ipv4 多ip地址设置,默认网关跃点和自动跃点是什么意思?(跃点数)

文章目录 Windows中的IPv4多IP地址设置以及默认网关跃点和自动跃点的含义引言IPv4和IPv6&#xff1a;简介多IP地址设置&#xff1a;Windows环境中的实现默认网关跃点&#xff1a;概念和作用自动跃点&#xff1a;何时使用&#xff1f;关于“跃点数”如何确定应该设置多少跃点数&…

【3Ds Max】布料命令的简单使用

简介 在3ds Max中&#xff0c;"布料"&#xff08;Cloth&#xff09;是一种模拟技术&#xff0c;用于模拟物体的布料、织物或软体的行为&#xff0c;例如衣物、帆布等。通过应用布料模拟&#xff0c;您可以模拟出物体在重力、碰撞和其他外力作用下的变形和动态效果。…

【学习FreeRTOS】第11章——FreeRTOS中任务相关的其他API函数

1.函数总览 序号函数描述1uxTaskPriorityGet()获取任务优先级2vTaskPrioritySet()设置任务优先级3uxTaskGetNumberOfTasks()获取系统中任务的数量4uxTaskGetSystemState()获取所有任务的状态信息5vTaskGetInfo()获取单个任务的状态信息6xTaskGetCurrentTaskHandle()获取当前任…

利用Velero对K8S备份还原与集群迁移实战

一、简介 Velero 是一款云原生时代的灾难恢复和迁移工具&#xff0c;采用 Go 语言编写&#xff0c;并在 github 上进行了开源&#xff0c;利用 velero 用户可以安全的备份、恢复和迁移 Kubernetes 集群资源和持久卷。 开源地址&#xff1a;https://github.com/vmware-tanzu/v…

Element通过v-for循环渲染的form表单校验

需求&#xff1a;有个表单信息是v-for渲染的&#xff0c;例如下图&#xff0c;通过循环遍历实现新增和删除模块&#xff0c;按照平时的写法实现校验&#xff0c;是不能实现我们想要的效果&#xff0c;根据这个需求&#xff0c;我找到了一个解决方法 1.HTML <el-form ref&qu…

【抓包工具】whistle抓包工具分享

一、使用场景 抓包请求转发 二、基础篇 官网&#xff1a;http://wproxy.org/whistle/ github: https://github.com/avwo/whistle 简介&#xff1a; whistle(读音[ˈwɪsəl]&#xff0c;拼音[wēisǒu])基于Node实现的跨平台web调试代理工具&#xff0c;类似的工具有Window…

React 之 Router - 路由详解

一、Router的基本使用 1. 安装react-router react-router会包含一些react-native的内容&#xff0c;web开发并不需要 npm install react-router-dom 2. 设置使用模式 BrowserRouter或HashRouter Router中包含了对路径改变的监听&#xff0c;并且会将相应的路径传递给子组件Bro…

优化视频流:利用美颜SDK提升直播质量的方法

随着互联网的迅猛发展&#xff0c;视频直播已成为人们分享、交流和娱乐的重要方式。然而&#xff0c;在实际的直播过程中&#xff0c;视频画质可能受到诸多因素的影响&#xff0c;例如摄像头品质、网络状况等。为了提升观众的体验和吸引更多的观众&#xff0c;美颜技术逐渐成为…

8.18号transformer 系列文章阅读

文章目录 STGM: Spatio-Temporal Graph Mixformer for Traffic ForecastingAttention Is Not All You Need AnymoreLEARNING IMAGE DERAINING TRANSFORMER NETWORK WITH DYNAMIC DUAL SELF-ATTENTIONSST: A Simplified Swin Transformer-based Model for Taxi Destination Pred…

zookeeper安装配置采坑流程

安装 wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.2/apache-zookeeper-3.8.2-bin.tar.gz解压&#xff1a; tar -zxvf apache-zookeeper-3.8.2-bin.tar.gz如下 bin目录下文件是可执行文件 conf目录文件是配置文件 修改zoo.cfg&#xff08;复制zoo_sample&#x…