12 面向对象编程:多态性(cpp大学教程)学习笔记

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是直接将指针转化为目标类型,不考虑其指向对象的类型

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值