C++ 多态

文章目录

一:概念

编译时多态(静态) 运行时多态(动态)

主要动态时多态:达到多种形态

给函数传不同对象完成不同的行为,达到不同效果

多态就是基类和派生类有共同的虚函数,满足三同,想实现一个功能

二、定义和实现

在类成员函数前加virtual修饰,形成虚函数

多态的实现需要满足两个条件:

  • 这个功能参数必须是基类的指针或者引用
  • 派生类必须堆基类的虚函数完成重写或者覆盖(返回值,函数名,参数(只看类型)都相同,函数体可以不相同)重写就是重写一下这个函数体,重写虚函数的实现

注意一下

  • 派生类的virtrul可以去掉,也可以构成多态,但是不规范,选择题会埋坑
  • 虚函数在类里声明加virtual关键字,在类外定义实现不需要加virtual
  • 友元函数不属于成员函数,不能实现为虚函数
  • 静态成员函数不能设置为虚函数,因为静态成员函数属于整个类,不属于具体的某个对象,调用时直接类::静态函数(),静态函数无需拿到this指针,就掉不到虚函数表,进而无法被写成虚函数,无法被重写

运行时跟基类没有关系,而是传谁(派生类)调用谁

只有在运行时,才知道基类的指针或者引用具体指向那个类的对象,进而再去找虚函数表,调用对应的虚函数,实现多态

你用不同的类去继承它,去重写这个虚函数。就可以调用同一个函数(函数体不同)去完成不同的功能,形成不同的形态

三、析构函数的重写

基类和派生类析构函数表面上不满足三同,因为函数名不同,但由于编译时析构函数同意编译成destroctor(),所以析构函数也可以构成重写;

为什么基类的中的析构函数建议设计成虚函数?

  • 如果你不设计成虚函数,如果一个基类的指针指向一个派生类,而这个派生类里面又有资源的申请,当你去调用析构函数时候,就默认调用基类析构,会有内存泄漏的风险;
  • 简单来说:父类的析构函数强力建议设置为虚函数,这样动态释放父类指针所指的子类对象时,能够达到析构的多态
  • 所以设计成虚函数构成重写,指向谁调用谁,就不会出现上述情况;且析构遵循先子后父,析构完派生类会自动调用基类析构函数;

四、 override和final关键字

提示:这里可以添加技术细节
override 在编译的时候检查时候检查是否构成多态,不构成编译报错

在函数参数列表的后面加上override就可以

  • 跟assert很像,区别是assert是运行时报错;
    final修饰的虚函数不能被重写;

五、重载/重写/隐藏的对比

相同函数名之间函数的关系

重载:

  • 首先构成重载的函数必须要在同一作用域
  • 两个函数函数名相同,参数类型和个数可以不同

重写:

  • 是在继承和多态之中出现的概念,两个函数的函数名,参数和返回值三者完全相同,函数体可以不同;调用时需要使用父类的指针或者引用进而构成重写

隐藏:

  • 当派生类中的函数名和父类中的函数名重复了,派生类就会隐藏父类的函数,不会去调用父类的重名函数
  • 可以说两个函数如果不构成重写就是隐藏

六、纯虚函数和抽象类

纯虚函数就是虚函数后面加上=0;

抽象类 特点:不能实例化出对象

实际应用中这个基类(抽象类)就会使用他的指针或者引用来指向派生类;

  • 派生类如果不重写纯虚函数,那么这个派生类也是抽象类

  • 所以在一定程度上如果基类是抽象类,派生类就会强制被要求重写虚函数

    七、多态的原理

    一个类里有虚函数,他的大小包含了这个类的成员变量和虚函数表---函数指针数组(首先他是一个数组,其次这个数组里面存放指针,而指针又指向一个个的虚函数,所以叫函数指针数组)

    也就是这个ptr他可能是Person本身,也可能是切出来的Person对象;

多态函数的调用,就是你传什么对象,他就去调用那个对象的虚表,找到对应的续表函数;


动态绑定(运行时确定地址)和静态绑定(编译时确定地址)

5.1 虚函数表

·来看一段代码,了解一下虚函数表

答案是12字节

原因就是有虚函数的类,他的大小都会有一个指向虚函数表的一个指针_vptr和他的成员变量构成

关于虚函数表(简称虚表)

  • 同一个类型的不同对象共享一个虚函数表
  • 派生类和基类的虚函数表不是一个,只是继承下来,地址也不一样
  • 一个类的不同对象共用一张虚表
    虚函数和普通函数一样存在于代码段
    虚函数表存在常量区

动态绑定和静态绑定

静态绑定就是编译时就只知道要调用哪个函数,对不满⾜多态条件(指针或者引⽤+调⽤虚函数)的函数就是静态绑定

动态绑定就是运行时才知道要调用那个函数,多态函数的调用就是动态绑定,运行时候才去虚表里找要调用的函数


相关推荐
IT枫斗者枫哥3 小时前
MyBatis一对多分页:LIMIT 20,为什么凑不齐20个订单?
java·数据库
代码方舟3 小时前
Java数据工程:利用天远全网运营商三要素优化线上实名认证合规体验
java·人工智能
BBmmo3 小时前
我的 Java 学习笔记 · 第 7 篇:泛型与通配符
java
独泪了无痕3 小时前
Hutool之RandomUtil:随机数生成的终极利器
java·后端
花开路口3 小时前
深入理解 Java/Kotlin 协变与逆变
java·kotlin
运行时异常3 小时前
【WMS 仓储系统集成 AI Agent 实战】第 7 讲:Vue3 前端工程化——Token 刷新锁、Markdown 渲染踩坑与权限体系
java
她的男孩3 小时前
开放接口限流从 20 改到 200 还是每分钟 20 次:拆完防重放+幂等+限流,我找到 5 个静默失效的坑
java·后端·架构
天天被压力3 小时前
【Python 量化取数指南 #13】Python 把行情落库:sqlite 一键存,回测随用随取
java·人工智能·python
天天被压力3 小时前
【Python 量化取数指南 #14】Python 清洗行情数据:复权停牌对齐,回测不翻车
java·人工智能·python
独泪了无痕4 小时前
开发利器Hutool之MapUtil的使用
java·后端