成员函数的重载、覆盖与隐藏(详细)【转】
(轉(zhuǎn)自:https://blog.csdn.net/weixin_42205987/article/details/81569744)
成員函數(shù)的重載、覆蓋與隱藏
成員函數(shù)的重載(overload)、覆蓋/重寫(override)與隱藏/重定義(hide)很容易混淆,C++程序員必須要搞清楚概念,否則錯(cuò)誤將防不勝防。(重寫——這個(gè)名詞可能是指覆蓋,也可能是指隱藏,在java和C++中有區(qū)別)
?
重載與覆蓋
成員函數(shù)被重載的特征:
(1)相同的范圍(在同一個(gè)類域中,注意這里的同一個(gè)類不是指只能發(fā)生在同一個(gè)類中)?
(2)函數(shù)名字相同?
(3)參數(shù)不同?
(4)virtual 關(guān)鍵字可有可無(wú)(若一個(gè)重載版本的函數(shù)面前有virtual修飾,則表示他是虛函數(shù),但他也是屬于重載的一個(gè)版本)
補(bǔ)充:1、重載不關(guān)心函數(shù)的返回類型,只關(guān)心參數(shù)的 類型,個(gè)數(shù),順序不同。
? ? ? ? ? ?2、不同的構(gòu)造函數(shù)(無(wú)參構(gòu)造、有參構(gòu)造、拷貝構(gòu)造)是重載的應(yīng)用
? ? ? ? ? ?3、重載關(guān)系只能發(fā)生在同一個(gè)類中嗎?非也。這時(shí)候你要深刻理解繼承,要知道一個(gè)子類所擁有的成員除了自己顯式寫出來(lái)的以外,還有父類遺傳下來(lái)的。所以子類中的某個(gè)方法和父類中繼承下來(lái)的方法也可以發(fā)生重載的關(guān)系。
覆蓋(也叫重寫)是指派生類函數(shù)覆蓋基類函數(shù),特征是:
(1)不同的范圍(分別位于派生類與基類)?
(2)函數(shù)名字相同?
(3)參數(shù)相同?
(4) 基類函數(shù)必須有virtual 關(guān)鍵字
補(bǔ)充:1、返回值類型也要相同。
? ? ? ? ? ?2、不能是final類型的。因?yàn)閒inal修飾的方法是無(wú)法覆蓋的。
? ? ? ? ? ? ? ? 不能為private。否則在其子類中只是新定義了一個(gè)方法,并沒(méi)有對(duì)其進(jìn)行覆蓋。
? ? ? ? ? ? ? ??不能為static。即使父類和子類中的方法都是靜態(tài)的,并且滿足覆蓋條件,但是仍然不會(huì)發(fā)生覆蓋,因?yàn)殪o態(tài)方法是在編譯的時(shí)候把靜態(tài)方法和類的引用類型進(jìn)行匹配。
? ? ? ? ? ?3、訪問(wèn)修飾符可以不同。但派生類方法的訪問(wèn)修飾符的權(quán)限不能比父類低。
? ? ? ? ? ?4、子類方法不能拋出比父類方法更多的異常。即子類方法所拋出的異常必須和父類方法所拋出的異常一致,或者是其子類,或者什么也不拋出;
記住:覆蓋一定是要 函數(shù)名相同 && 參數(shù)相同 && 返回值類型相同 && virtual && 基類與派生類
? ? ? ? ? ?覆蓋就是派生類中虛成員函數(shù)覆蓋基類中同名且參數(shù)相同的成員函數(shù)。
重載和覆蓋的區(qū)別:
? ? ? ? 父類的一個(gè)方法只能被子類覆蓋一次,而一個(gè)方法可以在所有的類中可以被重載多次。
? ? ? ? 覆蓋要求返回類型必須一致,重載對(duì)此沒(méi)有要求。
? ? ? ? 覆蓋只能用于子類覆蓋父類的方法,重載用于同一個(gè)類中的所有方法(包括從父類中繼承而來(lái)的方法)
? ? ? ? 另外,對(duì)于屬性(成員變量)而言,是不能重載的,只能覆蓋。
示例2-1 中
函數(shù)Base::f(int) 與 Base::f(float)相互重載
而Base::g(void) 被 Derived::g(void)覆蓋
#include <iostream.h> 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;} };void main(void) {Derived d;Base *pb = &d;pb->f(42); // Base::f(int) 42pb->f(3.14f); // Base::f(float) 3.14pb->g(); // Derived::g(void) } 示例2-1 成員函數(shù)的重載和覆蓋
令人迷惑的隱藏規(guī)則
這里“隱藏”是指派生類的函數(shù)屏蔽了與其同名的基類函數(shù)
規(guī)則如下:
(1)如果派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同。
????此時(shí),不論有無(wú)virtual關(guān)鍵字,基類的函數(shù)將被隱藏(注意別與重載混淆)。?
(2)如果派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,但是基類函數(shù)沒(méi)有virtual關(guān)>鍵字。
????此時(shí),基類的函數(shù)被隱藏(注意別與覆蓋混淆)。
補(bǔ)充:對(duì)函數(shù)返回值無(wú)要求。
? ? ? ? ?重載和隱藏的區(qū)別是:重載的作用范圍是同一個(gè)類域,而隱藏是派生類和基類之間。
???????? 覆蓋和隱藏的區(qū)別是:覆蓋,基類函數(shù)有virtual。重載,基類函數(shù)沒(méi)有virtual。
?
重載、覆蓋和隱藏判斷技巧:
函數(shù)同名的基礎(chǔ)上
先判斷作用范圍,如果是在同一個(gè)類,那有可能是重載。
如果是在派生類與基類之間,就判斷參數(shù)是否相同,不相同是隱藏。
參數(shù)相同的話,就判斷基類函數(shù)是否有virtual,有的話就是覆蓋,沒(méi)有的話
示例就是隱藏。
程序2-2(a)中:
(1)函數(shù)Derived::f(float) 覆蓋了 Base::f(float)
(2)函數(shù)Derived::g(int) 隱藏了 Base::g(float),而不是重載
(3)函數(shù)Derived::h(float) 隱藏了 Base::h(float),而不是覆蓋
?
示例2-2(b)中,pb 和pd 指向同一地址,按理說(shuō)運(yùn)行結(jié)果應(yīng)該是相同的,可事實(shí)并非這樣。
結(jié)論:
1、如果基類成員函數(shù)被派生類成員函數(shù)覆蓋了,不管是基類指針還是派生類指針,調(diào)用的都是派生類中的函數(shù)。
2、如果基類成員函數(shù)被派生類成員函數(shù)隱藏了,調(diào)用就取決于是基類指針還是派生類指針,如果是基類指針就調(diào)用基類中的成員函數(shù),派生類指針同理。
擺脫隱藏
隱藏規(guī)則引起了不少麻煩。
示例2-3 程序中,語(yǔ)句pd->f(10)的本意是想調(diào)用函數(shù)Base::f(int),但是Base::f(int)不幸被Derived::f(char *)隱藏了。
由于數(shù)字10不能被隱式地轉(zhuǎn)化為字符串,所以在編譯時(shí)出錯(cuò)。
class Base { public:void f (int x); };class Derived : public Base { public:void f (char *str); };void Test(void) {Derived *pd = new Derived;pd->f(10); // error } 示例2-3 由于隱藏而導(dǎo)致錯(cuò)誤
從示例2-3 看來(lái),隱藏規(guī)則似乎很愚蠢。但是隱藏規(guī)則至少有兩個(gè)存在的理由:
1 寫語(yǔ)句pd->f(10)的人可能真的想調(diào)用Derived::f(float),只是他誤寫錯(cuò)了,有了隱藏規(guī)則,編譯器就可以明確的指出錯(cuò)誤,未必是件壞事。
2 假如Derived有多個(gè)基類(多重繼承),有時(shí)搞不清楚哪些基類定義了函數(shù)f。那么pd->f(10)可能會(huì)出乎意料地調(diào)用了基類函數(shù)f。盡管隱藏規(guī)則看起來(lái)不怎么有道理,但是能明確的消除這些意外。
?
如果語(yǔ)句pd->f(10)一定要調(diào)用函數(shù)Base::f(int),那么將類
Derived 修改為如下即可。
?
下圖轉(zhuǎn)自:https://blog.csdn.net/gogogo_sky/article/details/72860426#commentBox
總結(jié)
以上是生活随笔為你收集整理的成员函数的重载、覆盖与隐藏(详细)【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 01赵玉荣-03安海莹-04郝玥-实训一
- 下一篇: Java创建一个简单的图书管理系统