• 多态


    1.多态与虚函数

    多态性是指同一个操作作用于不同的对象就会产生不同的响应。多态性分为静态多态性和动态多态性,其中函数重载和运算符重载属于静态多态性,虚函数属于动态多态性。

    一旦一个函数被声明为虚函数,无论经历多少次派生,都会保持虚函数的特性,即使派生类中没有使用virtual关键字,其仍然是虚函数。

    虚函数有以下注意点:

    1)virtual应用于修饰public或protect成员函数。使用virtual修饰private成员函数时尽管不会报错,但没有意义。

    2)如果派生类中没有对基类虚函数进行重定义,则它将继承基类中的虚函数。

    3)友元不能是虚函数,因为友元不是类成员,只有成员才能是虚函数,但可以在友元内调用虚函数解决问题。虚函数可以是另一个类的友元。

    2.虚函数的访问

    1)基指针访问

    /************************classdef.h********************/
    #include <iostream.h>
    using namespace std;
    class   base
    {
        public:
             virtual  void  disp()
             {
                  cout<<"hello,base"<<endl;
              }
    };
    
    class  child:public  base
    { 
          public:
              void disp()
              {
                    cout <<"hello,child"<<endl;
               }
    };
    /************************main1.c********************/
    #include "classdef.h"
    int main()
    {
          base  obj_base;
          base *pBase = &obj_base;
          child  obj_child;
          child *pChild = &obj_child;
          pBase->disp();
          pChild->disp();
          pBase = pChild;                      //将派生类指针赋值给基类函数
          pBase->disp();                       //使用基类指针调用虚函数
          pChild = (child*)&obj_base;   //使用基类对象地址为派生类指针赋值
          pChild->disp();                      //使用派生类指针调用虚函数,只取决于赋值对象
          pChild->base::disp();            //使用类名加作用域限定符指明要调用的版本
          return 0;
    }

    输出结果:

    hello,base
    hello,child
    hello,child
    hello,base
    hello,base

    2)引用访问

    /************************main2.c********************/
    #include "classdef.h"
    int main()
    {
          base  obj_base;
          base& rBase1 = obj_base;
          child  obj_child;
          rBase1.disp();                       //基类引用调用虚函数,基类中的disp版本
          base&  rBase2 = obj_child;  
          rBase2.disp();                       //基类引用调用虚函数,派生类中的disp版本                
          return 0;
    }

    输出结果:

    hello,base
    hello,child

    3)类内访问,使用this指针。

    4)在构造函数或析构函数中进行访问

    class   base
    {
        public:
             virtual  void  disp()
             {
                  cout<<"hello,base"<<endl;
              }
    };
    
    class  child:public  base
    { 
          public:
              child()
             {
                  disp();
             }
              void disp()
              {
                    cout <<"hello,child"<<endl;
               }
    };

    在上述代码中,类创建child对象时,输出信息总是“hello,child”。换言之,在child的构造函数中,无论是用disp()还是this->disp()来调用,编译器都将之解释为“child::disp()”,此时,若想在child构造函数中调用base类disp函数,必须使用base::disp()的形式;

    2.纯虚函数与抽象类

    纯虚函数是一种特殊的虚函数,它是指不必再基类中定义,但必须在派生类中被覆盖的函数。其形式如下:

    virtual   类型  函数名   (参数表)=0

    一个类可以包含多种纯虚函数。只要类中含有一个纯虚函数,该类便为抽象类。一个抽象类只能作为基类来派生新类,不能创建抽象类的对象。

    1)另一种抽象类:类中只定义了protect型的构造函数。

    2)private型构造函数。不能在外部函数和派生类中使用“类名+对象吗”创建实例,但可以通过类的static函数成员来创建类的实例。

    3)虚析构函数。虽然构造函数不能被声明为虚函数,但析构函数可以,形式如下:

    virtual   ~析构函数名();

    析构函数调用不当带来的内存泄漏:

    class   base
    {
        privatechar* data
        public:
             base()
             {
                  data  = new char[64];
                  cout<<"base类构造函数被调用"<<endl;
              };
             ~base()
             {
                   delete [] data;
                  cout<<"base类析构函数被调用"<<endl;
              };         
    };
    
    class   child : public  base
    {
        privatechar* m_data
        public:
             child():base()
             {
                  m_data  = new char[64];
                  cout<<"child类构造函数被调用"<<endl;
              };
             ~child()
             {
                   delete [] m_data;
                  cout<<"child类析构函数被调用"<<endl;
              };         
    };
    
    int main()
    {
          base *pB = new child;
          delete pB;
          return 0;
    }

    输出结果:

    base类析构函数被调用
    child类析构函数被调用
    base类析构函数被调用

    这段程序编译连接没有错,但是在“delete pB”中pB类型决定了调用哪个类的析构函数,因此编译器会调用base类的析构函数,这意味这child类析构函数没有被调用,child类中的m_data指向的内存泄漏了。

    解决方案:将基类中的析构函数定义为虚析构函数就能解决这个问题。

  • 相关阅读:
    一天一个 Linux 命令(44):ifstat 命令
    Java集合框架示意图
    Java中String类常见问题汇总
    一天一个 Linux 命令(43):netstat 命令
    Windows系统下,如何设置maven字符编码
    Java文件操作编程
    Java 注解(Annotation)
    Linux Centos7.4 更新Java jdk版本
    Java基础(6)Java数据类型扩展
    Windows系统下Elasticsearch7.15.2单服务器配置多节点
  • 原文地址:https://www.cnblogs.com/wlzy/p/5901875.html
Copyright © 2020-2023  润新知