• C++之虚函数和多态


    干货较多-需要自己深思理解:

    C++支持两种多态性:
    1.编译时多态性(静态绑定-早绑定)
    在程序编译阶段即可以确定下来的多态性
    通过使用 重载机制(重载函数)实现

    (模板)http://blog.csdn.net/my_business/article/details/12194691

    2.运行时多态性(动态绑定-晚绑定)
    必须等到程序运行时才能确定的多态性
    要通过 虚函数 来实现

    http://blog.csdn.net/zp752963831/article/details/46635885

    第一个父类中 把某个函数 定义成虚函数 ,那么在他的子类中 无论是否加 virtual 都是 虚函数。

    例子:

    class Base
    {
    public:
    virtual void fun(int i)
    {
    OutputDebugString(_T("Base::fun(int i)"));
    }
    };
    
    class BaseA :public Base
    {
    public:
    virtual void fun(int i)
    { 
    OutputDebugString(_T("BaseA::fun(int i)"));
    }
    };
    View Code

    其中BaseB 的fun函数 加与不加virtual函数都无所谓,其都是虚函数

    但是如果他继续作为基类,并且要用到多态,则其应该加一个virtual

     

    虚函数的访问权限:
    派生类中所定义的虚函数的访问权限 不会影响对它的晚绑定
    (即:只有在第一个父类中定义的public,private或protect才对 虚函数的访问 有控制功能)

    晚绑定 和 实例化对象 的 class 中函数的访问权限有关

    class base
    {
    public:
        base():strBase(_T("base"))
        {
            log();
        }
        virtual void log()
        {
            MessageBox(::GetTopWindow(NULL), _T("base"), _T("base"), MB_OK);
        }
    public:
        param strBase;
        param* pStr;
    };
    
    class child : public base
    {
    public:
        child()
        {
    
        }
        /*child(const child& other)
        {
            pStr = new param(_T("child2"));
        }*/
    pritave:
    virtual void log() { MessageBox(::GetTopWindow(NULL), _T("child"), _T("child"), MB_OK); } public: };
    int main()
    {
      base * pBase = new child();
      pBase->log();//ok
      child* pChild = static_cast<child*> pBase;
      pChild->log();//error
    }

    在成员函数中调用虚函数:
    在一个基类或派生类的虚或非虚成员函数中可以直接调
    用该类体系的虚函数或非虚函数

    class base
    {
    public:
        base()
        {
            log();
        }
            void go()
        {
            log();
        }
        virtual void log()
        {
            MessageBox(::GetTopWindow(NULL), _T("base"), _T("base"), MB_OK);
        }
    };
    
    class child : public base
    {
    public:
        child()
        {
    
        }
        void go()
        {
            log();
        }
    private:
        virtual void log()
        {
            MessageBox(::GetTopWindow(NULL), _T("child"), _T("child"), MB_OK);
        }
    
    public:
    
    };
    int main()
    {
            base * pBase = new child();
        pBase->go();//ok  调用父类的go,内部调用子类的log函数。
        child* pChild = static_cast<child*>(pBase);
        pChild->go(); //go 内部直接调用自己的
    }        

    在构造/析构函数中调用虚函数:
    在构造函数或析构函数中调用虚函数时,采用的是早绑定。
    也就是虚函数机制在构造函数中不工作。

    class base
    {
    public:
        base()
        {
            log();
        }
        void go()
        {
            log();
        }
        virtual void log()
        {
            MessageBox(::GetTopWindow(NULL), _T("base"), _T("base"), MB_OK);
        }
    };
    
    class child : public base
    {
    public:
        child()
        {
            log();
        }
        void go()
        {
            log();
        }
    private:
        virtual void log()
        {
            MessageBox(::GetTopWindow(NULL), _T("child"), _T("child"), MB_OK);
        }
    };
    int main()
    {
            base * pBase = new child();//构造父类时,父类构造调用自己的            //    log    ,子类构造,则用子类的log函数。
    }                    

    虚函数和缺省实参:
    运行的函数是派生来的函数,但使用的缺省实参是父类里的缺省实参
    即:虚函数的缺省实参不支持晚绑定。

    class base
    {
    public:
        base()
        {
        }
        virtual void log(int paramI = 1)
        {
            SStringT str = paramI;
            OutputDebugString(str);
        }
    };
    
    class child : public base
    {
    public:
        child()
        {
        }
        virtual void log(int paramI = 2)
        {
            SStringT str = paramI;
            OutputDebugString(str);
        }
    };
    int main()
    {
            base * pBase = new child();
        pBase->log();//  输出 1
        child* pChild = static_cast<child*>(pBase);
        pChild->log();        //输出2
    }    

    纯虚函数:
    定义:纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。
    在基类中实现纯虚函数的方法是在函数原型后加“ =0”:virtual void funtion1()=0
    *引入原因:
    1)为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。
    2)在很多情况下,基类本身生成对象是不合情理的。

    3)实现接口

    引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要
    求在派生类中必须予以重载以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。

    1  

    覆盖:
    在c++中,派生类继承了基类的全部特征,但有时为了更加准确地描述客观世界的对象,需要对从基类继承来的接口函数进行修改:
    这可以通过在派生类中定义一个与基类同名,而返回值,参数类型,顺序或个数都可同可不同的函数,
    这样,通过派生类对象调用该同类型的函数时,调用的是派生类中定义的函数。也就是说,
    派生类修改了从基类继承来的接口行为,也可称为派生类的函数覆盖了基类中的同名函数。


    重载:重载类成员函数与覆盖 有点类似:相同的方法(函数名)完成不同的行为


    覆盖和重载的 区别:
    1.重载是与被重载函数同名,而参数不同(类型、顺序或者数量,至少三者之一不同),返回值可同可不同的另一个函数。
    2.重载函数必须在同一个类中或不属于类成员的普通函数之间,不能分布在基类与派生类中。
    3.覆盖是,在基类与派生类中出现的标示符同名的情况。

    注:
    1.虚函数是一组特殊的覆盖函数,同组虚函数间要求函数名、返回值、参数类型、数量、顺序都相同。
    通过对象名调用虚函数时,与调用覆盖函数的规则一样-----采用早绑定。
    通过对象的指针或引用调用虚函数时采用晚绑定,调用的是指针实际指向,或实际引用的对象对应的类中定义的虚函数

    2.如果类外的两个同名函数,或同类中两个同名的成员函数参数相同,但返回值不同,编译器不认为是重载,而认为它们具有二义性,会给出错误提示。
    3.如果一组虚函数中,两个虚函数仅返回值不同,但其参数和名字都相同,编译器也认为出错。

    三者比较表格:

    *=======================================================================================*
    |函数名 |返回值 |参数 |绑定时间 |适用范围 |
    *---------------+---------------+---------------+-----------------------+---------------*
    |虚函数 |同 |同 |晚绑定(指针/引用调用)|基类与派生 |
    | | | |早绑定(对象名调用) |类之间 |
    *---------------+---------------+---------------+-----------------------+---------------*
    |重载函数 |可同可不同 |必须不同 |早绑定 |类外函数或同 |
    | | | | |一类中的函数 |
    *---------------+---------------+---------------+-----------------------+---------------*
    |覆盖函数 |可同可不同 |可同可不同 |早绑定(支配规则) |基类与派生类 |
    | | | | |之间 |
    *=======================================================================================*

  • 相关阅读:
    LeetCode: Longest Valid Parentheses 解题报告
    LeetCode: Generate Parentheses 解题报告
    Leetcode: LRU Cache 解题报告
    LeetCode: Maximal Rectangle 解题报告
    LeetCode: Min Stack 解题报告
    LeetCode: Restore IP Addresses 解题报告
    LeetCode: Longest Common Prefix 解题报告
    LeetCode: Regular Expression Matching 解题报告
    Python——rrdtool模块的安装
    python-xlsxwriter模块绘制表格
  • 原文地址:https://www.cnblogs.com/gaozhichao/p/5292905.html
Copyright © 2020-2023  润新知