本篇涉及内容:

  • 多态的定义
  • 虚函数
  • 静态绑定和动态绑定

多态的定义:

多态分为两类

  • 静态多态:在同一个类中,函数重载运算符重载都属于静态多态,即函数在相同的函数名情况下,存在着不同的状态,体现了多态特征.
  • 动态多态:一个父类可能会有多个子类,当子类重写了父类的虚函数后,用父类引用or指针指向子类对象,调用重写的函数时,会根据子类对象的不同来动态调用被重写的函数.

虚函数:

  • 虚函数指针:当一个类中存在虚函数时,这个类就当且仅当存在一个虚函数指针(4个字节大小),虚函数指针指向的是这个类独有虚函数表.
  • 虚函数表:一个类对应一个虚函数表,这个表中记录了本类中所有虚函数地址.

我们来看一段代码:

class Animal {public:virtual void speak() {cout << "动物在说话!" << endl;}
};class Cat : public Animal {public:void speak() {cout << "猫咪在说话!" << endl;}
};

根据这段代码来画一下Animal类和Cat类中的内部结构

有几点需要注意:

  1. 父类中的虚函数指针也能被子类继承过去
  2. 一个类中无论有多少个虚函数,这个类中的虚函数指针当且仅当只有一个.
  3. 一个类有多个实例化对象时,每个对象的虚函数指针指向的都是同一张虚函数表.
  4. 子类从父类那边继承过来的虚函数,在子类虚函数表中的地址依旧是父类中的地址.
  5. 子类如果重写了父类的虚函数,那么子类虚函数表中的原来的父类虚函数的地址会被重写的函数地址覆盖掉,如果子类中没有实现虚函数重写,那么其虚函数表保存的还是父类中的虚函数地址.

静态绑定和动态绑定:

  • 静态绑定
    在编译期就确定调用具体函数称为“静态绑定”又称先期联编,实现”静态绑定“的机制有:函数重载、运算符重载

  • 动态绑定
    在运行期才确定调用哪个函数称为“动态绑定”又称迟后联编,实现”动态绑定“的机制是通过虚函数

我们先来看一段代码

class Animal {public:void speak() {cout << "动物在说话!" << endl;}
};class Cat : public Animal {public:void speak() {cout << "猫咪在说话!" << endl;}
};void main() {Cat cat;Animal& animal = cat;animal.speak();
}

我们可以看见Animal类和Cat类之间是父类和子类关系,因此可以有Animal& animal = cat;,在Animal类和Cat类中都有speak函数,那么用animal这个引用调用speak函数,是执行的Animal类中的speak函数还是Cat类中的speak函数呢?

由打印结果可以知道执行的Animal类中的speak函数,下面让我们修改一下代码,把Animal类中的speak函数前上virtual关键字,再来看看打印结果是啥.

class Animal {public:virtual void speak() {cout << "动物在说话!" << endl;}
};class Cat : public Animal {public:void speak() {cout << "猫咪在说话!" << endl;}
};void main() {Cat cat;Animal& animal = cat;animal.speak();
}


此时用animal引用调用的speak函数是Cat类中的speak函数,为什么会出现这样的情况?下面来详细介绍.

1)当成员函数不是虚函数的时候

//此时Animal类中的speak函数为普通成员函数
Cat cat;
Animal& animal = cat;
animal.speak();

此时在编译期会根据引用or指针类型来确定调用哪个函数,由于animal这个引用的类型为Animal,而speak函数又为普通的成员函数,所以通过静态绑定确定调用的函数为Animal类中的speak函数.

2)当成员函数为虚函数时

//此时Animal类中的speak函数为普通成员函数
Cat cat;
Animal& animal = cat;
animal.speak();

此时在编译期阶段上述代码并不能确定调用的是父类还是子类中的speak函数,只有在程序运行期阶段,根据引用or指针指向的对象中的虚函数指针,找到对应的虚函数表,得到函数地址才能知道调用哪个方法,此时通过引用or指针调用的函数确定与引用or指针类型无关.

简单的说
当用父类型引用or指针指向子类型对象时:

  • 通过引用or指针调用普通成员函数,在编译期已经确定了调用的是父类的函数.
  • 通过引用or指针调用虚函数,在运行期根据指向的对象来调用子类对象中的函数.

注意动态绑定的触发条件:

  1. 要求父类型引用or指针指向子类型对象
  2. 父类型中有虚函数
  3. 子类重写父类的虚函数
  4. 用这个父类型引用or指针调用虚函数

