前幾天面試時被問及c++中的覆蓋、隱藏,概念基本答不上來,只答了怎麼用指標實現多型,也還有遺漏。最終不歡而散。回來後在網上查詢學習了一番,做了這個總結。其中部分文字借用了別人的部落格,望不要見怪。
•概念一、過載(overload)
指函式名相同,但是它的參數列列個數或順序,型別不同。但是不能靠返回型別來判斷。
(1)相同的範圍(在同乙個作用域中) ;
(2)函式名字相同;
(3)引數不同;
(4)virtual 關鍵字可有可無。
(5)返回值可以不同;
二、重寫(也稱為覆蓋 override)
是指派生類重新定義基類的虛函式,特徵是:
(1)不在同乙個作用域(分別位於派生類與基類) ;
(2)函式名字相同;
(3)引數相同;
(4)基類函式必須有 virtual 關鍵字,不能有 static 。
(5)返回值相同(或是協變),否則報錯;
(6)重寫函式的訪問修飾符可以不同。儘管 virtual 是 private 的,派生類中重寫改寫為 public,protected 也是可以的
三、重定義(也成隱藏)
(1)不在同乙個作用域(分別位於派生類與基類) ;
(2)函式名字相同;
(3)返回值可以不同;
(4)引數不同。此時,不論有無 virtual 關鍵字,基類的函式將被隱藏(注意別與過載以及覆蓋混淆) 。
(5)引數相同,但是基類函式沒有 virtual關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆) 。
•例子#include
using namespace std;
class sparent
; sparent( const sparent &p )
int add( int a,int b )
double add( double 程式設計客棧a,double b )
virtual int dec( int a,int b )
};class schild : public sparent
int dec(int a, int b)
};int main()
輸出結果:
parent int add
parent double add
parent int dec
child int dec
child float add
parent int add
child float add
child float add
parent copy construct
parent int add
parent int add
按 來關閉視窗...
•理解int sparent::add(int a,int b)與double sparent::add( double a,double b )是過載
int sparent::add(int a,int b)與double sparent::add( double a,double b )都被子類schild中的float schild::add( float a,float b )隱藏
int sparent::dec( int a,int b )被子類schild中的int schild::dec( int a,int b )覆蓋
•測試1.過載測試,簡單易懂,略過。
2.覆蓋測試。dec函式在基類、子類中同名同參,為虛函式,故稱覆蓋。
schild *pchild = (schild *)new sparent()建立的是乙個基類物件,其函式表應該為
sparent *pparent = new schild();建立乙個子類物件,其函式表應該為
由上面的函式表可見,當發生覆蓋時,子類的函式名會把基類的同名函式覆蓋(這也就是為什麼叫覆蓋的原因吧)。這樣我們可以利用乙個指向子類的基類指標實現多型。但重點只有一
個,就是函式表裡到底指向誰(不管這個指標經過轉換後是什麼型別的).故輸出分別為父類、子類。這是乙個執行時多型。
3.隱藏測試
int sparent::add程式設計客棧(int a,int b)與double sparent::add( double a,double b )都被子類schild中的float schild::add( float a,float b )覆蓋,是因為他們同名,而且在不同的作用域中(基類、子類作用域是不同的)。child.add( (int)3,(int)5 );這行**中,編譯器在子類中查詢add函式,只找到了乙個(基類的add(int a,int b)會被編譯根據隱藏規則略過),再根據隱式型別轉換發現該函式適用。如果無法隱式轉換,則編譯不過。隱藏的原因:防止隱式型別轉換造成錯誤。比如int也是可以轉換成char的,假如基類有一函式add(char a,char b),子類也有一函式add(double a,double b)。程式設計師想著在子類隱式把int轉換為double,但編譯器可能調的是基類的。這也防止了一些庫或封裝好的基類對程式設計師造成困擾。
像上面的**,如果你確實需要基類的函式,可以用using sparent:add。則把基類的add函式域擴大到了子類,構成過載。
4.函式表測試
上面我們說到函式表,這個是在編譯時定好的,程式執行時載入到記憶體中。這意味著我們可以直接通過位址去呼叫函式。所以((schild *)null)->add( 4,6 );這種**也是能執行通過的。網上還有人通過計算直接取到了函式表的位址直接呼叫了。但這種www.cppcns.com**不安全不規範不說,還有個更大的問題。當成員函式裡需要呼叫成員變數時,通過這種假的物件指標肯定找不到成員變數表,直接訪問了非法記憶體。
5.函式位址測試
有了隱藏、覆蓋,哪麼我們要怎麼呼叫被隱藏、覆蓋的函式呢。下面有兩種方法:
((sparent)child).add( (int)4,(int)8 );
child.sparent::add( 3,5 );
第一種是比較低效的方法。事實上它是通過拷貝建構函式生成乙個臨時的基類變數去呼叫基類的add函式。
第二種通過::指定域去訪問。這種方法是編譯器根據域直接找到了基類的函式位址,跟函式表沒有多大關係。
本文標題: c++中的過載、覆蓋、隱藏介紹
本文位址:
c 過載 覆蓋 隱藏
成員函式的過載 覆蓋與隱藏 成員函式的過載 覆蓋 override 與隱藏很容易混淆,c 程式設計師必須要搞清楚 概念,否則錯誤將防不勝防。8.2.1 過載與覆蓋 成員函式被過載的特徵 1 相同的範圍 在同乙個類中 2 函式名字相同 3 引數不同 4 virtual 關鍵字可有可無。覆蓋是指派生類函...
c 過載 覆蓋 隱藏
成員函式的過載 覆蓋與隱藏 成員函式的過載 覆蓋 override 與隱藏很容易混淆,c 程式設計師必須要搞清楚 概念,否則錯誤將防不勝防。8.2.1 過載與覆蓋 成員函式被過載的特徵 1 相同的範圍 在同乙個類中 2 函式名字相同 3 引數不同 4 virtual 關鍵字可有可無。覆蓋是指派生類函...
c 過載 覆蓋 隱藏
成員函式的過載 覆蓋與隱藏 成員函式的過載 覆蓋 override 與隱藏很容易混淆,c 程式設計師必須要搞清楚概念,否則錯誤將防不勝防。成員函式被過載的特徵 1 相同的範圍 在同乙個類中 2 函式名字相同 3 引數不同 4 virtual 關鍵字可有可無。覆蓋是指派生類函式覆蓋基類函式,特徵是 1...