過載、隱藏和重寫(有的書叫“覆蓋”)的區別?
阿新 • • 發佈:2019-02-03
1) 過載的特徵:
例子:
1)函式Derived::f(float)覆蓋(重寫)了Base::f(float)。
2)函式Derived::g(int)隱藏了Base::g(float),注意,不是過載。
3)函式Derived::h(float)隱藏了Base::h(float),而不是覆蓋。
而在隱藏方式中,用基類指標和派生類指標呼叫函式f()時,系統會進行區分,基類指標呼叫時,系統執行基類的f(),而派生類指標呼叫時,系統“隱藏”了基類的f(),執行派生類的f(),這也就是“隱藏”的由來。
a) 相同的範圍(在同一個類中)
b) 函式名字必須相同
c) 引數不同(指引數型別不同,或引數個數不同,或兩者皆有) d) virtual關鍵字可有可無
例子如下:
- class Base
- {
- public:
- void fun(void);
- int fun(int a);
- int fun(double b);
- int fun(int a, int b);
- int fun(int a, double b);
- };
上面Base類裡fun()屬於過載函式,主要函式的過載只是函式引數有關,和函式的返回值無關的。
如下面的例子,只是函式的返回值不同,不屬於函式的過載,編譯器會報錯。
- class Base
- {
- public:
- void fun(int a);
- double fun(int a);
- int fun(int a);
- };
(a)
- class Base
- {
- public:
- // virtual關鍵字可有可無
- void fun(int n){
- cout << "in the Base" << endl;
- }
- };
- class Derived: public Base
- {
- public:
- // 注意引數和基類的是不同的
- void fun(void){
- cout << "in the Derived" << endl;
-
}
- };
- /*
- 這時候,儘管派生類Derived公共繼承於基類Base,但是派生類Derive隱藏基類Base的fun(int n)的函式介面,Derive類的內部只有fun(void)函式。只要派生類Derive的fun()函式引數和基類的不一樣(和函式返回值無關),派生類就會隱藏基類的同名函式。
- */
- int main(void)
- {
- Derived test;
- test.fun(10);// 錯誤,Derived類沒fun(int)這個成員函式
- test.fun(); // 結果為:"in the Derived"
- return0;
- }
(b)
- class Base
- {
- public:
- //注意:沒有virtual關鍵字
- void fun(int n){
- cout << "in the Base" << endl;
- }
- };
- class Derived: public Base
- {
- public:
- // 引數和基類相同
- void fun(int n){
- cout << "in the Derived" << endl;
- }
- };
- int main(void)
- {
- Derived test;
- test.fun(10);
- /*
- 結果為:"in the Derived"
- 不是基類Base裡的"in the Base",因為派生類隱藏了基類同名的函式。
- */
- return0;
- }
- #include <iostream.h>
- class Base
- {
- public:
- void f(int x){ cout << "Base::f(int) " << x << endl; }
- void f(float x){ cout << "Base::f(float) " << x << endl; }
- // 必須有virtual關鍵字
- virtualvoid g(void){ cout << "Base::g(void)" << endl;}
- };
- class Derived : public Base
- {
- public:
- // virtual關鍵字,可有可無
- virtualvoid g(void){ cout << "Derived::g(void)" << endl;}
- };
- void main(void)
- {
- Derived d;
- Base *pb = &d;
- pb->f(42); // 執行結果: Base::f(int) 42
- pb->f(3.14f); // 執行結果: Base::f(float) 3.14
- pb->g(); // 執行結果: Derived::g(void) (動態聯編)
- }
綜合例子:
- #include <iostream.h>
- class Base
- {
- public:
- virtualvoid 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:
- virtualvoid 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),而不是覆蓋。
看完前面的示例,可能大家還沒明白隱藏與覆蓋到底有什麼區別,因為我們前面都是講的表面現象,怎樣的實現方式,屬於什麼情況。下面我們就要分析覆蓋與隱藏在應用中到底有什麼不同之處。在下面的程式中bp和dp指向同一地址,按理說執行結果應該是相同的,可事實並非如此。
- void main(void)
- {
- Derived d;
- Base *pb = &d; // Bad : behavior depends on type of the pointer
- Derived *pd = &d; // Good : behavior depends solely on type of the object
- // f()為虛擬函式,動態聯編
- pb->f(3.14f); //執行結果: Derived::f(float) 3.14
- pd->f(3.14f); //執行結果: Derived::f(float) 3.14
- pb->g(3.14f); //執行結果: Base::g(float) 3.14
- pd->g(3.14f); //執行結果: Derived::g(int) 3
- pb->h(3.14f); //執行結果: Base::h(float) 3.14
- pd->h(3.14f); //執行結果: Derived::h(float) 3.14
- }
請大家注意,f()函式屬於覆蓋,而g()與h()屬於隱藏。
從上面的執行結果,我們可以注意到在覆蓋中,用基類指標和派生類指標呼叫函式f()時,系統都是執行的派生類函式f(),而非基類的f(),這樣實際上就是完成的“介面”功能。而在隱藏方式中,用基類指標和派生類指標呼叫函式f()時,系統會進行區分,基類指標呼叫時,系統執行基類的f(),而派生類指標呼叫時,系統“隱藏”了基類的f(),執行派生類的f(),這也就是“隱藏”的由來。