C++面向对象------多态

一、虚函数、覆盖、多态

  虚函数:在定义时添加virtual关键字的成员函数,叫虚函数

  覆盖:在子类中实现与父类中虚函数相同的函数,那么子类中的成员函数会覆盖父类中的成员函数

    不同于隐藏,隐藏是在父子类之间名字相同的标识符,只要不够成覆盖,就是隐藏。子类会隐藏父类中的同名函数

  多态:如果子类中的成员函数对父类中的成员函数进行了覆盖,那么当一个指向子类的父类指针或引用了子类的父类引用,在调用此同名函数时会调用子类中的函数,而不是父类中的虚函数,这种语法现象叫多态。

  多态的意义在于同一种类发出同一种调用而产生不同的反映

二、覆盖、重载、隐藏的条件

  覆盖(重写):

    a、不在同一作用域,分别在基类和派生类

    b、函数名、参数、返回值相同

    c、基类函数必须有virtual关键字

    d、访问修饰符可以不同

    

  重载:

    a、在同一作用域下

    b、函数名相同,参数不同

    c、返回值可以不同

  

  隐藏:

    a、在不同作用域中

    b、函数名相同

    c、在基类和派生类中只要不构成覆盖就是隐藏

三、多态的条件

   1、派生类必须重写基类的虚函数。

   2、通过基类指针或引用调用基类的虚函数(该虚函数派生类必须要重写)

   3、当指针或引用已经构成多态时,此时调用成员所传的this指针再调用成员函数时也构成多态

   4、在子类的构造函数执行前会先调用父类的构造函数,如果调用被覆盖的虚函数,由于子类还没构造完成,因此只能是调用父类中的虚函数构造函数在进入函数体执行时,类中看得见的资源已经全部构造完成

   5、在子类的析构函数执行完成后会再调用父类的析构函数,如果调用被覆盖的虚函数,由于子类已经开始析构完成已经不能算是完整的子类了,因此只能调用父类中的虚函数

四、纯虚函数和抽象类
  1、纯虚函数
    class A
    {
      public:
      virtual void test(void) = 0;
      virtual void test(void) const = 0;
    };
    a、纯虚函数不需要被实现,如果非要实现也不能在类中,必须要在类外(虚函数)

    b、纯虚函数如果想调用必须在子类中覆盖,然后以多态的方式调用


  2、抽象类

    成员函数中有纯虚函数的叫抽象类,这种类不能创建对象。

    如果子类继承了抽象类,则必须把父类中的纯虚函数覆盖了,否则他也变成了抽象类不能被实例化

    因此抽象类只能以指针或引用的方式指向子类来调用非纯虚函数


  3、纯抽象类

    所有的成员函数都是纯虚函数,这种类叫纯抽象类

    面向对象的四大特性:抽象、封装、继承、多态

    纯抽象类是类封装的过程,同时抽象类也可以当做一个统一的接口

六、虚函数表

    1、什么是虚函数表,当一个类中有虚函数时,编译器会为这个函数分配一个专门记录这些的虚函数表,在类中会有一个隐藏的指针成员指向这张表

    2、如何证明这张表存在

      有虚函数的类会比没有虚函数的类(相同的)多4字节,还会添加补齐和对其

    3、一个类只有一张虚函数表,所有对象共享一张虚函数表

    4、一般对象的前4字节是指向虚函数表的指针


七、动态类型绑定(多态)
  1、当使用父类指针或引用指向子类时,编译器并没有立即生成调用函数的指针,而是生成了一段代码,用于检查指针指向的真正的对象是什么类型

  2、在代码真正运行时才通过对象的指针找到指向虚函数的成员指针

  3、再通过成员指针访问到虚函数表,再从中找到调用的函数地址

  4、使用多态会产生额外的一些代码和调用,因此使用多态会降低代码的执行速度



九、虚析构
  1、如果通过父类指针或引用指向子类对象,当使用delete释放对象时,此时只能调用父类的析构函数,如果子类中使用new/malloc申请了内存资源,那么将导致内存泄漏

  2、解决方法就是把父类的析构函数设置为虚函数

  3、在设计类时如果析构函数什么都需要做,编译器也会生成一个空的析构函数,但这样会让继承它的子类会有安全隐患

  4、最好把所有的析构函数都设置为虚函数

 

猜你喜欢

转载自www.cnblogs.com/xkk956227639/p/9470687.html
今日推荐