【多态】底层原理

embedded/2024/10/18 10:18:49/
图片名称

博主首页: 有趣的中国人

专栏首页: C++进阶


    本篇文章主要讲解 多态底层原理 的相关内容

      1. 多态原理

      1.1 虚函数表


      先看一下这段代码,计算一下sizeof(Base)是多少:

      class Base
      {
      public:virtual void Func1(){cout << "Func1()" << endl;}
      private:int _b = 1;char _ch = 'd';
      };
      

      我这里以32位机器为例:很多人会认为这里是8字节,但是肯定没那么简单,这里答案是12字节。为什么呢?

      在这里插入图片描述

      这里不但有两个成员变量,还有一个虚表指针:__vfptr: virtual function pointer

      在这里插入图片描述

      在一个含有虚函数的类中,一定会存在一个虚表指针,因为虚函数的地址会存放在虚表当中,那么派生类中的这个表都有什么呢?接着往下分析。


      上面的代码进行改造:

      1. 增加一个派生类Derive去继承Base
      2. Derive中重写Func1
      3. Base再增加一个虚函数Func2和一个普通函数Func3

      代码如下:

      class Base
      {
      public:virtual void Func1(){cout << "Base::Func1()" << endl;}virtual void Func2(){cout << "Base::Func2()" << endl;}void Func3(){cout << "Base::Func3()" << endl;}
      private:int _b = 1;
      };
      class Derive : public Base
      {
      public:virtual void Func1(){cout << "Derive::Func1()" << endl;}
      private:int _d = 2;
      };
      int main()
      {Base b;Derive d;return 0;
      }
      

      通过监视窗口观察,发现基类和派生类虚表指针的地址是不同的
      在这里插入图片描述
      在这里插入图片描述

      通过观察,我们发现,基类的虚函数表会复制到派生类的虚函数表中,如果派生类虚函数进行了重写,那么对应的虚函数地址就会改变,新函数地址会覆盖掉基类中的地址,因此重写又叫做覆盖。

      因此,多态是如何保证父类的指针调用虚函数就访问父类,派生类的指针调用虚函数就访问派生类的呢?
      在编译阶段,编译器会检查语法,看是否满足多态的两个条件:

      1. 虚函数重写
      2. 父类的指针或者引用调用虚函数

      如果满足,就会在链接阶段直接在虚表找到对应的函数地址并调用;
      如果不满足,就会在编译阶段根据类型确定函数的地址。
      以下是不构成重写的情况:

      class Person {
      public:// 这个函数没有进入虚函数表void BuyTicket() { cout << "买票-全价" << endl; }private:int _i = 1;
      };class Student : public Person {
      public:virtual void BuyTicket() { cout << "买票-半价" << endl; }int _j = 2;
      };void Func(Person* p)
      {p->BuyTicket();
      }int main()
      {Person Mike;Func(&Mike);Person p1;Func(&p1);Student Johnson;Func(&Johnson);return 0;
      }
      

      2. 打印虚表

      虚表本质上是一个函数指针数组,即是一个数组,存放的类型是函数指针类型,我们只需要知道函数指针数组的首地址就可以访问其中的所有元素了。
      我们同样知道__vfptr存放的就是首地址,取到他就好,这里可以用指针的强制转换。

      先看一下这段代码:

      class Base {
      public:virtual void func1() { cout << "Base::func1" << endl; }virtual void func2() { cout << "Base::func2" << endl; }
      private:int a = 1;
      };class Derive :public Base {
      public:virtual void func1() { cout << "Derive::func1" << endl; }virtual void func3() { cout << "Derive::func3" << endl; }virtual void func4() { cout << "Derive::func4" << endl; }
      private:int b = 2;
      };
      

      这里Derive中覆盖了Base中的func1,继承了Base中的func2fun3func4进入了虚表:
      在这里插入图片描述

      typedef void(*VFPTR)();
      void PrintVFT(VFPTR* vft)
      {for (int i = 0; i < 4; ++i){printf("%p->", vft[i]);VFPTR v = vft[i];(*v)();}
      }
      int main()
      {Base b;Derive d;VFPTR* ptr = (VFPTR*)(*((int*)(&d)));PrintVFT(ptr);return 0;
      }
      

      在这里插入图片描述


      http://www.ppmy.cn/embedded/10100.html

      相关文章

      分别用高斯消元法和列主元消去法求解,(自制)表格比较两种算法的结果与精度,分析实验出现的问题,并总结解决办法。

      以下是一个使用高斯消元法和列主元消去法求解线性方程组的示例&#xff1a; 假设我们要解决以下线性方程组&#xff1a; 4x 2y z 8 -2x y - 3z -11 3x - 2y 4z 10 首先&#xff0c;我们可以将该线性方程组表示为增广矩阵的形式&#xff1a; [4 2 1 | 8] [-2 1 -3 | …

      照片相似性搜索引擎Embed-Photos;赋予大型语言模型(LLMs)视频和音频理解能力;OOTDiffusion的基础上可控制的服装驱动图像合成

      ✨ 1: Magic Clothing Magic Clothing是一个以可控制的服装驱动图像合成为核心的技术项目&#xff0c;建立在OOTDiffusion的基础上 Magic Clothing是一个以可控制的服装驱动图像合成为核心的技术项目&#xff0c;建立在OOTDiffusion的基础上。通过使用Magic Clothing&#xf…

      mybatis使用xml中的if-else/choose

      最近需要使用 xml 文件来实现一些增删改查&#xff0c;此文对 其中的 if-else 加以说明 背景&#xff1a; 有一个引用类&#xff0c;假设叫 Student public class Student {private String name; private String address; private Integer yn;}现在我们查询条件也被封装成一个…

      论文笔记:Large Language Models Are Zero-Shot Time Series Forecasters

      2023 neurips 完全是零样本&#xff08;zero-shot&#xff09;的&#xff0c;不需要微调 1 方法 1.1 Tokenization&#xff08;分词和编码&#xff09; 现有的LLM&#xff08;比如GPT3&#xff09;的tokenizer不能直接用来编码时间序列的句子 比如对数字42235630&#xff0…

      GEE:基于光谱距离度量方法的巴以冲突造成的地表覆盖变化检测

      作者:CSDN @ _养乐多_ 本文将介绍如何在 Google Earth Engine (GEE) 平台中使用光谱距离度量方法进行地表覆盖变化检测,并以加沙地区为例,使用Sentinel2数据展示2023年3月和2024年3月的地表覆盖变化区域。 结果如下图所示, 文章目录 一、核心函数1.1 spectralDistance函数…

      高通发布电脑CPU,比英特尔Ultra9领先51%

      要说2024年最热门的关键词&#xff0c;那肯定非 AI 莫属&#xff0c;当前 AI 已经开始深入各行各业&#xff0c;AI 电视、AI 手机、AI 车机、AI 家电&#xff0c;以及 AI PC ,这些都意味着 AI 将对各个行业带来的新风向和不小的冲击。 2024 年了&#xff0c;PC 处理器还能卷出什…

      世界读书日:探索阅读的多样性样性——漫画、图解、图形化立体图书

      在当今信息爆炸的时代&#xff0c;阅读已经不再局限于传统的书籍形式。随着科技的发展和文化的多样化&#xff0c;人们可以通过多种形式来获取知识和享受阅读的乐趣。从漫画、图解到图形化立体图书&#xff0c;每一种形式都有其独特的魅力&#xff0c;适合不同类型的读者和学习…

      Podman容器的原理及应用详解(一)

      本系列文章简介&#xff1a; Podman是一个用于管理容器的工具&#xff0c;它提供了一种在Linux系统中运行和管理容器的替代方案。与传统的容器管理工具Docker不同&#xff0c;Podman使用了一种不需要守护进程的架构&#xff0c;这使得它更加轻量化、安全和易于使用。 Podman的核…