多态

多态是指同一操作作用于不同的对象,可以有不同的解释和执行结果。

分为两类

  • 静态多态 : 函数重载、运算符重载复用函数名 (让函数名、运算符符号 有多种形态表现出来)
  • 动态多态派生类虚函数 实行运行时多态 (多种形态调用公共接口)

一句话概括静态多态:

同一段模板代码,在编译时根据传入的不同类型,生成不同的具体实现。

一句话概括动态多态:

用父类的指针或引用,调用子类重写的函数,实现"一个接口,多种实现"。

区别
静态多态的函数地址早绑定,即编译阶段确定函数地址
动态多态的函数地址晚绑定,即运行阶段确定函数地址

1.动态多态(虚函数)

父类引用指向接收子类对象(c++中允许父子之间的类型转换)

![[多态.png]]

想让猫说话,但实际上是动物在说话
原因:该写法属于地址早绑定(speak函数)

若想让猫说话,利用动态多态(晚绑定)

virtual关键字 虚函数:

![[虚函数.png]]

(子类实现父类同名函数)

![[同名函数.png]]

动态多态满足条件
  1. 继承关系
  2. 子类重写父类中虚函数 ,virtual关键字可以不加(函数返回类型、函数名、参数完全相同,不是重载)
动态多态的使用

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

2.多态的原理剖析

复习:只有非静态成员变量存储于类,静态函数和成员,非静态函数都不存储于类

虚函数:
virtual 虚函数指针,指向虚函数表,表内部记录虚函数地址(成员函数的地址,加作用域 &取地址)

子类:
->不重写
继承父类——指针,指向子类虚函数表 ,记录虚函数
->重写
子类中虚函数表内部替换为子类的虚函数地址

当父类指针或引用指向子类对象,发生多态(从子类的虚函数表中找虚函数地址)

3.多态的优势

普通写法,扩展新功能时需要不断修改源码

开发提倡:开闭原则,即对扩展开放,对修改进行关闭

多态实现:
1.抽象类(多态写虚函数,子类中重写)
2.继承(vitual关键字可省略)抽象类
3.多态使用条件:[[#动态多态的使用|父类指针或引用指向子类对象]]

new一个对象,用指针接收、访问
![[多态案例.png]]

4.纯虚函数和抽象类

多态中,父类虚函数的实现无意义,主要调用子类重写的内容,因此可以将虚函数改为纯虚函数

纯虚函数语法:virtual 返回值类型 函数名 (参数列表) = 0;
*删去了{}

当类中有了纯虚函数,这个类也称为抽象类

抽象类特点
  • 无法实例化对象(太抽象,不允许)
  • 子类必须重写(完全一样)抽象类中的纯虚函数,否则也属于抽象类(无法实例化对象)

new一个普通类型和数组之前有讲过,
如何new一个对象?(类类型)

// 写法1:默认构造
Son* p1 = new Son;            // 调用默认构造函数(不带括号)

// 写法2:默认构造(带括号,效果一样)
Son* p2 = new Son();          // 也调用默认构造函数

// 写法3:带参构造
Son* p3 = new Son(100);       // 调用带参数的构造函数

// 写法4:数组
Son* p4 = new Son[5];         // 分配5个Son对象,每个都调用默认构造

区别:
![[new对象.png]]

// 多态技术调用
Base * base = new Son;

多态让函数接口更通用化,通过一个指针,创建对象不同,调用不同形态的函数

案例2

父类指针:
普通函数——调用父类,虚函数——调用子类版本(多态)

堆区数据手动释放
abs指向 堆区数据

  1. new Coffee → 在堆区创建 Coffee 对象,返回地址(假设 0x1000

  2. 调用 doWork(0x1000) → 形参 abs 保存地址 0x1000

  3. delete abs → 释放地址 0x1000 处的堆区对象
    ![[堆区数据释放.png]]

扩展开放,修改关闭,增加新功能不需要修改,扩展即可

纯虚函数,父类不写实现,子类重写函数并且写具体实现

5.虚析构和纯虚析构

问题:
delete 父类指针 不会调子类的析构代码
解决:
将父类中的析构改成(纯)虚析构,释放子类对象

  • 父类指针释放子类对象

子类中有数据开辟到堆区,需要调用子类的析构代码,但多态调不到
![[子类堆区属性释放.png]]

纯虚析构
和虚析构都需要代码实现

父类中的堆区数据在父类的析构函数中释放,所以需要代码实现

纯虚析构的代码实现:
类内声明类外实现(不用写virtual,加类的作用域)

有纯虚析构,这个类属于抽象类,无法实例化

总结
在这里插入图片描述

![[虚析构和纯虚析构总结.png]]![[虚析构和纯虚析构总结2.png]]

案例

抽象类 <-纯虚函数

电脑类,构造函数传入零件的指针;提供工作函数调用零件工作的接口

具体厂商的零件继承抽象类(重写纯虚函数,写实现)

测试阶段组装三台不同的电脑

更多推荐