C++多态(一)——多态的定义、虚函数、静态绑定和动态绑定相关推荐

  1. 【C++grammar】多态、联编、虚函数

    目录 1.多态概念 1.多态性有两种表现的方式 2.联编(实现多态) 1.静态联编 2.动态联编 3.实现运行时多态 1.为何要使用运行时多态? 2.如何实现运行时多态 3.多态的例子 1.调用哪个同 ...

  2. 初入c++(六)虚函数实现多态,虚析构函数,虚函数表和多态实现机制,纯虚函数。

    1.c++多态的概念以及用途. 1.1虚函数实现多态 通过基类指针只能够访问派生类的成员变量,不能够访问派生类的成员函数. 解决问题的办法:使用虚函数(virtual function),只需要在函数 ...

  3. 猿创征文|深入剖析多态的实现原理与虚函数指针

    学习导航 一.多态实现原理 二.不同情况下的虚函数表 (1)单继承无虚函数覆盖 (2)单继承有虚函数覆盖 (3)多继承无虚函数覆盖 (4)多继承有虚函数覆盖 三.对虚函数指针与虚函数表的深入理解 (1 ...

  4. C++ 多态(二) : 虚函数、静态绑定、动态绑定、单/多继承下的虚函数表

    文章目录 ⏰1.多态的原理--虚函数表

  5. C++多态中虚函数的深入理解

    c++中动态多态性是通过虚函数来实现的.静态多态性是通过函数的重载来实现的,在程序运行前的一种早绑定,动态多态性则是程序运行过程中的一种后绑定.根据下面的例子进行说明. #include <io ...

  6. 多态指针访问虚函数不能被继承的类快速排序N皇后问题插入排序堆排序merge归并排序栈上生成对象两个栈实现一个队列...

    多态 /*1. 要想实现覆盖(重写)父类必须声明为virtual,子类可以不声明为virtual.-->FunB()2. 派生类重写基类的虚函数实现多态,要求函数名.参数列表.返回值完全相同.( ...

  7. 【C++ 语言】面向对象 ( 继承 | 重写 | 子类调用父类方法 | 静态多态 | 动态多态 | 虚函数 | 纯虚函数 )

    文章目录 类的继承 方法的重写 子类中调用父类方法 多态 虚函数 虚函数示例 纯虚函数 相关代码 类的继承 1. 继承表示 : C++ 中继承可以使用 ":" 符号 , 格式为 & ...

  8. C++中类的多态与虚函数的使用(转)

    C++中类的多态与虚函数的使用 http://www.cnblogs.com/fangyukuan/archive/2010/05/30/1747449.html 类的多态特性是支持面向对象的语言最主 ...

  9. C++中类的多态与虚函数的使用

    C++中类的多态与虚函数的使用 http://www.cnblogs.com/fangyukuan/archive/2010/05/30/1747449.html 类的多态特性是支持面向对象的语言最主 ...

最新文章

  1. 在Android界面上显示和获取Logcat日志输出
  2. CentOS 7 解决丢失 nginx.pid 1
  3. Outlook 阅读窗格(Reading Pane)
  4. 请教各位 android activity之间切换的问题
  5. ubuntu下Pure-FTPd的安装和配置
  6. python—gc.collect()清楚内存
  7. Codeproject收藏
  8. 计算机软件毕业论文教师指导记录,毕业论文导师指导记录【毕业论文指导记录(精选多篇)】...
  9. win7系统升级到ie11浏览器(常见错误,升级经验)
  10. linux镜像文件iso下载RedHat,RedHat Enterprise Linux ISO文件下载镜像站点
  11. Leetcode刷题之旅--剑指 Offer 17. 打印从1到最大的n位数
  12. 当下社会和经济形势概述
  13. WORD打开很慢的解决办法[整理]
  14. 分享一个stm8s003单片机的ADC转换,附加一个冒泡算法(用于减少误差)
  15. 论文笔记(精读文章) - Invisible Backdoor Attack with Sample-Specific Triggers
  16. 从npm、npx说起,到shell
  17. 2022/1/23(每周总结)
  18. 解决Invalid HTTP_HOST header: ‘xxx.xx.xxx.xxx:8000‘. You may need to add ‘xxx.xx‘ to ALLOWED_HOSTS问题
  19. CES 2017媒体日:VR AR波澜不惊,无人驾驶和智能家居大放异彩
  20. java程序设计答案电子工业出版社_java 语言程序设计(机械工业出版社)课后习题答案 - 下载 - 搜珍网...

热门文章

  1. android ——Toolbar
  2. 服务器挂在公网,如何禁止公司以外的人访问公司网站
  3. 5-32 说反话-加强版
  4. Mac OS X安装 ffmpeg
  5. Centos 7 环境下,如何使用 Apache 实现 SSL 虚拟主机 双向认证 的详细教程:
  6. Journey Of Code组组员贡献率
  7. 【SpringMVC 笔记】结果跳转、数据处理、乱码问题
  8. 【MyBatis笔记】02-MyBatis配置SQL打印
  9. [转]形态学操作:膨胀与腐蚀
  10. jq使用教程03_JQData说明书概要