多态的基本原理和使用

多态的概念、定义以及实现

多种形态,当不同的对象去执行同一种行为时,产生的不同表现形态

构成多态三个条件(同时满足,缺一不可):在不同的继承关系的类对象,去调用同一函数,产生了不同的行为

  1. 必须在继承的框架下实现(前提是继承)
  2. 必须通过基类的指针或者引用调用虚函数,即都为切片行为
  3. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

虚函数的重写:重写函数逻辑

  1. 构成虚函数的重写条件:子类含有和父类借口完全相同的函数–>返回值,函数名,参数完全相同(例外:协变,析构函数重写)

不满足条件但是函数名相同则构成函数隐藏

  1. 协变:返回值类型可以不同,但是返回值类型必须是父子关系的指针或者引用

注意:如果父类函数加了virtual声明,则子类借口完全一致的函数即使不加virtual的声明,也具有虚函数的属性,但是反过来不成立。建议一般对于所有虚函数都加上virtual

  • 非多态:看类型
  • 多态:看实际指向的实体

析构函数的重写:

  1. 只要父类的析构函数是虚函数,则子类的析构和父类析构构成重写

原因:编译器对继承关系下的所有类的析构函数的名字做了统一处理,保证了继承关系下子类析构函数和父类析构函数底层同名,一般把析构函数的名称统一处理成destructor

所以只要父类析构是虚函数,则子类析构重写父类析构

finaloverride关键字:

  1. final:修饰虚函数,表示该虚函数不能再被继承,其定义的函数不能被重写,体现实现继承
  2. override:检查派生类虚函数是否重写了某个虚函数,如果没有重写则编译报错,强制子类重写父类的某一个虚函数

抽象类

抽象类:包含纯函数的类,抽象类不能实例化对象

class A
{
public:
  //纯虚函数:没有函数体的虚函数
  virtual void fun() = 0;
};

class B : public A
{
public:
  virtual void fun()
  {
    cout << "B::fun()" << endl;
  }
};

void test()
{
  //无法执行以下代码
  //A a;
  //a.fun();
  
  B b;
  A* pb = &b;
  b.fun();
  pb->fun();
}

抽象类存在意义,实现多态,其体现出接口继承

多态原理

多态原理:如果访问的为虚函数,则通过指针/引用找到实际指向的实体,获取实体中的虚表指针,通过虚表指针访问虚表,在虚表中找到需要执行的虚函数指针,通过虚函数指针执行具体函数行为

虚函数表

class D
{};
class Car
{
public:
  virtual void Drive()
  //包含隐藏成员变量,虚函数表指针
};

包含虚函数的类:类中包含一个隐含的成员变量,即虚表指针

虚表指针:指向虚表的首地址,类型为二级指针,函数指针的指针

虚表:存放虚函数指针的数组,类型为指针数组

  1. 只存放虚函数的指针
  2. 普通函数不会存入虚表
  3. 如果子类重写了父类的虚函数,则子类虚表中对应位置使用子类虚函数指针覆盖
  4. 如果子类没有重写父类的任何虚函数,则子类完全继承父类虚表,不做任何修改
  5. 虚函数指针在虚表中的存放顺序和其声明/定义的顺序一致
  6. 子类新定义的虚函数,其虚函数指针按照声明/定义的顺序依次加入虚表的末尾
  7. 虚表一般以nullptr结束

只要类中包含虚函数,就会有虚表指针和虚表

  • 虚表指针存在对象当中
  • 虚表存放在代码段
  • 虚函数存放在代码段

多态:看实际指向的实体

继承下的虚表

单继承虚表

  1. 子类继承父类虚表
  2. 用重写的虚函数指针覆盖子类对应的虚函数指针
  3. 子类新定义的虚函数,其指针按照声明/定义顺序存入虚表的末尾

多继承虚表

  1. 虚表个数:等同于直接父类的个数
  2. 子类继承父类所有的虚表
  3. 用重写的虚函数指针覆盖对应父类的虚函数指针
  4. 子类新定义的虚函数,其函数指针按照声明/定义的顺序存入第一个直接父类虚表的末尾
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值