1. 程式人生 > >過載、隱藏和重寫(有的書叫“覆蓋”)的區別?

過載、隱藏和重寫(有的書叫“覆蓋”)的區別?

1) 過載的特徵:
    a) 相同的範圍(在同一個類中)
    b) 函式名字必須相同 
    c) 引數不同(指引數型別不同,或引數個數不同,或兩者皆有) 
    d) virtual關鍵字可有可無

例子如下:

  1. class Base  
  2. {  
  3. public:  
  4.     void fun(void);  
  5.     int fun(int a);  
  6.     int fun(double b);  
  7.     int fun(int a, int b);  
  8.     int fun(int a, double b);  
  9. };  

上面Base類裡fun()屬於過載函式,主要函式的過載只是函式引數有關,和函式的返回值無關的。

如下面的例子,只是函式的返回值不同,不屬於函式的過載,編譯器會報錯。

  1. class Base  
  2. {  
  3. public:  
  4.     void fun(int a);  
  5.     double fun(int a);  
  6.     int fun(int a);  
  7. };  
2) 隱藏是指派生類的函式遮蔽了與其同名的基類函式。 規則如下: a)如果派生類的函式與基類的函式同名,但是引數不同。此時,不論有無virtual關鍵字,   基類的函式將被隱藏(注意別與過載混淆)。  b)如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有virtual關鍵字。此時,基類的函式被隱藏(注意別與重寫(覆蓋)混淆)。
例子:

(a)

  1. class Base  
  2. {  
  3. public:  
  4.     // virtual關鍵字可有可無
  5.     void fun(int n){   
  6.         cout << "in the Base" << endl;   
  7.     }  
  8. };  
  9. class Derivedpublic Base  
  10. {  
  11. public:   
  12.     // 注意引數和基類的是不同的 
  13.     void fun(void){   
  14.         cout << "in the Derived" << endl;  
  15.     }  
  16. };  
  17. /* 
  18. 這時候,儘管派生類Derived公共繼承於基類Base,但是派生類Derive隱藏基類Base的fun(int n)的函式介面,Derive類的內部只有fun(void)函式。只要派生類Derive的fun()函式引數和基類的不一樣(和函式返回值無關),派生類就會隱藏基類的同名函式。 
  19. */
  20. int main(void)  
  21. {  
  22.     Derived test;  
  23.     test.fun(10);// 錯誤,Derived類沒fun(int)這個成員函式
  24.     test.fun();   // 結果為:"in the Derived"
  25.     return0;  
  26. }  

(b)

  1. class Base  
  2. {  
  3. public:  
  4.     //注意:沒有virtual關鍵字
  5.     void fun(int n){  
  6.         cout << "in the Base" << endl;  
  7.     }  
  8. };  
  9. class Derivedpublic Base  
  10. {  
  11. public:  
  12.     // 引數和基類相同
  13.     void fun(int n){  
  14.         cout << "in the Derived" << endl;  
  15.     }  
  16. };  
  17. int main(void)  
  18. {  
  19.     Derived test;  
  20.     test.fun(10);    
  21.     /* 
  22.     結果為:"in the Derived" 
  23.     不是基類Base裡的"in the Base",因為派生類隱藏了基類同名的函式。 
  24.     */
  25.     return0;  
  26. }  
 3) 重寫(覆蓋)的特徵有:         a) 不同的範圍(分別位於派生類與基類)        b) 函式名字必須相同        c) 引數必須相同        d) 基類函式必須有virtual關鍵字 例子:
  1. #include <iostream.h> 
  2. class Base   
  3. {   
  4. public:   
  5.     void f(int x){ cout << "Base::f(int) " << x << endl; }   
  6.     void f(float x){ cout << "Base::f(float) " << x << endl; }  
  7.     // 必須有virtual關鍵字
  8.     virtualvoid g(void){ cout << "Base::g(void)" << endl;}   
  9. };   
  10. class Derived : public Base   
  11. {   
  12. public:   
  13.     // virtual關鍵字,可有可無
  14.     virtualvoid g(void){ cout << "Derived::g(void)" << endl;}   
  15. };   
  16. void main(void)   
  17. {   
  18.     Derived d;   
  19.     Base *pb = &d;   
  20.     pb->f(42);     // 執行結果: Base::f(int) 42 
  21.     pb->f(3.14f);  // 執行結果: Base::f(float) 3.14 
  22.     pb->g();       // 執行結果: Derived::g(void) (動態聯編) 
  23. }   

綜合例子:

  1. #include <iostream.h> 
  2. class Base   
  3. {   
  4. public:   
  5.     virtualvoid f(float x){ cout << "Base::f(float) " << x << endl; }   
  6.     void g(float x){ cout << "Base::g(float) " << x << endl; }   
  7.     void h(float x){ cout << "Base::h(float) " << x << endl; }   
  8. };   
  9. class Derived : public Base   
  10. {   
  11. public:   
  12.     virtualvoid f(float x){ cout << "Derived::f(float) " << x << endl; }   
  13.     void g(int x){ cout << "Derived::g(int) " << x << endl; }   
  14.     void h(float x){ cout << "Derived::h(float) " << x << endl; }   
  15. };   
通過分析可得: 
1)函式Derived::f(float)覆蓋(重寫)了Base::f(float)。 
2)函式Derived::g(int)隱藏了Base::g(float),注意,不是過載。 
3)函式Derived::h(float)隱藏了Base::h(float),而不是覆蓋。

看完前面的示例,可能大家還沒明白隱藏與覆蓋到底有什麼區別,因為我們前面都是講的表面現象,怎樣的實現方式,屬於什麼情況。下面我們就要分析覆蓋與隱藏在應用中到底有什麼不同之處。在下面的程式中bp和dp指向同一地址,按理說執行結果應該是相同的,可事實並非如此。 

  1. void main(void)   
  2. {   
  3.     Derived d;   
  4.     Base *pb = &d;   // Bad : behavior depends on type of the pointer 
  5.     Derived *pd = &d; // Good : behavior depends solely on type of the object
  6.     // f()為虛擬函式,動態聯編
  7.     pb->f(3.14f); //執行結果: Derived::f(float) 3.14 
  8.     pd->f(3.14f); //執行結果: Derived::f(float) 3.14 
  9.     pb->g(3.14f); //執行結果: Base::g(float) 3.14 
  10.     pd->g(3.14f); //執行結果: Derived::g(int) 3 
  11.     pb->h(3.14f); //執行結果: Base::h(float) 3.14 
  12.     pd->h(3.14f); //執行結果: Derived::h(float) 3.14 
  13. }    

請大家注意,f()函式屬於覆蓋,而g()與h()屬於隱藏。

從上面的執行結果,我們可以注意到在覆蓋中,用基類指標和派生類指標呼叫函式f()時,系統都是執行的派生類函式f(),而非基類的f(),這樣實際上就是完成的“介面”功能。
而在隱藏方式中,用基類指標和派生類指標呼叫函式f()時,系統會進行區分,基類指標呼叫時,系統執行基類的f(),而派生類指標呼叫時,系統“隱藏”了基類的f(),執行派生類的f(),這也就是“隱藏”的由來。