C++中的重載、籠罩、隱蔽引見。本站提示廣大學習愛好者:(C++中的重載、籠罩、隱蔽引見)文章只能為提供參考,不一定能成為您想要的結果。以下是C++中的重載、籠罩、隱蔽引見正文
頭幾天面試時被問及C++中的籠罩、隱蔽,概念根本答不下去,只答了怎樣用指針完成多態,也還有漏掉。終究不歡而散。回來後在網上查找進修了一番,做了這個總結。個中部門文字借用了他人的博客,望不要見責。
•概念
1、重載(overload)
指函數名雷同,然則它的參數表列個數或次序,類型分歧。然則不克不及靠前往類型來斷定。
(1)雷同的規模(在統一個感化域中) ;
(2)函數名字雷同;
(3)參數分歧;
(4)virtual 症結字無關緊要。
(5)前往值可以分歧;
2、重寫(也稱為籠罩 override)
是指派生類從新界說基類的虛函數,特點是:
(1)不在統一個感化域(分離位於派生類與基類) ;
(2)函數名字雷同;
(3)參數雷同;
(4)基類函數必需有 virtual 症結字,不克不及有 static 。
(5)前往值雷同(或是協變),不然報錯;<—-協變這個概念我也是第一次才曉得…
(6)重寫函數的拜訪潤飾符可以分歧。雖然 virtual 是 private 的,派生類中重寫改寫為 public,protected 也是可以的
3、重界說(同樣成隱蔽)
(1)不在統一個感化域(分離位於派生類與基類) ;
(2)函數名字雷同;
(3)前往值可以分歧;
(4)參數分歧。此時,豈論有沒有 virtual 症結字,基類的函數將被隱蔽(留意別與重載和籠罩混雜) 。
(5)參數雷同,然則基類函數沒有 virtual症結字。此時,基類的函數被隱蔽(留意別與籠罩混雜) 。
•例子
#include <iostream> using namespace std; class SParent { public: SParent( ){}; SParent( const SParent &p ) { cout << "parent copy construct" << endl; } int add( int a,int b ) { cout << "parent int add" << endl; return a + b; } double add( double a,double b ) { cout << "parent double add" << endl; return a + b; } virtual int dec( int a,int b ) { cout << "parent int dec" << endl; return a - b; } }; class SChild : public SParent { public: //using SParent::add; float add( float a,float b ) { cout << "child float add" << endl; return a + b; } int dec(int a, int b) { cout << "child int dec" << endl; return a - b; } }; int main() { /* 測試重載 */ SParent parent; parent.add( 3,5 ); parent.add( (double)3,(double)5 ); cout << endl; /* 測試籠罩 */ SChild *pchild = (SChild *)new SParent();/* 基類強轉為子類...風險...,用dynamic_cast轉換也不可 */ pchild->dec( 10,3 ); SParent *pparent = new SChild(); pparent->dec( 11,3 ); cout << endl; /* 測試隱蔽 */ SChild child; child.add( (int)3,(int)5 ); cout << endl; /* 測試函數表 */ ((SParent *)NULL)->add( 4,6 ); ((SChild *)NULL)->add( 4,6 ); int a = 0; ((SChild *)&a)->add( 4,6 ); cout << endl; /* 測試函數地址 */ ((SParent)child).add( (int)4,(int)8 ); child.SParent::add( 3,5 ); return 0; }
輸入成果:
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 按 <RETURN> 來封閉窗口...
•懂得
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 );這類代碼也是能運轉經由過程的。網上還有人經由過程盤算直接取到了函數表的地址直接挪用了。但這類代碼不平安不標准不說,還有個更年夜的成績。當做員函數裡須要挪用成員變量時,經由過程這類假的對象指針確定找不到成員變量表,直接拜訪了不法內存。
5.函數地址測試
有了隱蔽、籠罩,哪麼我們要怎樣挪用被隱蔽、籠罩的函數呢。上面有兩種辦法:
((SParent)child).add( (int)4,(int)8 );
child.SParent::add( 3,5 );
第一種是比擬低效的辦法。現實上它是經由過程拷貝結構函數生成一個暫時的基類變量去挪用基類的add函數。
第二種經由過程::指定域去拜訪。這類辦法是編譯器依據域直接找到了基類的函數地址,跟函數表沒有多年夜關系。