覆蓋與隱藏

2021-09-24 02:23:58 字數 1773 閱讀 6391

下面程式的輸出是()

class a

virtual void fun()

};class b:public a

void fun() };

int main(void)

a.121434

b.121414

c.121232

d.123434

b首先宣告為a型別的指標指向實際型別為a的物件,呼叫的肯定是a的方法,輸出1 2,

然後宣告為a型別的指標指向實際型別為b的物件,則非虛函式呼叫a的方法,輸出1,虛函式呼叫實際型別b的方法,輸出4

宣告型別為a的指標指向實際型別為b的物件,進行乙個強制型別轉換,其實這種父類指標指向子類會自動進行型別轉換,所以是否強制型別轉換都不影響結構,原理同上一步,結果輸出1 4

所以最終輸出為121414

大家都覺得很自然,但是沒有注意到乙個小插曲,就是這個foo()觸發的隱藏機制: 派生類的foo()由於函式名,引數與基類都相同,然而又沒有virtual修飾,因此不可避免地會觸發隱藏。

問題是,看到有同學問: 為什麼此處觸發隱藏了,p和ptr在呼叫foo()的時候仍然呼叫基類的,不是被隱藏了麼???

這麼問的原因是,很多同學知道了有隱藏這麼回事,但是不清楚隱藏觸發後會發生什麼。 隱藏機制觸發之後,指標的呼叫取決於指標的型別。如果定義的是派生類指標,則該基類成員不可見(隱藏),但是若為基類指標,該基類成員仍然是可見的啊!因為此處的p和ptr均為基類指標,只是分別指向了基類和派生類物件,所以呼叫foo()的時候仍然是基類的成員。

但是如果定義個派生類指標pb,如下:

b *pb=&b;

pb->foo();

這時只會呼叫派生類的foo(),雖然b繼承自a,但是基類的foo()會被隱藏

這樣看起來似乎莫名其妙,因為你想當然地認為派生類的指標肯定呼叫自己的成員啊,隱藏存在的意義是什麼?就像此題,不用考慮它我也能做對!

但是一旦foo()裡有引數的時候,你就會大吃一驚!

假設a中為void foo(float a),b中為void foo(int a):

做如下呼叫:

b *pb=&b;

pb->foo(3.14);

到底會呼叫誰?你可能會想: 首先foo()成員不是虛函式,但是b繼承a,b中有兩個foo(),呼叫foo(3.14)時根據引數型別應該匹配基類的void foo(float)成員。

然而並不是!

因為觸發了隱藏機制,基類的void foo(float)會被隱藏,所以即使你呼叫foo(3.14)仍然只會呼叫派生類的void foo(int)成員。

你的驚訝正好解釋了隱藏機制存在的意義。

(ps:牛客網上c/c++專項訓練上有專門一道題考察這種情況,當時解釋裡提出隱藏機制時大多數人也是一臉懵逼)

總結:1.判斷要點:如果不是過載也不是覆蓋,派生類和基類中一旦出現同名函式,一定觸發隱藏機制(這是個簡便判斷技巧,你可以考慮除去過載和覆蓋的任何同名函式情況,一定滿足隱藏機制觸發的兩條規則)。

2.隱藏觸發的結果:指針對成員的函式呼叫取決於指標型別。

若本身是基類指標(不管指向基類還是派生類)則仍然呼叫基類成員(不會牽扯到派生類,此處是隱藏,和多型沒關係,按第1點已說明隱藏的觸發可以首先排除覆蓋,也就是多型問題);

若本身是派生類指標,這時你就會看到隱藏的威力!此時不是簡單地繼承基類的成員,然後根據引數匹配呼叫,而是隱藏基類成員,只會呼叫派生類成員。

隱藏與覆蓋

成員函式的過載 overload 覆蓋 override 與隱藏很容易混淆,c 程式設計師必須要搞清楚概念,否則錯誤將防不勝防。1 過載與覆蓋 成員函式被過載的特徵 1 相同的範圍 在同乙個類中 2 函式名字相同 3 引數不同 4 virtual 關鍵字可有可無。覆蓋是指派生類函式覆蓋基類函式,特徵...

覆蓋與隱藏

覆蓋是占用了原來的位置,隱藏只是存在找不到 例如 class a void fun1 int v static void fun2 int v class b extends a void fun1 int u static void fun2 int u a a new b a.fun1 呼叫的是...

過載 覆蓋與隱藏

一 總結如下表 函式名均相同 引數返回值型別 virtual有無 類別父類子類間 方法為public 繼承為public同同 必須有override同異 有編譯不通過同 均可無hide異均可 無關hide 同一類內同異 無關編譯不通過異 均可無關 overload 二 幾點說明 override 重...