(1) C++:過載、覆蓋與隱藏
C++之中的過載、覆蓋、隱藏
過載
過載是指函式不同的引數表,對同名函式的名稱做修飾,然後這些同名函式就成了不同的函式。在同一可訪問區域內被宣告的幾個具有不同引數列表(引數型別、個數、順序不同)的同名函式,程式會根據不同的引數列來確定具體呼叫哪個函式。對於過載函式的呼叫,在編譯期間就已經確定,是靜態的,它們的地址在編譯期間就綁定了與多型無關。
注意:過載不關心函式的返回值型別
特徵:
(1)相同的範圍(在同一個類中)
(2)函式名字相同
(3)引數不同
(4)virtual 關鍵字可有可無
覆蓋
覆蓋是指派生類中存在重新定義基類的函式,其函式名、引數列、返回值型別必須同負類中的相對應被覆蓋的函式嚴格一致,覆蓋函式和被覆蓋函式只有函式體不同,當派生類物件呼叫子類中該同名函式時會自動呼叫子類中的覆蓋版本,而不是負類中的被覆蓋函式版本,它和多型真正相關。當子類重新定義了負類的虛擬函式後,負類指標根據賦給它的不同的子類指標,動態地呼叫屬於子類的該函式,這樣的函式呼叫在編譯期間是無法確定的(呼叫的子類的虛擬函式的地址無法給出)。因此,這樣的函式地址是在執行期繫結的。。
覆蓋特徵
(1)不同的範圍(分別位於派生類與基類)
(2)函式名字相同
(3)引數相同
(4)基類函式必須有virtual關鍵字
過載與覆蓋的區別
(1)覆蓋是子類與父類之間的關係,是垂直關係;過載是同一個類中方法之間的關係,是水平關係
(2)覆蓋只能由一個方法,或只能由一堆方法產生關係:方法的過載是多個方法之間的關係。
(3)覆蓋要求引數列表相同;過載要求引數列表不同
(4)覆蓋關係中,呼叫方法體是根據物件的型別(物件對應儲存空間型別)來決定的,過載關係是根據呼叫時的實參表與形參表來選擇方法體的
相關程式碼
// Base::f(int) 與 Base::f(float)相互過載
// Base::g(void) 被Derived::g(void)覆蓋
#include<iostream>
using namespace std;
class Base
{
public:
void f( int x )
{
cout << "Base::f( int )" << x << endl;
}
void f(float x )
{
cout << "Base::f( float )" << x << endl;
}
virtual void g( void )
{
cout << "Base::g( void )" << endl;
}
};
class Derived: public Base
{
public:
virtual void g( void )
{
cout << "Derived::g( void )" << endl;
}
};
int main()
{
Derived d;
Base *pb = &d;
pb->f( 42 );
pb->f( 3.14f );
pb->g();
return 0;
}
隱藏
隱藏是指派生類的函式遮蔽了與其同名的基類函式,規則如下
(1)如果派生類的函式與基類的函式同名,但是引數不同,則不論有無virtual關鍵字,基類的函式都將被隱藏
(2)如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有virtual關鍵字,此時基類的函式被隱藏
在呼叫一個類的成員函式時,編譯器會沿著類的繼承鏈逐級地向上查詢函式的定義,如果找到了就停止查找了,所以,如果一個派生類和一個基類都存在同名(暫時不論引數是否相同)的函式,而編譯器最終選擇了在派生類中的函式,那麼久說這個派生類的成員函式“隱藏”了基類的成員函式,也就是組織了編譯器繼續向上查詢函式的定義。
隱藏關係:
(1)必須分別位於派生類和基類中
(2)必須同名
(3)引數不同的時候本身已經不構成覆蓋關係了,所以此時是否是virtual函式已經不重要了
(4)引數相同的時候,看是否有virtual關鍵字,有的話就是覆蓋關係,沒有的時候就是隱藏關係了。
------------------------------------------------------------------------------------------------------------
關於我自己
* 一個正派但不正經的程式設計師
* 18年計算機專業碩士畢業生,騰訊SNG部門實習生,現加盟快手科技 ,後端研發工程師一枚
* 喜歡技術,喜歡網際網路
* 民遙控 ,趙雷、陳粒、宋冬野
* 公眾號:程式設計美學,時不時寫篇文章,偶爾數羊,其實說到底,只是想和你聊聊