下面程式的輸出是()
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 重...