C++面向对象-23-多态原理剖析

短命女 2023-03-14 10:50 178阅读 0赞

前面一篇学习了多态,有静态多态和动态多态之分。动态绑定是第一需要继承关系,第二是子类需要重写父类的函数。什么是重写,从函数返回值,函数名称和参数列表一模一样才叫函数重写。本篇就借助vs 开发工具来捋一捋多态的底层原理。

1.两个单词概念

在前面多继承的时候,我们也介绍了虚继承,其中使用了virtual,当时有vbptr虚基类指针和vbtable虚基类表,其中作用是vbptr指向了vbtable。这次多态底层原理学习也需要理解类似的两个概念。

虚函数指针 vfptr,vritual function pointer

虚函数表 vftable, virtual function table

虚函数指针的作用是指向虚函数表。

2.不带virtual的Animal类占内存大小

代码和前面一篇一样,当前这里操作需要删除代码中Animal基类虚函数前面vritual,先看看这个父类不带virtual所占内存大小

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE1NDE5NDY_size_16_color_FFFFFF_t_70

不带virtual,而且当前Anima类没有什么成员变量,所以所占内存就1个字节。

2.带virtual的Animal类占内存大小

在Animal基类中加上virtual,运行上面命令,看看占内存是多少

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE1NDE5NDY_size_16_color_FFFFFF_t_70 1

加上virtual关键字之后,所占内存为4字节,不用怀疑和乱猜测,这里四个字节就是一个指针大小,前面学习过,任何类型的指针所占内存大小都是4字节,这里这个指针就是vfptr,也就是文章开头的虚函数指针。注意上面,这个vfptr指向vftable,在虚函数表中,当前存储的是 &Animal::speak,Animal::这个是作用域,表示存储的是Animal类的speak函数,前面加上&符号,就表示Animal类中speak函数的地址。

3.静态绑定的时候子类Cat中存储内容

现在我们又来去除基类Animal中虚函数前面的关键字virtual,把上面命令变成查询子类Cat的继承关系情况。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE1NDE5NDY_size_16_color_FFFFFF_t_70 2

这个时候,子类中可以看到父类是Animal, 而且子类所占内存大小1字节,这里没有vfptr,也就是虚函数指针,子类继承父类的全部,所以调用speak函数,输出的内容是父类中speak函数的结果。

4.动态绑定子类Cat中存储的内容

把前面删除关键字virtual添加回来,再次查询子类Cat的继承关系

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE1NDE5NDY_size_16_color_FFFFFF_t_70 3

这个时候动态绑定,子类Cat中显示父类是Animal, 还有一个虚函数指针,这个是父类继承过来的,所以字节大小是4。这个时候虚函数指针指向虚函数表,此时虚函数表中存储的是&Cat::speak 这个很清楚写明白了,存储的是子类Cat作用域下speak函数的内存地址。所以,动态绑定下,doSpeak函数传入参数是什么子类对象,就调用该子类对象中的speak方法。因为虚函数表中用子类中的同名函数覆盖了原来父类的虚函数。

发表评论

表情:
评论列表 (有 0 条评论,178人围观)

还没有评论,来说两句吧...

相关阅读

    相关 C++面向对象-23-原理剖析

    前面一篇学习了多态,有静态多态和动态多态之分。动态绑定是第一需要继承关系,第二是子类需要重写父类的函数。什么是重写,从函数返回值,函数名称和参数列表一模一样才叫函数重写。本篇就

    相关 面向对象

    面向对象—多态 定义 实现 原理 1、定义 > 多态可以简单的概括为“一个接口,多种方法”,在程序运行过程中才决定调用的函数,简单的说就是,允许

    相关 面向对象

    多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。 编译时的多态性: 编译时的多态性是通过重

    相关 面向对象---

    多态: > 可以理解为事物存在的多种体现形态。 > 比如:人:男人,女人 多态的体现: > 父类的引用指向了自己的子类对象。 > > 父类的引用也可以接受自己的对象。