C++中的多态问题

多态
  • 多态分类
    • 静态多态:函数重载和运算符重载属于静态多态,复用函数名
    • 动态多态:派生类和虚函数实现运行时多态
  • 静态多态和动态多态的区别
    • 静态多态的函数地址早绑定—编译阶段确定函数地址
    • 动态多态的函数地址晚绑定—运行阶段确定函数地址
  • 静态多态就是我们常用的那些函数等
  • 动态多态满足等条件
    • 继承关系
    • 子类要重写(重写和重载是两个不同的概念)父类的虚函数
    • 几点分析
      • 重载的前提是函数名相同即可,重写的前提是函数类型相同(包括函数名和参数及返回值参数)
      • 虚函数即为在父类中用virtual修饰的函数,必须要在子类中重写,子类在重写过程中不必要再次写virtual
  • 动态多态使用
    • 父类的指针或者引用执行子类对象
      void doSpeak(Animal& animal){
          animal.speak();
      }
      int main(){
          Cat cat;
          doSpeak(cat);
      }
    
  • 深入分析多态底层
      class Animal{
          public:
              void speak(){
                  cout << "动物在说话" << endl;
              }
      }
      //sizeof--->1字节
         class Animal{
          public:
          virtual void speak(){
                  cout << "动物在说话" << endl;
              }
      }
      //sizeof--->4字节--->指针 
    
    • 上述代码结果其实就反应了其变为一个指针—>vfptr—虚函数指针
    • vfptr指向虚函数表vftable
    • 父类vftable虚函数表记录虚函数的地址—此例中存&Animal::speak
    • 子类的vftable虚函数表记录虚函数的地址—此例中存&Cat::speak
    • 当父类的指针或者引用指向子类对象时候,发生多态—Animal& animal = cat; animal.speak();
    • 总结
      • 就是存在虚函数表,相当于一个函数指针内保存了不同的访问接口(函数入口)
      • 保证了接口一样但是内部实现不一样
    • 多态实现的方式
      • 建立一个抽象类virtual修饰一个函数但父类不做任何实现
      • 子类可以更多的实现virtual这个类,通过这种方式来实现不同的功能
    • 多态的优点
      • 代码结构清晰
      • 可读性强
      • 利于前期和后期的扩展以及维护
  • 纯虚函数和抽象类
    • 多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容,因此,可以直接将虚函数变为纯虚函数
    • 语法
      • virtual 返回值类型 函数名(参数列表) = 0;
    • 抽象类
      • 当类中有了纯虚函数,这个类也称为抽象类
    • 抽象类的特点
      • 无法实例化对象
      • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
      // 抽象类
      class BaseTest{
          public:
          virtual void func() = 0;
      };
    
  • 注意使用多态的两种方式
      Base *p = new Son;// 指针
      Son s;
      Base &p = s;// 引用
    
  • 抽象类和子类的常用背景
    • 抽象类更趋向于一种方式
    • 子类实现更趋向于一种这个方式在做什么—每一个具体做什么构成一个子类
    • 一个案例—武器更换
      #include <iostream>
      #include <string>
      using namespace std;
      class Gun{
          public:
          virtual void TakeGun() = 0;
          virtual void ReloadGun() = 0;
          virtual void EmissionGun() = 0;
          virtual void LiftedGun() = 0;
          void PleaseGun(void){
              TakeGun();
              ReloadGun();
              EmissionGun();
              LiftedGun();
          }
      };
      class AK47:public Gun{
          virtual void TakeGun(){
              cout << "takeak47" << endl; 
          }
          virtual void ReloadGun(){
              cout << "reloadak47" << endl; 
          }
          virtual void EmissionGun(){
              cout << "emissionak47" << endl;         
          }
          virtual void LiftedGun(){
              cout << "liftedgunak47" << endl;       
          }    
      };
      class M4A1:public Gun{
          virtual void TakeGun(){
              cout << "takem4a1" << endl; 
          }
          virtual void ReloadGun(){
              cout << "reloadm4a1" << endl; 
          }
          virtual void EmissionGun(){
              cout << "emissionm4a1" << endl;         
          }
          virtual void LiftedGun(){
              cout << "liftedgunm4a1" << endl;       
          }    
      };
      void HaveGun(Gun* gun){
          gun->PleaseGun();
      }
      int main(){
          HaveGun(new AK47);
          return 0;
      }
    
  • 虚析构和纯虚析构
    • 多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
    • 解决
      • 将父类中的析构函数改为虚析构函数或者纯虚析构
    • 虚析构和纯虚析构共性
      • 可以解决父类指针释放子类对象
      • 都需要有具体函数实现
    • 虚析构和纯虚析构区别
      • 如果是纯虚析构,该类属于抽象类,无法实例化对象
    • 纯虚析构和纯虚函数的区别
      • 在父类存在内存释放问题时,必须使用析构函数,因此纯虚析构既要声明又要去实现内容
      • 父类纯虚函数的实现,可以在类外采用作用域方式进行
    • 语法
      • 虚析构语法
        • virtual ~类名(){}
      • 纯虚析构语法
        • virtual ~类名() = 0;
        • 类名::~类名(){}
    • 作用
      • 释放内存问题
    • 总结
      • 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
      • 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
      • 拥有纯虚析构函数的类也属于抽象类
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值