1.多态是C++面向对象的三大特性之一。
多态分为两类:
①静态多态:函数重载和运算符重载属于多态,复用函数名
②动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态的区别:
静态多态的函数地址早绑定,编译阶段确定函数地址
动态多态的函数地址晚绑定,运行阶段确定函数地址
动态多态满足条件:①有继承关系 ②子类重写父类的虚函数
重写:函数返回值类型 函数名 参数列表 完全一致称为重写
函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了
动态多态的使用:父类的指针或者引用,指向子类对象
2.类的内部结构如下:
vfptr = virtual function pointer 虚函数指针
vftable 虚函数表 表内记录虚函数地址
vfptr ---> vftable
//class Animal size(4):
// +---
// 0 | {vfptr}
// +---
//
//Animal::$vftable@:
// | &Animal_meta
// | 0
// 0 | &Animal::speak
//
//Animal::speak this adjustor: 0
//
//class Cat size(4):
// +---
// | +--- (base class Animal)
// 0 | | {vfptr}
// | +---
// +---
//
//Cat::$vftable@:
// | &Cat_meta
// | 0
// 0 | &Cat::speak //继承下来时 &Animal::speak 被 &Cat::speak 覆盖掉
//
//Cat::speak this adjustor: 0
//
//class Dog size(4):
// +---
// | +--- (base class Animal)
// 0 | | {vfptr}
// | +---
// +---
//
//Dog::$vftable@:
// | &Dog_meta
// | 0
// 0 | &Dog::speak //继承下来时 &Animal::speak 被 &Dog::speak 覆盖掉
//
//Dog::speak this adjustor: 0
3.纯虚函数和抽象类
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法:virtual 返回值类型 函数名(参数列表) = 0;
当类中有了纯虚函数,这个类也称为抽象类
抽象类特点:无法实例化对象;子类必须重写抽象类中的纯虚函数,否则也属于抽象类
4.虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
如果子类中没有堆区数据,可以不写虚析构或纯虚析构
解决方式:将父类中的析构函数改为虚析构或纯虚析构
虚析构或纯虚析构共性:
可以解决父类指针释放子类对象
都需要具体的函数实现
虚析构或纯虚析构区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名() = 0;
类名::~类名(){}