学习笔记 | C++ | 多态与重载、虚函数、纯虚函数

12. 多态与重载

  • 掌握如何实现多态性
  • 掌握虚函数的定义以及用法
  • 熟悉虚析构函数
  • 熟悉抽象基类
  • 熟悉并掌握运算符重载
12.1 多态概述
  • 多态性就相当于具有不同功能的函数可以共用同一个函数名,这样就可以用一个函数名调用具有不同功能的函数。
12.1.1 认识多态行为
  • 所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
静态多态性和动态多态性
  • 函数重载运算符重载实现的多态性就属于静态多态性,在程序编译时系统就能决定调用的是哪个函数,因此静态多态性又称编译时的多态性
  • 静态多态性是通过函数重载实现的。
  • 动态多态性是在程序运行过程中才动态地确定操作所针对的对象,它又称运行时的多态性动态多态性是通过虚函数和派生类实现的。
12.1.2 实现多态性
  • 在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。
  • C++编译器在编译的时候,要确定每个对象调用的函数的地址,这称为早期绑定
  • 当编译器使用晚期绑定时,就会在运行时再去确定对象的类型以及正确的调用函数,而要让编译器采用晚期绑定,就要在基类中声明函数时使用virtual关键字,这样的函数称之为虚函数
  • 一旦某个函数在基类中声明为virtual,那么在所有的派生类中该函数都是virtual,而不需要再显示地声明为virtual
12.2 虚函数
  • 虚函数是在基类中使用关键字virtual声明的函数。
  • 在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态连接到该函数。用户想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态联编,或晚期绑定
12.2.1 虚函数的定义
  • 一种是基类希望其派生类进行覆盖的函数;
  • 另一种是基类希望派生类直接继承而不要改变的函数。
  • 任何构造函数之外的非静态函数都可以是虚函数。派生类经常覆盖它继承的虚函数,如果派生类没有覆盖其基类中某个虚函数,则该虚函数的行为类似于其他的普通成员,派生类会直接继承其在基类的版本。
12.2.2 认识虚函数表
  • 编译器在编译的时候,发现Base类中有虚函数,此时编译器会为每个包含虚函数的类创建一个虚表vtable该表是一个一维数组,在这个数组中存放每个虚函数的地址。
    在这里插入图片描述
  • 那么如何让定位虚表呢?
    编译器另外还为每个对象提供了一个虚表指针vptr,这个指针指向了对象所属类的虚表,在程序运行时,根据对象的类型去初始化vptr,从而让vptr正确地指向了所属类的虚表,从而在调用虚函数的时候,能够找到正确的函数。
  • 正是由于每个对象调用的虚函数都是通过虚表指针来索引的,也就决定了虚表指针的正确初始化是非常重要的,换句话说,
    在虚表指针没有正确初始化之前,用户不能够去调用虚函数,那么虚表指针是在什么时候,或者什么地方初始化呢?
    答案:在构造函数中进行虚表的创建和虚表指针的初始化,在构造子类对象时,要先调用父类的构造函数,此时编译器只看到了父类,并不知道后面是否还有继承者,它初始化父类对象的虚表指针,该虚表指针指向父类的虚表,当执行子类的构造函数时,子类对象的虚表指针被初始化,指向自身的虚表。
  • 虚函数表有以下特点:
    (1)每一个类都有虚表。
    (2)虚表可以继承,如果子类没有重写虚函数,那么子类虚表中仍然会有该函数的地址,只不过这个地址指向的是基类的虚函数实现,如果基类有3个虚函数,那么基类的虚表中就有三项(虚函数地址),派生类也会创建虚表,至少有三项,如果重写了相应的虚函数,那么虚表中的地址就会改变,指向自身的虚函数实现,如果派生类有自己的虚函数,那么虚表中就会添加该项。
    (3)派生类的虚表中虚地址的排列顺序和基类的虚表中虚函数地址排列顺序相同。
12.2.3 虚函数的用法
  • 虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
  • 经常会用到类的继承,目的是保留基类的特性,以减少新类开发的时间。但是,从基类继承来的某些成员函数不完全满足派生类的需要。
  • 当把基类的某个成员函数声明为虚函数后,允许在其派生类中对该函数重新定义,赋予它新的功能,并且可以通过指向基类的指针指向同一类族中不同类的对象,从而调用其中的同名函数。
    由虚函数实现的动态多态性就是:同一类族中不同类的对象,对同一函数调用作出不同的响应。
  • 在派生类中重新定义此函数,要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数相同,并根据派生类的需要重新定义函数体。
  • 但习惯上一般在每一层声明该函数时都加virtual
  • 定义一个指向基类对象的指针变量,并使它指向同一类族中需要调用该函数的对象。
  • 通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。
#include <iostream>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值