談談重載(overload)覆蓋(override)與隱藏

       這三個概念都是與OO中的多態有關係的。如果單是區別重載與覆蓋這兩個概念是比較容易的,但是隱藏這一概念卻使問題變得有點複雜了,下面說說它們的區別吧。

       重載是指不同的函數使用相同的函數名,但是函數的參數個數或類型不同。調用的時候根據函數的參數來區別不同的函數。

       覆蓋(也叫重寫)是指在派生類中重新對基類中的虛函數(注意是虛函數)重新實現。即函數名和參數都一樣,只是函數的實現體不一樣。

       隱藏是指派生類中的函數把基類中相同名字的函數屏蔽掉了。隱藏與另外兩個概念表面上看來很像,很難區分,其實他們的關鍵區別就是在多態的實現上。什麼叫多態?簡單地說就是一個接口,多種實現吧。

       還是引用一下別人的代碼來說明問題吧(引用自林銳的《高質量C/C++編程指南》)。

仔細看下面的代碼:

#include <iostream.h>

    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)函數Derived::f(float)覆蓋了Base::f(float)。

2)函數Derived::g(int)隱藏了Base::g(float),而不是重載。

3)函數Derived::h(float)隱藏了Base::h(float),而不是覆蓋。

       嗯,概念大概明白了,但是在實際的編程中,我們會因此遇到什麼問題呢?再看下面的代碼:

void main(void)

{

Derived  d;

Base *pb = &d;

Derived *pd = &d;

// Good : behavior depends solely on type of the object

pb->f(3.14f); // Derived::f(float) 3.14

pd->f(3.14f); // Derived::f(float) 3.14

 

// Bad : behavior depends on type of the pointer

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

pd->g(3.14f); // Derived::g(int) 3        (surprise!)

 

// Bad : behavior depends on type of the pointer

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

pd->h(3.14f); // Derived::h(float) 3.14

}

在第一種調用中,函數的行爲取決於指針所指向的對象。在第二第三種調用中,函數的行爲取決於指針的類型。所以說,隱藏破壞了面向對象編程中多態這一特性,會使得OOP人員產生混亂。

不過隱藏也並不是一無是處,它可以幫助編程人員在編譯時期找出一些錯誤的調用。但我覺得還是應該儘量不要使用隱藏這一些特性,該加virtual時就加吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章