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

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

                                        食用指南:本文在有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();//调用的是基类的sleepCat 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.lryc.cn/news/128582.html

相关文章:

  • Python“牵手”1688商品评论数据采集方法,1688API申请指南
  • “深入解析JVM内部机制:探秘Java虚拟机的奥秘“
  • 【系统工具】开源服务器监控工具WGCLOUD初体验
  • powerBI应用技巧
  • RK3568背光调试分享
  • Numpy入门(2)—随机数
  • ansible的playbook剧本
  • 【03 英语语法:从句(名词从句、定语从句/形容词从句、状语从句/副词从句)】
  • vue动态修改audio地址
  • CF113A Grammar Lessons 题解
  • puzzle(0414)六边形拼图
  • 回归预测 | MATLAB实现基于SAE堆叠自编辑器多输入单输出回归预测
  • BEV感知实时构建路口拓扑 觉非科技基于MapTR的优化与实践
  • 如何在TikTok“点火”?用时下最流行的工具解码赚钱
  • set NOCOUNT on
  • 垃圾回收机制
  • Golang 程序性能优化利器 PGO 详解(一):简单介绍及使用
  • redis key操作的相关命令
  • WebRTC | 网络传输协议RTP与RTCP
  • 160. 相交链表
  • 【MFC】12.双缓冲序列化机制-笔记
  • Linux 终端会话中,启动任务并放到后台运行
  • 软考笔记——10.项目管理
  • 算法与数据结构(二十四)最优子结构原理和 dp 数组遍历方向
  • Java Vue Uniapp MES生产执行管理系统
  • 深入探究Socks5代理与IP代理在网络安全与爬虫中的应用
  • Vue使用jspdf和html2canvas组件库结合导出PDF文件
  • 7. 实现 API 自动生成
  • 使用Druid解析SQL,获取SQL中所有使用的表
  • 公司内部测试团队可以替代专业的软件检测机构吗,性能测试怎么收费?