【C++】多态

目录

  • 多态条件
  • 两个特殊情况
  • 接口继承和实现继承
  • final 和 override
  • 重载、重写(覆盖)、隐藏(重定义)
  • 抽象类
  • 多态原理
  • 打印虚表
  • 多继承中的虚函数表
  • 动态绑定和静态绑定
  • 菱形继承,菱形虚拟继承中的虚表

多态条件

  1. 必须是多函数的重写
  2. 通过父类指针或引用去调用

两个特殊情况

  • 1.父类加virtual,子类对应函数不加virtual也能构成多态
    比如父类析构加virtual,子类不加,可以避免调错
  • 2.协变:虚函数重写返回值可以不同,但必须是父子关系类的指针或引用(可以不是自身所属类)

接口继承和实现继承

  • 普通函数继承是实现继承,派生类可使用基类函数,继承的是函数的实现
  • 虚函数继承是一种接口继承派生类继承的是基类函数的接口(函数名和参数列表),目的是为了重写(重写的是函数实现或者也可能重写返回值(协变)),达成多态,继承的是接口

final 和 override

  • final

    • final 修饰的类不能被继承 ---- 最终类
    • final 修饰的虚函数不能被重写
  • override

    • 对虚函数是否重写进行检查,确保完成虚函数重写
    • (虚函数就是为了重写!重写就是为了实现多态!)

重载、重写(覆盖)、隐藏(重定义)

  • 重载
    • 重载函数都在同一作用域
    • 函数名相同,参数类型个数不同
  • 重写(覆盖)
    • 函数分别在基类和派生类的作用域
    • 三同(协变情况返回值可以不同)
    • 两个函数必须是虚函数
  • 重定义(隐藏)
    • 函数分别在基类和派生类作用域
    • 函数名相同
    • 基类和派生类的同名函数不构成重写即是重定义

抽象类

virtual void Drive() = 0;

  • 虚函数后加 = 0 就是纯虚函数,包含纯虚函数的类是抽象类(接口类)
  • 抽象类不能实例化出对象
  • 子类必须对抽象父类纯虚函数进行重写

多态原理

  • 虚函数地址会进虚函数地址表,类对象头部有虚函数表指针指向这个虚函数表
  • 子类中重写的虚函数会将虚表中原基类对应的虚函数地址覆盖
  • 重写的就覆盖,没重写就不覆盖
     
  • 同类对象的虚表是同一份

对于这段代码
【C++】多态_第1张图片

【C++】多态_第2张图片

打印虚表

  • 虚表是在编译阶段生成的
  • 虚表指针的初始化实在构造函数的初始化列表完成
  • 虚表在代码段(常量区)

打印虚表
可验证派生类中新增的虚函数会进派生类的虚表
【C++】多态_第3张图片

【C++】多态_第4张图片

多继承中的虚函数表

多继承

  • 派生类中新增的虚函数会进到第一张基类虚表中
  • 重写了的func1会覆盖两张虚表中的func1,调用时会用第一张虚表中的func1,
  • 若指定调用Base2部分中的func1,会跳转到Base1部分的func1【C++】多态_第5张图片
    【C++】多态_第6张图片

动态绑定和静态绑定

  • 静态绑定:编译时确定程序行为,也叫静态多态,如函数重载
  • 动态绑定:运行期间根据拿到的类型确定程序行为(调用对应函数),也叫动态多态

菱形继承,菱形虚拟继承中的虚表

  • 虚表:存储虚函数地址
  • 虚基表:存储偏移量

你可能感兴趣的:(c++,开发语言,java)