“多态(polymorphism)”指的是同一名字的事物可以完成不同的功能。
多态可以分为编译时的多态和运行时的多态。
编译时的多态(静态多态):主要是指函数的重载(包括运算符的重载)、对重载函数的调用,在编译时就能根据实参确定函数地址,然后确定调用哪个函数。
运行时的多态(动态多态):和继承、虚函数等概念有关,运行阶段确定函数地址。
构成动态多态的满足条件:
- 有继承关系
- 子类重写父类的虚函数
- 存在父类的指针,通过该指针调用虚函数。
动态多态使用:父类的指针或引用指向子类对象
虚函数
虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
虚函数是根据指针的指向来调用的,指针指向哪个类的对象就调用哪个类的虚函数。
纯虚函数
将虚函数声明为纯虚函数,语法格式为:
virtual 返回值类型 函数名 (函数参数) = 0;
纯虚函数没有函数体,只有函数声明,在虚函数声明的结尾加上=0
,表明此函数为纯虚函数。
包含纯虚函数的类称为抽象类(Abstract Class)。之所以说它抽象,是因为它无法实例化,也就是无法创建对象。原因很明显,纯虚函数没有函数体,不是完整的函数,无法调用,也无法为其分配内存空间。
抽象基类中除了包含纯虚函数外,还可以包含其它的成员函数(虚函数或普通函数)和成员变量。
只有类中的虚函数才能被声明为纯虚函数,普通成员函数和顶层函数均不能声明为纯虚函数。
通常是基类作为抽象类,让派生类去实现纯虚函数。派生类必须实现纯虚函数才能被实例化
虚析构和纯虚析构
多态使用时,如果子类有属性开辟到堆区,那么父类指针在释放时无法调用子类的析构函数
解决方式:将父类的析构函数改为虚析构和纯虚析构
虚析构和纯虚析构异同:
同:
- 可以解决父类指针释放子类对象
- 都需要有具体的函数实现
异:
- 如果是纯虚构,该类属于抽象类,无法实例化对象
语法:
//虚析构
virtual ~类名(){}
//纯虚析构
virtual ~类名(){} = 0;