前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >动态多态原理浅析(C++)

动态多态原理浅析(C++)

作者头像
LonelyEnderman
发布2022-10-27 14:05:19
3200
发布2022-10-27 14:05:19
举报

前言

多态主要分为两类:

  • 静态多态:地址早绑定,即编译阶段确定函数地址,例如函数重载运算符重载
  • 动态多态:地址晚绑定,即运行阶段确定函数地址

动态多态

使用条件

父类指针或引用指向子类对象

基础语法

引入一段代码示例:

代码语言:javascript
复制
#include<iostream>
using namespace std;
class Animal
{
public:
    void speak()
    {
        cout << "动物在叫" << endl;
    }
};
class Cat :public Animal
{
public:
    void speak()
    {
        cout << "猫在叫" << endl;
    }
};
void doSpeak(Animal& animal)    //Animal& animal = cat
{
    animal.speak();     //地址早绑定
}
void test01()
{
    Cat cat;
    doSpeak(cat);   //父类引用/指针指向子类对象
    cout << "Animal类占用内存:" << sizeof(Animal) << endl;
}
int main()
{
    test01();
    system("pause");
}

运行结果为:

file
file

程序期望输出Cat类的speak方法,也即输出内容为猫在叫

可以看到实际输出与期望不符,原因是speak()在编译阶段已经确定了地址,无法通过父类指针指向子类对象,解决思路即是将早绑定改为晚绑定,让speak()在运行阶段正确指向子类对象,将Animal类的代码改成如下:

代码语言:javascript
复制
class Animal
{
public:
    virtual void speak() //virtual修饰后变成虚函数
    {
        cout << "动物在叫" << endl;
    }
};

修改后的运行结果为:

file
file

加入virtual关键词后,speak()变为虚函数,子类中的speak()无需添加virtual关键字(但也为虚函数)

此时speak()正确指向Cat类,由此可以得出多态满足的条件:

  • 有继承关系
  • 子类重写父类中的虚函数

修改之前的Animal类占用内存为1字节,说明此时为空类(空类占用1字节),修改之后的占用变为4字节,可知加入virtual关键词后,类内部结构发生了变化,不难猜出此时类中存在一个指针

实现原理

为了直观看到Animal类内部结构,借助VS自带的命令提示工具,到源文件存放目录后运行cl /d1 reportSingleClassLayoutAnimal test.cpp,结果如下:

file
file

可以看到类内存在一个大小为4的vfptr,也即是virutal function pointer-虚函数(表)指针,该指针指向下方的vftable,也即是virtual function table-虚函数表,该表中存放的speak()实际地址是&Animal::speak

重复上述操作,继续查看Cat类内部结构:

file
file

可以看到重写后,Cat类中的虚函数表内实际存储的函数地址为&Cat::speak

图示

为方便理解,另附一张示意图

file
file
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-6-24 0,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 动态多态
    • 使用条件
      • 基础语法
        • 实现原理
          • 图示
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档