C++ 多态虚函数的底层原理深入理解

 更新时间:2022年08月05日 11:01:41   作者:炼丹之路​​​​​​​  
这篇文章主要介绍了C++ 多态虚函数的底层原理深入理解,多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为,通常是父类调用子类的重写函数,在C++中就是 父类指针指向子类对象,此时父类指针的向下引用就可以实现多态

多态的基本概念

1.1 什么是多态?

  • 多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为,通常是父类调用子类的重写函数,在C++中就是 父类指针指向子类对象,此时父类指针的向下引用就可以实现多态

比如看下面的代码:

class Animal
{
public:
  //虚函数
  virtual void speak()
  {
    cout << "动物在说话" << endl;
  }

  virtual void eat(int a )
  {
    cout << "动物在吃饭" << endl;
  }
};

class Cat :public Animal
{
public:
  void speak()
  {
    cout << "小猫在说话" << endl;
  }

  void eat(int a)
  {
    cout << "小猫在吃饭" << endl;
  }
};
class Dog :public Animal
{
public:
  void speak()
  {
    cout << "小狗在说话" << endl;
  }
};

这两个类实现集成关系,简单来说就是 Animal是父类,Cat是子类,通过父类引用调用子类函数,这就是多态(字面意思就是一个对象多个状态),这样就 符合** 高内聚低耦合** 的设计原则,更容易 后期维护与修改

1.2 怎么实现多态

说了这么多,那么多态到底怎么实现呢?

  • 想必上面代码中也已经透露出了一些信息,并且十分关键。没错,就是virtual,字面意思是 虚拟的,而也的确如此,这个关键字修饰的 函数,叫做虚函数,拥有虚函数的 类,被称为 抽象类(虚类),virtual是实现多态的必要不充分条件
  • 同时 ,子类要重写父类的虚函数,什么叫重写?就是函数类型,函数名,参数列表完全相同。
  • 并且父类指针还要指向子类对象,

正如下所示:

void doSpeak(Animal & animal) //Animal & animal = cat;
{
  animal.speak();
}

void test01()
{
  Cat cat;
  doSpeak(cat);

  Dog dog;
  doSpeak(dog);
}

如此方能满足实现多态的三个条件:

  • 注:如果没有多态,那么父类指向子类时就无法调用子类函数,也就是此时该函数地址早就绑定好了,只能是animal说话,属于静态联编(静态);如果想调用小猫说话,这个时候函数的地址就不能早就绑定好,而是在运行阶段再去绑定函数地址,属于地址晚绑定,叫动态联编,(动态)多态的实现就是依靠动态联编。

2 虚函数的底层原理

那么虚函数到底是怎么工作的呢?

void test02()
{
  Animal * animal = new Cat;
  ((void(*)()) (*(int *)*(int *)animal)) ();
  typedef void( __stdcall *FUNPOINT)(int);
  (FUNPOINT (*((int*)*(int*)animal + 1)))(10);
}
  Animal * animal = new Cat;

就是animal->speak();

  ((void(*)()) (*(int *)*(int *)animal)) ();

这里 *(int *)animal 解引用到虚函数表中,先将animal类型的指针强转为int *,然后解引用得到int类型的值放到虚函数表中,然后偏移相应位置指向speak()

 ((void(*)()) (*(int *)*(int *)animal)) ();

调用猫说话,因为C/C++默认调用惯例 __cdecl,而用下列调用时 是__stdcall

typedef void( __stdcall *FUNPOINT)(int);
(FUNPOINT (*((int*)*(int*)animal + 1)))(10);

到此这篇关于C++ 多态虚函数的底层原理深入理解的文章就介绍到这了,更多相关C++ 多态虚函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++文件关键词快速定位出现的行号实现高效搜索

    C++文件关键词快速定位出现的行号实现高效搜索

    这篇文章主要为大家介绍了C++文件关键词快速定位出现的行号实现高效搜索,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • 解析sizeof, strlen, 指针以及数组作为函数参数的应用

    解析sizeof, strlen, 指针以及数组作为函数参数的应用

    本篇文章是对sizeof, strlen, 指针以及数组作为函数参数的应用进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 380行C++代码实现扫雷小游戏

    380行C++代码实现扫雷小游戏

    这篇文章主要为大家详细介绍了380行C++代码实现扫雷小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-01-01
  • Qt音视频开发之音频播放QAudioOutput的实现

    Qt音视频开发之音频播放QAudioOutput的实现

    这篇文章主要为大家详细介绍了如何利用Qt实现音频播放QAudioOutput功能,文中的示例代码讲解详细,对我们学习Qt开发有一定的帮助,需要的可以参考一下
    2023-03-03
  • C语言之选择分支语句详解

    C语言之选择分支语句详解

    大家好,本篇文章主要讲的是C语言之选择分支语句详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • Qt增加版本公司等信息两种方式

    Qt增加版本公司等信息两种方式

    在项目中生成exe或者动态库过程中可能需要加入公司信息、版本号、说明等等,下面这篇文章主要给大家介绍了关于Qt增加版本公司等信息的两种方式,需要的朋友可以参考下
    2024-01-01
  • C++堆和栈的区别与联系讲解

    C++堆和栈的区别与联系讲解

    今天小编就为大家分享一篇关于C++堆和栈的区别与联系讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • 详解C++虚函数表存储位置

    详解C++虚函数表存储位置

    相信大家知道虚表指针和虚函数存储的位置,但对于虚函数表的存储位置一时无法确定。本文就来和大家详细聊聊相关内容,希望对大家有所帮助
    2023-04-04
  • C++实现转置矩阵的循环

    C++实现转置矩阵的循环

    大家好,本篇文章主要讲的是C++实现转置矩阵的循环,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2022-01-01
  • VC判断一个文件为目录的方法

    VC判断一个文件为目录的方法

    这篇文章主要介绍了VC判断一个文件为目录的方法,在Windows应用程序设计中非常具有实用价值,需要的朋友可以参考下
    2014-10-10

最新评论