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++繼承
- C++ 派生類函式過載與虛擬函式繼承詳解C++函式繼承
- 繼承關係裡的六個預設成員函式繼承函式
- 18、繼承以及繼承中成員變數和成員方法的重名問題繼承變數
- [C++] 成員函式指標和函式指標C++函式指標
- C++:類的成員函式C++函式
- c++ const 成員函式C++函式
- C++ 類成員函式C++函式
- C++ 函式過載和模板C++函式
- C++ 過載運算子和過載函式C++函式
- C++ 函式過載,函式模板和函式模板過載,選擇哪一個?C++函式
- Javascript繼承2:建立即繼承—-建構函式繼承JavaScript繼承函式
- JavaScript中的函式繼承JavaScript函式繼承
- C++函式過載C++函式
- C++單繼承、多繼承情況下的虛擬函式表分析C++繼承函式
- 深入C++成員函式及虛擬函式表C++函式
- 類&成員可見性&繼承繼承
- 繼承中的建構函式繼承函式
- js建構函式的繼承JS函式繼承
- C++之函式過載C++函式
- 118 C++中函式的過載C++函式
- 開心檔之C++ 過載運算子和過載函式C++函式
- c++智慧指標中的reset成員函式C++指標函式
- C++ 中的 const 物件與 const 成員函式C++物件函式
- Java中的過載和覆蓋的細微差別 - rajivprabJava
- python入門基礎(14)--類的屬性、成員方法、靜態方法以及繼承、過載Python繼承
- python3-----繼承 過載Python繼承
- C++中公有繼承、保護繼承、私有繼承的區別C++繼承
- C++繼承C++繼承
- Java建構函式的繼承問題Java函式繼承
- QImage:使用QImage建構函式載入影像和使用成員函式loadFromData載入影像的區別函式
- C++中的繼承C++繼承
- C++ 成員函式指標簡單測試C++函式指標
- C++特殊成員函式及其生成機制C++函式
- C++ 獲取指定的過載函式地址C++函式
- C++ 成員資料指標成員函式指標簡單測試C++指標函式
- 建構函式、原型、原型鏈、繼承函式原型繼承
- [c++] 繼承和多型整理二C++繼承多型