函數(shù)重載(overload)、函數(shù)覆蓋(override)

字號:

“overload”翻譯過來就是:超載,過載,重載,超出標準負荷;“override”翻譯過來是:重置,覆蓋,使原來的失去效果。
    先來說說重載的含義,在日常生活中我們經(jīng)常要清洗一些東西,比如洗車、洗衣服。盡管我們說話的時候并沒有明確地說用洗車的方式來洗車,或者用洗衣服的方式來洗一件衣服,但是誰也不會用洗衣服的方式來洗一輛車,否則等洗完時車早就散架了。考試大提示我們并不要那么明確地指出來就心知肚明,這就有重載的意思了。在同一可訪問區(qū)內(nèi)被聲名的幾個具有不同參數(shù)列的(參數(shù)的類型、個數(shù)、順序不同)同名函數(shù),程序會根據(jù)不同的參數(shù)列來確定具體調(diào)用哪個函數(shù),這種機制叫重載,重載不關(guān)心函數(shù)的返回值類型。這里,“重載”的“重”的意思不同于“輕重”的“重”,它是“重復”、“重疊”的意思。例如在同一可訪問區(qū)內(nèi)有:
    ① double calculate(double);
    ② double calculate(double,double);
    ③ double calculate(double, int);
    ④ double calculate(int, double);
    ⑤ double calculate(int);
    ⑥ float calculate(float);
    ⑦ float calculate(double);
    六個同名函數(shù)calculate,①②③④⑤⑥中任兩個均構(gòu)成重載,⑥和⑦也能構(gòu)成重載,而①和⑦卻不能構(gòu)成重載,因為①和⑦的參數(shù)相同。
    覆蓋是指派生類中存在重新定義的函數(shù),其函數(shù)名、參數(shù)列、返回值類型必須同父類中的相對應(yīng)被覆蓋的函數(shù)嚴格一致,覆蓋函數(shù)和被覆蓋函數(shù)只有函數(shù)體(花括號中的部分)不同,當派生類對象調(diào)用子類中該同名函數(shù)時會自動調(diào)用子類中的覆蓋版本,而不是父類中的被覆蓋函數(shù)版本,考試大,提示這種機制就叫做覆蓋。
    下面我們從成員函數(shù)的角度來講述重載和覆蓋的區(qū)別。
    成員函數(shù)被重載的特征有:
    1) 相同的范圍(在同一個類中)
    2) 函數(shù)名字相同
    3) 參數(shù)不同
    4) virtual關(guān)鍵字可有可無
    覆蓋的特征有:
    1) 不同的范圍(分別位于派生類與基類)
    2) 函數(shù)名字相同
    3) 參數(shù)相同
    4) 基類函數(shù)必須有virtual關(guān)鍵字
    比如,在下面的程序中:
    #include
    using namespace std;
    class Base
    {
    public:
    void f(int x){ cout << "Base::f(int) " << x << endl; }
    void f(float x){ cout << "Base::f(float) " << x << endl; }
    virtual void g(void){ cout << "Base::g(void)" << endl;}
    };
    class Derived : public Base
    {
    public:
    virtual void g(void){ cout << "Derived::g(void)" << endl;}
    };
    void main(void)
    {
    Derived d;
    Base *pb = &d;
    pb->f(42); // 運行結(jié)果: Base::f(int) 42
    pb->f(3.14f); // 運行結(jié)果: Base::f(float) 3.14
    pb->g(); // 運行結(jié)果: Derived::g(void)
    }
    函數(shù)Base::f(int)與Base::f(float)相互重載,而Base::g(void)被Derived::g(void)覆蓋。
    隱藏是指派生類的函數(shù)屏蔽了與其同名的基類函數(shù),規(guī)則如下:
    1) 如果派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同。此時,不論有無virtual關(guān)鍵字,基類的函數(shù)將被隱藏(注意別與重載混淆)。
    2) 如果派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,但是基類函數(shù)沒有virtual關(guān)鍵字。此時,基類的函數(shù)被隱藏(注意別與覆蓋混淆)。
    比如,在下面的程序中:
    #include
    using namespace std;
    class Base
    {
    public:
    virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
    void g(float x){ cout << "Base::g(float) " << x << endl; }
    void h(float x){ cout << "Base::h(float) " << x << endl; }
    };
    class Derived : public Base
    {
    public:
    virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
    void g(int x){ cout << "Derived::g(int) " << x << endl; }
    void h(float x){ cout << "Derived::h(float) " << x << endl; }
    };
    通過分析可得:
    1) 函數(shù)Derived::f(float)覆蓋了Base::f(float)
    2) 函數(shù)Derived::g(int)隱藏了Base::g(float),注意,不是重載
    3) 函數(shù)Derived::h(float)隱藏了Base::h(float),而不是覆蓋
    看完前面的示例,可能大家還沒明白隱藏與覆蓋到底有什么區(qū)別,因為我們前面都是講的表面現(xiàn)象,怎樣的實現(xiàn)方式,屬于什么情況。下面我們就要分析覆蓋與隱藏在應(yīng)用中到底有什么不同之處。在下面的程序中bp和dp指向同一地址,按理說運行結(jié)果應(yīng)該是相同的,可事實并非如此。
    void main(void)
    {
    Derived d;
    Base *pb = &d;
    Derived *pd = &d;
    // Good : behavior depends solely on type of the object
    pb->f(3.14f); //運行結(jié)果: Derived::f(float) 3.14
    pd->f(3.14f); //運行結(jié)果: Derived::f(float) 3.14
    // Bad : behavior depends on type of the pointer
    pb->g(3.14f); //運行結(jié)果: Base::g(float) 3.14
    pd->g(3.14f); //運行結(jié)果: Derived::g(int) 3
    // Bad : behavior depends on type of the pointer
    pb->h(3.14f); //運行結(jié)果: Base::h(float) 3.14
    pd->h(3.14f); //運行結(jié)果: Derived::h(float) 3.14
    }
    Examda提示: f()函數(shù)屬于覆蓋,而g()與h()屬于隱藏。從上面的運行結(jié)果,我們可以注意到在覆蓋中,用基類指針和派生類指針調(diào)用函數(shù)f()時,系統(tǒng)都是執(zhí)行的派生類函數(shù)f(),而非基類的f(),這樣實際上就是完成的“接口”功能。而在隱藏方式中,用基類指針和派生類指針調(diào)用函數(shù)f()時,系統(tǒng)會進行區(qū)分,基類指針調(diào)用時,系統(tǒng)執(zhí)行基類的f(),而派生類指針調(diào)用時,系統(tǒng)“隱藏”了基類的f(),執(zhí)行派生類的f(),這也就是“隱藏”的由來。