重載是指不一樣的函數使用相同的函數名,可是函數的參數個數或類型不一樣。調用的時候根據函數的參數來區別不一樣的函數。 重載是對於在一個做用域中來講的,和父子不要緊 ios
覆蓋(也叫重寫)是指在派生類中從新對基類中的虛函數(注意是虛函數)從新實現。即函數名和參數都同樣,只是函數的實現體不同。 編程
隱藏是指派生類中的函數把基類中相同名字的函數屏蔽掉了。隱藏與另外兩個概念表面上看來很像,很難區分,其實他們的關鍵區別就是在多態的實現上。什麼叫多態?簡單地說就是一個接口,多種實現吧。只能經過子類調用. ide
仍是引用一下別人的代碼來講明問題吧(引用自林銳的《高質量C/C++編程指南》)。 函數
仔細看下面的代碼: spa
#include <iostream.h> .net class Base 指針 { 對象 public: blog 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時就加吧。
我的認爲, 只有子類有同名函數,那父親的一系列的同名函數們就不能用了