4.7 多态
4.7.1 多态的基本概念
4.7.2 纯虚函数和抽象类
4.7.3 虚析构和纯虚析构
4.7 多态
4.7.1 多态的基本概念
多态是C++面向对象三大特性之一
多态分为两类
-
静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
-
动态多态: 派生类和虚函数实现运行时多态
静态多态和动态多态区别:
-
静态多态的函数地址早绑定 - 编译阶段确定函数地址
-
动态多态的函数地址晚绑定 - 运行阶段确定函数地址
多态满足条件:
-
有继承关系
-
派生类重写基类中的虚函数
多态使用条件
-
基类指针或引用指向派生类对象
重写:函数返回值类型 函数名 参数列表 完全一致称为重写
示例
#include#include #include #include using namespace std; class person{ public: void show(){ cout<<"是一个人"< 虚函数实现
#include#include #include #include using namespace std; class person{ public: //函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了 virtual void show(){ cout<<"是一个人"< 多态的优点:
代码组织结构清晰
可读性强
利于前期和后期的扩展以及维护
示例
#include#include #include #include using namespace std; //抽象计算器类 //多态优点:代码组织结构清晰,可读性强,利于前期和后期的扩展以及维护 class base{ public: int x,y; virtual int calculate(){ return 0; } }; //加法计算器 class add:public base{ public: int calculate(){ return x+y; } }; //减法计算器 class sub:public base{ public: int calculate(){ return x-y; } }; //乘法计算器 class mul:public base{ public: int calculate(){ return x*y; } }; int main(){ //基类指针指向派生类对象的加法计算器 add a; base *b1=&a; b1->x=10; b1->y=20; cout< calculate()< x=10; b3->y=20; cout< calculate()< 总结:C++开发提倡利用多态设计程序架构,因为多态优点很多
4.7.2 纯虚函数和抽象类
在多态中,通常基类中虚函数的实现是毫无意义的,主要都是调用派生类重写的内容,可以将虚函数改为纯虚函数
纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;
当类中有了纯虚函数,这个类也称为抽象类(只要有一个函数是纯虚函数,就是抽象类)
抽象类特点:
无法实例化对象
派生类必须重写抽象类中的纯虚函数,否则也属于抽象类
示例:
#include#include #include #include using namespace std; class point{ public: int x,y; //纯虚函数 //类中只要有一个纯虚函数就称为抽象类 virtual void show()=0; }; class point_son_1:public point{ public: }; class point_son_2:public point{ public: void show(){ cout< x=10; p3->y=20; p3->show(); } int main(){ test01(); test02(); return 0; }
4.7.3 虚析构和纯虚析构
多态使用时,如果派生类中有属性开辟到堆区,那么基类指针在释放时无法调用到派生类的析构代码
解决方式:将基类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
可以解决基类指针释放派生类对象
都需要有具体的函数实现
虚析构和纯虚析构区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名() = 0;
类名::~类名(){}
示例:
#include#include #include #include using namespace std; class person{ public: person(){ cout<<"person的构造函数调用"< show(); //通过基类指针去释放,会导致派生类对象可能清理不干净,造成内存泄漏 delete p; return 0; } 解决方法1 将基类函数的析构函数改为虚析构
#include#include #include #include using namespace std; class person{ public: person(){ cout<<"person的构造函数调用"< show(); delete p; return 0; } 解决方法2 利用纯虚析构函数的方法
#include#include #include #include using namespace std; class person{ public: person(){ cout<<"person的构造函数调用"< show(); delete p; return 0; } 总结:
1. 虚析构或纯虚析构就是用来解决通过基类指针释放派生类对象
2. 如果派生类中没有堆区数据,可以不写为虚析构或纯虚析构
3. 拥有纯虚析构函数的类也属于抽象类



