C++ 成員函式的過載,繼承,覆蓋和隱藏
一、 C++成員函式的過載
C++中的成員函式有四種,分別是普通成員函式,virtual虛擬函式,const成員函式。
- (1) void func(int a);
- (2) virtual void func(int a);
- (3) void func(int a) const;
如果在一個類中,宣告這四種函式,哪是重複定義?哪些是過載?
其中(1)(2)是重複定義,故編譯不能通過,而(3)與(1)(2)是不同型別的函式,是過載。
成員函式被過載的特徵是:
- (1)具有相同的作用域(即同一個類定義中);
- (2)函式名字相同
- (3)引數型別,順序 或 數目不同(包括const引數和非const函式)
- (4)virtual關鍵字可有可無。
從成員函式的過載特徵中,可以知道(1)(2)是重複定義。那麼(3)為什麼和(1)(2)不同呢?
因為類中的函式,都會自動新增一個自身類指標this,所以
void func(int a) ==== void func(Base * this, int a) virtual func(int a) ==== virtual func(Base *this, int a) void func(int a)const === void func(const Base *this, int a) const
所以(3)可以與(1)(2)發生過載,因為引數有一個const。
二 、C++成員函式的繼承
#include <iostream> using namespace std; class Base { public: void f(int a){ cout << "Base::f(int a)" << endl; } virtual void g(int a) { cout << "virtual Base::g(int a)" << endl; } }; class Derived : public Base { public: void h(int a) { cout << "Derivd::h(int a)" << endl; } }; int main() { Base b; b.f(3); b.g(4); Derived d; d.f(3); d.g(4); d.h(3); } #include <iostream> using namespace std; class Base { public: void f(int a){ cout << "Base::f(int a)" << endl; } virtual void g(int a) { cout << "virtual Base::g(int a)" << endl; } }; class Derived : public Base { public: void h(int a) { cout << "Derivd::h(int a)" << endl; } }; int main() { Base b; b.f(3); b.g(4); Derived d; d.f(3); d.g(4); d.h(3); }
Base b的物件模型:
Derived d的物件模型:
則在子類Derived d中繼承了父類中的virtual void g(int a) ; void f(int a);
執行結果為:
三、C++成員函式的覆蓋
覆蓋是指派生類重新實現(或者改寫)了基類的成員函式,其特徵是:
- (1)不同的作用域(非別位於派生類和基類中);
- (2)函式名稱相同
- (3)引數列表完全相同;
- (4)基類函式必須是虛擬函式。
從(4)中我們得知覆蓋只是針對虛擬函式的。
#include <iostream> using namespace std; class Base { public: void f(int a){ cout << "Base::f(int a)" << endl; } virtual void g(int a) { cout << "virtual Base::g(int a)" << endl; } }; class Derived : public Base { public: void h(int a) { cout << "Derivd::h(int a)" << endl; } virtual void g(int a) { cout << "virtual Derived::g(int a)" << endl; } }; int main() { Base b; b.f(3); b.g(4); Derived d; d.f(3); d.g(4); d.h(3); } #include <iostream> using namespace std; class Base { public: void f(int a){ cout << "Base::f(int a)" << endl; } virtual void g(int a) { cout << "virtual Base::g(int a)" << endl; } }; class Derived : public Base { public: void h(int a) { cout << "Derivd::h(int a)" << endl; } virtual void g(int a) { cout << "virtual Derived::g(int a)" << endl; } }; int main() { Base b; b.f(3); b.g(4); Derived d; d.f(3); d.g(4); d.h(3); }
Derived d物件模型如下:
其中Derived中重新定義了基類的虛成員函式virtual void g(int a);
四、C++成員函式的隱藏
隱藏是指派生類的成員函式遮蔽了與其同名的基類成員函式,具體規則如下:
(1) 派生類的函式與基類的函式同名,但是引數列表有所差異。此時,不論有無virtual關鍵字,基類的函式在派生類中將被隱藏。(注意別與過載混合)
(2)派生類的函式與基類的函式同名,引數列表也相同,但是基類函式沒有virtual關鍵字。此時,基類的函式在派生類中將被吟唱。(注意別與覆蓋混合)
判斷下面哪些函式是覆蓋,哪些函式是隱藏?
#include <iostream> using namespace std; class Base { public: virtual void f(float x) { cout << "virtual 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 << "virtual 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; } }; int main(void) { Derived d; Base *pb = &d; Derived *pd = &d; pb->f(3.14f); pd->f(3.14f); pb->g(3.14f); pd->g(3.14f); pb->h(3.14f); pd->h(3.14f); } #include <iostream> using namespace std; class Base { public: virtual void f(float x) { cout << "virtual 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 << "virtual 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; } }; int main(void) { Derived d; Base *pb = &d; Derived *pd = &d; pb->f(3.14f); pd->f(3.14f); pb->g(3.14f); pd->g(3.14f); pb->h(3.14f); pd->h(3.14f); }
其中子類Derived中 vitual void f(float x) 是覆蓋,而void g(int x) 和void h(float x)都是隱藏。
執行結果:
再看一個例子:
#include <iostream> using namespace std; class Base { public: virtual void f(int a) { cout << "virtual Base::f(int a)" << endl; } void f(double d) { cout << "Base::f(double d)" << endl; } }; class Derived : public Base { public: void f(double d) { cout << "Derivd::f(double d)" << endl; } }; int main() { Derived d; d.f(3); d.f(2.5); Derived *pd = new Derived(); pd->f(3); pd->f(2.5); Base b; b.f(5); b.f(3.5); Base *pBase = new Derived(); pBase->f(5); pBase->f(3.5); } #include <iostream> using namespace std; class Base { public: virtual void f(int a) { cout << "virtual Base::f(int a)" << endl; } void f(double d) { cout << "Base::f(double d)" << endl; } }; class Derived : public Base { public: void f(double d) { cout << "Derivd::f(double d)" << endl; } }; int main() { Derived d; d.f(3); d.f(2.5); Derived *pd = new Derived(); pd->f(3); pd->f(2.5); Base b; b.f(5); b.f(3.5); Base *pBase = new Derived(); pBase->f(5); pBase->f(3.5); }
其中父類中的void f(double d)隱藏了子類的virtual void f(int a), void f(double d)函式。
所以在主函式中
Derived d; d.f(3); d.f(2.5); Derived *pd = new Derived(); pd->f(3); pd->f(2.5); Derived d; d.f(3); d.f(2.5); Derived *pd = new Derived(); pd->f(3); pd->f(2.5);只要通過Derived物件或者Derived指標執行f()函式,都只執行void Derived::f(double d)該函式。 [html] Base *pBase = new Derived(); pBase->f(5); pBase->f(3.5); Base *pBase = new Derived(); pBase->f(5); pBase->f(3.5);
在呼叫pBase->f(5)時,首先要去pBase類中找到對應需要執行的函式,因為Base類中有兩個函式virtual void f(int a) 和 void f(double)過載,因為該實參是5,為int型別,所以要呼叫virtual void f(int a)函式,因為該f(int a)是一個虛擬函式,所以再去判斷pBase所指向的具體物件,具體物件為Derived子類,再去Derived子類的虛擬函式表中找到void f(int a)函式。因為Derived子類繼承了父類Base的虛擬函式vitural void f(int a),所以輸出 virtual Base::f(int a);
在呼叫pBase->f(3.5)時,首先要去pBase類中找到對應需要執行的函式,因為因為Base類中有兩個函式virtual void f(int a) 和 void f(double)過載,因為該實參是3.5,為double類,所以要呼叫void f(double d)函式,因為該函式是一個普通成員函式,故直接輸出。 void Base::f(double d);
再舉一個例子:
#include <iostream> using namespace std; class Base { public: virtual void f(int a) { cout << "virtual Base::f(int a)" << endl; } void f(double d) { cout << "Base::f(double d)" << endl; } }; class Derived : public Base { public: void f(int a) { cout << "virtual Derived::f(int a)" << endl; } }; int main() { Derived d; d.f(3); d.f(2.5); Derived *pd = new Derived(); pd->f(3); pd->f(2.5); Base b; b.f(5); b.f(3.5); Base *pBase = new Derived(); pBase->f(5); pBase->f(3.5); } #include <iostream> using namespace std; class Base { public: virtual void f(int a) { cout << "virtual Base::f(int a)" << endl; } void f(double d) { cout << "Base::f(double d)" << endl; } }; class Derived : public Base { public: void f(int a) { cout << "virtual Derived::f(int a)" << endl; } }; int main() { Derived d; d.f(3); d.f(2.5); Derived *pd = new Derived(); pd->f(3); pd->f(2.5); Base b; b.f(5); b.f(3.5); Base *pBase = new Derived(); pBase->f(5); pBase->f(3.5); }
子類Derived中的void f(int a)既覆蓋了基類Base的虛擬函式virtual void f(int a),也隱藏了基類的virtual void f(int a), void f(double d)函式。
Derived d; d.f(3); d.f(2.5); Derived *pd = new Derived(); pd->f(3); pd->f(2.5); Derived d; d.f(3); d.f(2.5); Derived *pd = new Derived(); pd->f(3); pd->f(2.5);
同理所有用子類物件或者子類指標來呼叫f()函式時,都只執行virtual void f(int a),輸出virtual Derived::f(int a)
view plaincopyprint?Base *pBase = new Derived(); pBase->f(5); pBase->f(3.5); Base *pBase = new Derived(); pBase->f(5); pBase->f(3.5);
pBase->f(5),首先去Base類中尋找相應的函式,同理Base類中的兩個函式virtual void f(int a)和void f(double d)是過載函式,因為實參為5,為int型別,所以我們要呼叫virtual void f(int a)虛擬函式,因為該函式是虛擬函式,所以要去判斷pBase指向的具體物件,因為pBase指向的是一個子類的物件,所以需要去子類的虛擬函式表中取找virtual void f(int a)函式,找到之後,執行該函式,故輸出virtual Derived::f(int a)。
pBase->f(3.5),首先去Base類中尋找相應的函式,同理Base類中的兩個函式virtual void f(int a)和void f(double d)是過載函式,因為實參為3.5,為double型別,所以我們要呼叫void f(double d),因為該函式為普通成員函式,故執行輸出: void Base::f(double d);
相關文章
- C++之過載覆蓋和隱藏C++
- C++中的覆蓋和隱藏C++
- 類成員函式的重寫,過載和隱藏的區別函式
- Java基礎 成員變數的繼承與覆蓋Java變數繼承
- Performanced C++ 經驗規則(5):再談過載、覆蓋和隱藏ORMC++
- c++繼承,隱藏(重定義)C++繼承
- Java繼承中成員方法的overload(過載/過載)Java繼承
- C++ 派生類函式過載與虛擬函式繼承詳解C++函式繼承
- 繼承關係裡的六個預設成員函式繼承函式
- C++程式設計學習筆記:2 類和物件初探 內聯成員函式和過載成員函式C++程式設計筆記物件函式
- C++ 虛擬函式和虛繼承淺析C++函式繼承
- 繼承與派生,多繼承,函式過載,建構函式呼叫順序 靜態多型和動態多型繼承函式多型
- [C++] 成員函式指標和函式指標C++函式指標
- C++:類的成員函式C++函式
- c#之多型性_繼承_重寫_虛擬函式_new覆蓋整合測試C#多型繼承函式
- C++ 類成員函式C++函式
- C++繼承二之虛擬函式C++繼承函式
- C++ 繼承、多型、虛擬函式C++繼承多型函式
- c++中的隱藏及過載、重寫與隱藏的區別C++
- C++ 過載運算子和過載函式C++函式
- C++ 函式過載和模板C++函式
- c++ const 成員函式C++函式
- 18、繼承以及繼承中成員變數和成員方法的重名問題繼承變數
- Javascript繼承2:建立即繼承—-建構函式繼承JavaScript繼承函式
- C/C++—— C++中函式重寫和函式過載C++函式
- 【c++】cout過載能不能寫成成員函式,若能,寫出函式原型,若不能,說明原因C++函式原型
- C++的函式過載C++函式
- C++ 函式過載,函式模板和函式模板過載,選擇哪一個?C++函式
- JavaScript中的函式繼承JavaScript函式繼承
- 函式指標使用c++類成員函式函式指標C++
- 類&成員可見性&繼承繼承
- C++函式過載C++函式
- C++的函式的過載C++函式
- 在 C++ 中子類繼承和呼叫父類的建構函式方法C++繼承函式
- 在C++中子類繼承和呼叫父類的建構函式方法C++繼承函式
- JS原型繼承和類式繼承JS原型繼承
- C++單繼承、多繼承情況下的虛擬函式表分析C++繼承函式
- 深入C++成員函式及虛擬函式表C++函式