12.1 类继承层次中对象的关系
将基类指针指向派生类对象
CommissionEmployee * commisssionEmployeePtr = &basePlusCommissionEmployee;
只能调用CommissionEmployee
中的方法,而不能调用BasePlusCommissionEmployee
类中的方法
注意:被调用的功能取决于调用函数句柄的类型(即引用或者指针),而不是其指向对象的类型
若想调用派生类的功能,则需要进行“向下转换”
BasePlusCommissionEmployee *derivedPtr = dynamic_cast<BasePlusCommissionEmployee *>(employeePtr); //将基类指针类型employeePtr向下转化为派生类BasePlusCommissionEmployee类型指针,进而可以调用其功能,如下: employeePtr->getBaseSalary();
将派生类指针指向基类对象
编译器会报错!因为BasePlusCommissionEmployee
是一个CommissionEmployee
对象,而反过来则不存在这种关系,因此不能进行赋值
12.2 virtual函数和virtual析构函数
virtual函数
virtual函数功能
调用成员函数的是指针指向的对象的类型而不是句柄的类型,用来决定使用哪个版本的virtual函数;与之前的非虚函数相反,非虚函数效用的成员函数是基于调用函数句柄的类型
#声明
virtual void draw() const;//在函数原型前加上关键字virtual
注意:
-
派生类中重写的virtual函数应当和基类函数拥有相同的函数原型
-
一旦一个函数声明为virtual时,其之后的派生类都将保持是virtual的,即使没有显式声明
-
为了使程序清晰可读,派生类应当显式声明virtual函数
-
如果派生类不重写基类virtual函数,则会默认地继承基类的virtual函数的实现
静态绑定和动态绑定
1、静态绑定
通常使用对象名称加上圆点成员选择运算符basePlusCommissionEmployee.getBaseSalary()
调用成员函数时,调用的函数时在编译时就已经绑定了,因此被称作静态绑定
2、动态绑定
使用virtual函数,利用指针或者引用句柄完成调用成员函数
例如:
#include<vector> vector<Employee *> employees(3); employees[0] = &salariedEmployee; employees[1] = &commissionEMployee; employees[2] = &basePlusCommissionEmployee; for(Employee * employeePtr:employees){ (*employeePtr).print();//通过引用调用 employeePtr->print();//通过指针调用 }
virtual析构函数
声明
virtual ~Employee(){};
如果一个非虚析构函数的派生类,对指向其的指针调用delete运算符,则会出现错误
注意
-
因为析构函数不会继承,当一个派生类对象被销毁时,那么其内部成员初始化时的基类也会被消除,但此时不存在析构函数,因此会出现错误
-
基类的析构函数在派生类析构函数执行后执行,基类的构造函数在派生类的构造函数之前构造
-
如果一个对象含有virtual函数,那么该类就要提供一个virtual析构函数
Final成员函数和类
virtual void print() const final;//该函数不能够被派生类重载
声明final的类将不能够作为基类被继承
class Employee final{ //class body }
12.3 抽象类和纯virtual函数
抽象类
定义
通常作为基类,并且永远不打算实例化任何对象的类。抽象类是不完整的,需要派生类去定义哪些“缺少的部分”
构造抽象类的目的是为其他类提供合适的基类
纯virtual函数(纯虚函数)
声明
virtual void draw() const = 0;//pure virtual function
"=0"是纯指示符。纯虚函数不需要提供任何实现,其具体的实现由其派生类提供
注意:抽象类至少含有一个纯虚函数
“实现继承”和“接口继承”
-
“实现继承”:将功能的实现主要设置在较高层,共派生类继承使用这些功能
-
“接口继承”:较高层的基类主要提供函数原型,其具体的实现由其派生类提供
12.4 向下强制类型转换、dynamic_cast、typeid和type_info
dynamic_cast与static_cast
dynamic_cast向下强制类型转换
同12.1,可以将基类指针类型转换为其派生类类型,进而调用派生类对象的功能
注意:dynamic_cast是对指针指向对象的检测,如果对象类型不是即将转化的类型,则返回nullptr;若是则将指针转化为目标类型
static_cast强制类型转换
static_cast是直接将指针转化为目标类型,不考虑其指向对象的类型