C++ 重载、覆盖、隐藏

~~~~个人生活,个人点点滴滴!!ios




(1) 重载的几个函数必须在同一个类中, 覆盖的函数必须在有继承关系的不一样的类中, 隐藏也必须在有继承关系的不一样的类中;


(2) 覆盖的函数前必须加关键字Virtual;重载和Virtual没有任何瓜葛,加不加都不影响重载的运做,隐藏对virtual无关紧要


(3) 覆盖的几个函数必须函数名、参数、返回值都相同;


(4) 重载的函数必须函数名相同,参数不一样, 返回值也要相同;


      重载的函数必须函数名相同,参数不一样。参数不一样的目的就是为了在函数调用的时候编译器可以经过参数来判断程序是在调用的
函数

哪一个函数。这也就很天然地解释了为何函数不能经过返回值不一样来重载,由于程序在调用函数时颇有可能不关心返回值,编译器就无spa

法从代码中看出程序在调用的是哪一个函数了。
  
     "隐藏"是指派生类的函数屏蔽了与其同名的基类函数,规则以下:
 
(1)若是派生类的函数与基类的函数同名,可是参数不一样。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。   


(2)若是派生类的函数与基类的函数同名,而且参数也相同,可是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。  

指针



#include <QCoreApplication>
#include <QDebug>

#include <iostream>

using namespace std;

class Base

{

public:


    virtual void f(float x){ qDebug() << "Base::f(float) " << x ; }


    void g(float x){ qDebug() << "Base::g(float) " << x ; }


    void h(float x){ qDebug() << "Base::h(float) " << x ; }


};


class Derived : public Base

{

public:


    virtual void f(float x){ qDebug() << "Derived::f(float) " << x ; }
    //重载
    void g(int x){ qDebug() << "Derived::g(int) " << x ; }

    void g(float x) { qDebug() << "Derived::g(float)" << x ; }

    void h(int x){ qDebug() << "Derived::h(int) " << x ; }

};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Derived d;


    Base *pb = &d;


    Derived *pd = &d;


    // Good 行为 ---- 覆盖

    // f()函数是virtual,pb又是父指针,他指向派生类,多态的体现
    // Derived::f(float) 3.14
    pb->f(3.14f);

    // pd是派生类指针,因此他确定是调用本身的函数
    // Derived::f(float) 3.14
    pd->f(3.14f); //


    // Bad 行为 ---- 隐藏与重载

    // Base::g(float) 3.14
    pb->g(3.14f);

    // g(float)非virtual函数,父类与子类中都有,这样就是隐藏
    // Derived::g(float) 3.14
    pd->g(3.14f);

    // Derived::g(int) 4
    pd->g(4);

    //特别注意,若是派生类中没有g(float)只有g(int)函数,那么pd->g(3.14f);
    //会输出 Derived::g(int) 3 是否是以为很惊讶,本身能够试试,下面就展现出了
    //我刚才说的问题

    // Bad 行为 ---- 隐藏

    // Base::h(float) 3.14
    pb->h(3.14f);

    // Derived::h(int) 3 惊讶!!!
    pd->h(3.14f);

    return a.exec();
}

输出结果:



其实这样来理解就比较容易搞懂了:   


一、虚函数的使用有特殊性,在使用的时候会查询指针所指对象内的虚函数表来肯定具体应该调用的函数地址。所以调用虚函数的时候优先使用指针
code

所指对象的类函数,而不是其基类的类函数,若是找不到则才从其基类中找一个匹配的成员函数   



二、非虚成员函数的调用则是直接调用指针所指类对象的成员函数,而不会动态编译。 
  
  
   上面例子中pb是基类指针,pd是派生类指针,pd的全部函数调用都只是调用本身的函数,和多态性无关,因此pd的全部函数调用的结果都输出Derived::是彻底正常的,
对象

pb的函数调用若是有virtual则根据多态性调用派生类的,若是没有virtual则是正常的静态函数调用,仍是调用基类的,因此有virtual的f函数调用输出Derived::,其它blog

两个没有virtual则仍是输出Base::很正常啊,nothing surprise! 

继承

记住“只有在经过基类指针或引用间接指向派生类子类型时多态性才会起做用”编译器