• 多态(day10)


    二十二 多态(Polymorphic)
    1 函数重写(虚函数覆盖)、多态概念
       如果将基类中的某个成员函数声明为虚函数,那么子类与其具有相同原型的成员函数就也将是虚函数,并且对基类中的版本形成覆盖。
       这时,通过指向子类对象的基类指针,或者引用子类对象的基类引用,调用该虚函数,实际被执行的将是子类中覆盖版本,而不是基类中的原始版本,这种语法现象称为多态.
    eg:
       class Base{
       public:
               virtual void foo(void){
                   cout << "Base::foo" << endl;
               }
       };
       class Derived:public Base{
       public:
               void foo(void){
                   cout << "Derived::foo" << endl;
               }   
       };
       int main(void){
               Derived d;
               Base* pb=&d;//pb指向子类对象的基类指针
               Base& rb=d;//rb引用子类对象的基类引用
               pb->foo();//Derived::foo
               rb->foo();//Derived::foo
       }
       
    2 函数重写要求(虚函数覆盖条件)
    1)类中普通的成员函数可以声明为虚函数,而全局函数、类中的静态成员函数、构造函数都不能声明为虚函数。
      注:析构函数可以为虚函数(后面讲)
    2)只有在基类中以virtual关键字修饰的函数,才能作为虚函数被子类覆盖,而与子类中virtual关键字无关。
    3)虚函数在子类中的覆盖版本和改函数在基类中原始版本要拥有相同的函数签名,即函数名、形参表、常属性必须严格一致.
    4)如果基类中的虚函数返回基本类型的数据,那么子类的覆盖版本必须返回相同的类型。
    5)如果基类的虚函数返回类类型指针(A*)或引用(A&),那么允许子类返回其子类的指针(B*)或引用(B&)。--类型协变
    class A{};
    class B:public A{};
    
    3 多态的条件
    1)在满足虚函数覆盖前提下,必须要通过指针或引用调用该虚函数,才能表现出来。
    2)调用虚函数的指针也可以是this指针,只要它是一个指针子类对象的基类指针,调用虚函数时,同样可以表现多态的特性。//重点掌握
    
    4 纯虚函数、抽象类和纯抽象类
    1)纯虚函数
      virtual 返回类型 函数名(形参表)[const]=0;
    2)抽象类
      如果一个类中包含纯虚函数,那么这个类就是抽象类,抽象类不能创建对象。
    3)纯抽象类(有名接口类)
      如果一个抽象类除了构造函数和析构函数以外的所有成员函数都是纯虚函数,那么该类就是纯抽象类。
      
    注:如果子类没有覆盖抽象基类的纯虚函数,那么该子类就也是一个抽象类,类的抽象属性可以被继承.
    
    eg:PDF文档阅读器
    
    5 多态实现原理(了解)
      通过虚函数表和动态绑定,参考poly.jpg

    1)动态绑定会增加内存开销 2)虚函数调用会增加时间开销 3)虚函数不能被内联优化 结论:如果没有多态的语法要求,最好不要使用虚函数。 6 虚析构函数 1)基类析构函数不能调用子类的析构函数,对一个指向子类对象的基类指针使用delete运算符,实际被执行的仅是基类的析构函数,所释放的仅是基类子对象构造时的分配的动态资源,而子类特有的动态资源将会形成内存泄露。 2)将基类的析构函数声明为虚函数,那么子类的析构函数就也是一个虚函数,并且可以对基类的虚析构函数形成有效的覆盖,可以表现多态的特性。 3)这时delete一个指向子类对象的基类指针,实际被调用的将是子类的析构函数,而子类的析构函数在执行后又会自动调用基类的析构函数,避免内存泄露。 //笔试题:虚析构函数的作用? ========================================= 练习:薪资计算 员工 / | 技术员 经理 销售员 / / 技术主管 销售主管 所有员工:姓名、工号、职位等级、出勤率 经理:绩效奖金(元/月) 技术员:研发津贴(元/小时) 销售员:提成比率(x%) 薪资=基本工资+绩效工资 基本工资计算=职位等级的固定额度*出勤率(输入); 绩效工资根据具体的职位而定: 普通员工:基本工资一半 经理:绩效奖金*绩效因数(输入) 技术员:研发津贴*工作小时数*进度因数(输入) 销售员:提成比率*销售额度(输入) 技术主管:(技术员绩效工资+经理绩效工资)/2 销售主管:(销售员绩效工资+经理绩效工资)/2 结果:打印员工信息,输入必要数,计算和打印工资 class 员工{ double 计算工资(){ return 基本工资() + 绩效工资(); } virutal void 绩效工资(){} }; class 技术员:public 员工{ void 绩效工资(){} } int main(){ 员工对象.计算工资(); 技术员对象.计算工资(); }
  • 相关阅读:
    51nod 1163 最高的奖励
    51nod 1191 消灭兔子
    51nod 2538 二三排列
    node做渲染服务器的实现
    gulp静态服务器的搭建
    canvas中裁切(橡皮檫)的应用--探照灯,点击去除遮罩
    canvas中图片、视频的加载(截图、切片)
    canvas中笔触基础知识
    Gitee的使用流程
    gulp的使用
  • 原文地址:https://www.cnblogs.com/Kernel001/p/7729895.html
Copyright © 2020-2023  润新知