C/C++之函数
Tips:
?1. 本人當(dāng)初學(xué)習(xí)C/C++的記錄。
?2. 資源很多都是來(lái)自網(wǎng)上的,如有版權(quán)請(qǐng)及時(shí)告知!
?3. 可能會(huì)有些錯(cuò)誤。如果看到,希望能指出,以此共勉!
??說(shuō)到函數(shù),第一個(gè)要說(shuō)的就是main函數(shù),他是C/C++標(biāo)準(zhǔn)規(guī)定的!main的形式如下:
/* 形式一*/ int main(int argc, char *argv[]) {statements;return 0; } /* 形式二*/ int main(void) {statements;return 0; } /* 形式三*/ void main() {statements;return; } /* 形式四*/ main() {statements;return; }??上面這些形式,是比較常見(jiàn)的幾種main函數(shù)的形式,下面來(lái)詳細(xì)解釋一下。關(guān)于main函數(shù),最詳細(xì)的說(shuō)明當(dāng)然是C/C++的標(biāo)準(zhǔn)文檔,以下內(nèi)容是對(duì)標(biāo)準(zhǔn)文檔的記錄。ANSI C89和C90、C99和C11以及C++標(biāo)準(zhǔn)各個(gè)版本之間沒(méi)有實(shí)質(zhì)變化,只有一些細(xì)節(jié)上的東西有些區(qū)別。
C 標(biāo)準(zhǔn)
??首先是最后一種:這在C89標(biāo)準(zhǔn)中允許出現(xiàn),Brian W. Kernighan 和Dennis M. Ritchie 的經(jīng)典巨著 The C programming Language(《C 程序設(shè)計(jì)語(yǔ)言》)用的就是main( )這種形式。這主要是因?yàn)镃語(yǔ)言誕生初期,只有一種類(lèi)型,那就是int,沒(méi)有char、long、float等。既然只有一種類(lèi)型,那么就可以不寫(xiě),后來(lái)的C標(biāo)準(zhǔn)為了兼容以前的代碼于是規(guī)定:不明確標(biāo)明返回值的,默認(rèn)返回值為int,也就是說(shuō) main()等同于int main(),而不是等同于void main()。但是,該條規(guī)則,從C99開(kāi)始,就不在支持了!
??在C99中,第5.1.2.2.1 Program startup節(jié),指出了main函數(shù)的定義:
??The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;9) or in some other implementation-defined manner.
9) Thus, int can be replaced by a typedef name defined as int, or the type of argv can be written as char ** argv, and so on
如果main函數(shù)的末尾沒(méi)寫(xiě)return語(yǔ)句,C99 規(guī)定編譯器要自動(dòng)在生成的目標(biāo)文件中加入 return 0
??第三種:關(guān)于第三種,返回值為void的,C++之父 Bjarne Stroustrup 在他的主頁(yè)上的 FAQ 中明確地寫(xiě)著 The definition void main( ) { /* …… */ } is not and never has been C++, nor has it even been C。至于出現(xiàn)的原因,可能是由于在 C 和 C++ 中,不接收任何參數(shù)也不返回任何信息的函數(shù)原型為“void foo(void);”。但是,這條規(guī)則并不適用于main函數(shù)。事實(shí)上,void main()在C仍然可以是符合標(biāo)準(zhǔn)(conforming)的擴(kuò)展,為什么呢?因?yàn)閛r in some other implementation-defined manner這句的存在。(ISO C/C++中,根據(jù)對(duì)環(huán)境的要求,分為兩類(lèi):一類(lèi)是獨(dú)立實(shí)現(xiàn)(freestanding implementation),另一類(lèi)是宿主實(shí)現(xiàn)(hosted implementation),不同的實(shí)現(xiàn)環(huán)境是有區(qū)別的,更詳細(xì)的就只能看標(biāo)準(zhǔn)了。)
C++標(biāo)準(zhǔn)
??在C++98中,第3.6.1 Main function節(jié),指出了main函數(shù)的定義:
??An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a return type of type int, but otherwise its type is implementationdefined.
All implementations shall allow both of the following definitions of main:
int main() { /* ... */ }
and
int main(int argc, char* argv[]) { /* ... */ }
- main 函數(shù)的返回值類(lèi)型也必須是int。如果main函數(shù)的末尾沒(méi)寫(xiě)return語(yǔ)句,C++98 規(guī)定編譯器要自動(dòng)在生成的目標(biāo)文件中加入 return 0
全局main禁止被使用。因此不像C,C++中main無(wú)法遞歸調(diào)用。&::main也是錯(cuò)誤的
再來(lái)說(shuō)說(shuō)函數(shù)返回值:
??C語(yǔ)言的(void)或函數(shù)定義中的()表示不接受任何參數(shù),相當(dāng)于C++的(),也和C++的(void)等價(jià)。C語(yǔ)言的()在函數(shù)定義外表示接受任何參數(shù),相當(dāng)于C++的(…)。所以在C語(yǔ)言中,聲明時(shí)最好不要省略(void)中的void,要是省略就不是預(yù)期想要的函數(shù)原型了。在定義中可以使用(),如int main(){},同int main(void){}。但若要保證聲明和定義通用,只用(void)表示函數(shù)沒(méi)有參數(shù)。
??而C++中,不接受任何參數(shù)的參數(shù)列表寫(xiě)成(void)是不必要的。C++中函數(shù)參數(shù)空著和寫(xiě)void等效。C語(yǔ)言中,main函數(shù)省略返回值相當(dāng)于返回int,但是在C++中,不再主張這樣用!
- 關(guān)于注釋,/**/是C風(fēng)格的注釋;// 是C++風(fēng)格注釋?,F(xiàn)在,C及C++同時(shí)支持這兩種注釋風(fēng)格
- 關(guān)于頭文件,xx.h是C和C++舊風(fēng)格;C++新風(fēng)格沒(méi)有擴(kuò)展名(iostream),原來(lái)舊的C頭文件以c加原文件名組成(cmath)
- 在舊的C標(biāo)準(zhǔn)中,變量的定義必須在函數(shù)開(kāi)始的位置(C99支持隨時(shí)定義),而C++中,習(xí)慣做法是在使用的地方定義!
- C++中,可以使用連續(xù)賦值(a = b = c = 10 這個(gè)語(yǔ)句從右向左執(zhí)行),C中不允許這樣做
- C++和C一樣,不允許嵌套定義函數(shù)(可以嵌套聲明),每個(gè)函數(shù)都必須是獨(dú)立的!
函數(shù)定義
??函數(shù)分為有返回值和沒(méi)有返回值兩大類(lèi)。
void functionName(parameterlist) // 無(wú)返回值 { statements; return; // 可以省略 }typeName functionName(parameterlist) // 有返回值 { statements; return value; // value的類(lèi)型為typeName類(lèi)型 }??C和C++對(duì)于返回值類(lèi)型有一定的限制:不能是數(shù)組。但可以是其他任何類(lèi)型:整型、浮點(diǎn)型、指針、結(jié)構(gòu)、對(duì)象。(但是,數(shù)組可以作為結(jié)構(gòu)或?qū)ο蟮慕M成部分被返回)。通常,函數(shù)將返回值放到寄存器或者內(nèi)存中進(jìn)行返回。
函數(shù)原型(聲明)
C++函數(shù)原型與ANSI C函數(shù)原型
?ANSI C借鑒了C++中函數(shù)原型,但是兩者是有區(qū)別的。其中,最大的區(qū)別就是:
??1. 為了與C兼容,ANSI C中的函數(shù)原型是可選的,但是,在C++中是必不可少的。
??2. 在C++中形參列表為空與寫(xiě)void是等效的——意味著函數(shù)沒(méi)有參數(shù)。在ANSI C中,形參為空意味著不指明參數(shù)——意味著將在函數(shù)定義中給出形參列表。
??3. 在C++中,不指明形參列表時(shí),需要使用省略號(hào) … 。例如:void func(…); 通常,只有在需要與可變參數(shù)的C函數(shù)(如:printf)交互時(shí),才需要這樣做。
4.
為什么需要函數(shù)原型(聲明)
??原型提供了函數(shù)到編譯器的接口。原型告訴編譯器函數(shù)有什么類(lèi)型的返回值、參數(shù)類(lèi)型和數(shù)量。方便編譯器捕捉錯(cuò)誤。關(guān)于編譯器為什么不直接取cpp文件找函數(shù)定義,原因之一就是這樣效率太低;再一個(gè),函數(shù)的定義可能不在一個(gè)文件中或者定義在一個(gè)動(dòng)態(tài)庫(kù)中。
函數(shù)的形參和返回值
??參數(shù)的形參和返回值可以是基本類(lèi)型、結(jié)構(gòu)體變量、類(lèi)變量、指針變量、引用等,變量的傳遞方式可以分為值傳遞和指針傳遞。需要重點(diǎn)說(shuō)明的是引用型形參以及引用型返回值。
函數(shù)的返回值
返回值的隱式轉(zhuǎn)換
??C和C++中同樣:如果函數(shù)的實(shí)際返回值和聲明的類(lèi)型不一致,那么實(shí)際返回值將被自動(dòng)轉(zhuǎn)換為函數(shù)聲明的返回類(lèi)型。(超出范圍,將可能出錯(cuò))
VC編譯器會(huì)給出如上圖所示的警告!
返回值為引用的函數(shù)(僅C++)
類(lèi)型標(biāo)識(shí)符 &函數(shù)名(形參列表及類(lèi)型說(shuō)明) {//函數(shù)體 }??好處:在內(nèi)存中不產(chǎn)生被返回值的副本;(注意:正是因?yàn)檫@點(diǎn)原因,所以返回一個(gè)局部變量的引用是不可取的。因?yàn)殡S著該局部變量生存期的結(jié)束,相應(yīng)的引用也會(huì)失效,產(chǎn)生runtime error!
注意:
1. 不能返回局部變量的引用。這條可以參照Effective C++[1]的Item 31。主要原因是局部變量會(huì)在函數(shù)返回后被銷(xiāo)毀,因此被返回的引用就成為了”無(wú)所指”的引用,程序會(huì)進(jìn)入未知狀態(tài)。
2. 不能返回函數(shù)內(nèi)部new分配的內(nèi)存的引用。 這條可以參照Effective C++[1]的Item 31。雖然不存在局部變量的被動(dòng)銷(xiāo)毀問(wèn)題,可對(duì)于這種情況(返回函數(shù)內(nèi)部new分配內(nèi)存的引用),又面臨其它尷尬局面。例如,被函數(shù)返回的引用只是作為一個(gè)臨時(shí)變量出現(xiàn),而沒(méi)有被賦予一個(gè)實(shí)際的變量,那么這個(gè)引用所指向的空間(由new分配)就無(wú)法釋放,造成memory leak。
3. 可以返回類(lèi)成員的引用,但最好是const。 這條原則可以參照Effective C++[1]的Item 30。主要原因是當(dāng)對(duì)象的屬性是與某種業(yè)務(wù)規(guī)則(business rule)相關(guān)聯(lián)的時(shí)候,其賦值常常與某些其它屬性或者對(duì)象的狀態(tài)有關(guān),因此有必要將賦值操作封裝在一個(gè)業(yè)務(wù)規(guī)則當(dāng)中。如果其它對(duì)象可以獲得該屬性的非常量引用(或指針),那么對(duì)該屬性的單純賦值就會(huì)破壞業(yè)務(wù)規(guī)則的完整性。
4. 流操作符重載返回值聲明為“引用”的作用:
流操作符<<和>>,這兩個(gè)操作符常常希望被連續(xù)使用,例如:cout <<”hello” << endl; 因此這兩個(gè)操作符的返回值應(yīng)該是一個(gè)仍然支持這兩個(gè)操作符的流引用??蛇x的其它方案包括:返回一個(gè)流對(duì)象和返回一個(gè)流對(duì)象指針。但是對(duì)于返回一個(gè)流對(duì)象,程序必須重新(拷貝)構(gòu)造一個(gè)新的流對(duì)象,也就是說(shuō),連續(xù)的兩個(gè)<<操作符實(shí)際上是針對(duì)不同對(duì)象的!這無(wú)法讓人接受。對(duì)于返回一個(gè)流指針則不能連續(xù)使用<<操作符。 因此,返回一個(gè)流對(duì)象引用是惟一選擇。這個(gè)唯一選擇很關(guān)鍵,它說(shuō)明了引用的重要性以及無(wú)可替代性。 賦值操作符 = 和流操作符一樣,是可以連續(xù)使用的,例如:x = j = 10;或者(x=10)=100;賦值操作符的返回值必須是一個(gè)左值,以便可以被繼續(xù)賦值。因此引用成了這個(gè)操作符的惟一返回值選擇。
5. 在另外的一些操作符中,卻千萬(wàn)不能返回引用:+-*/ 四則運(yùn)算符。它們不能返回引用,Effective C++[1]的Item23詳細(xì)的討論了這個(gè)問(wèn)題。主要原因是這四個(gè)操作符沒(méi)有side effect,因此,它們必須構(gòu)造一個(gè)對(duì)象作為返回值,可選的方案包括:返回一個(gè)對(duì)象、返回一個(gè)局部變量的引用,返回一個(gè)new分配的對(duì)象的引用、返回一 個(gè)靜態(tài)對(duì)象引用。根據(jù)前面提到的引用作為返回值的三個(gè)規(guī)則,第2、3兩個(gè)方案都被否決了。靜態(tài)對(duì)象的引用又因?yàn)?(a+b) == (c+d))會(huì)永遠(yuǎn)為true而導(dǎo)致錯(cuò)誤。所以可選的只剩下返回一個(gè)對(duì)象了。
形參
形參的隱式轉(zhuǎn)換
??C和C++中同樣:將一個(gè)表達(dá)式作為實(shí)參傳遞給函數(shù)調(diào)用,此時(shí)形參和實(shí)參類(lèi)型不一致:目標(biāo)轉(zhuǎn)換類(lèi)型為形參的類(lèi)型
同4.1.1的返回值情況,編譯器會(huì)給出警告!
引用型形參和臨時(shí)變量(僅C++)
??如果實(shí)參和引用形參類(lèi)型不匹配,C++將產(chǎn)生臨時(shí)變量,當(dāng)且僅當(dāng)引用形參為const時(shí)。如果形參為const 引用,當(dāng)出現(xiàn)以下兩種情況時(shí),C++將產(chǎn)生臨時(shí)變量:
實(shí)參類(lèi)型不正確,但是可以轉(zhuǎn)化為正確的類(lèi)型
如果變量為基本類(lèi)型,盡量不要使用引用形參,而是使用按值傳遞的方式;當(dāng)數(shù)據(jù)比較大(類(lèi)、結(jié)構(gòu)體)時(shí),使用引用傳遞較好。
形參的sizeof問(wèn)題(C和C++同樣)
函數(shù)形參在使用sizeof()取大小時(shí),有許多需要注意的地方。
參數(shù)及返回值的傳遞問(wèn)題
??C語(yǔ)言函數(shù)參數(shù)和返回值的傳遞方式有:值傳遞和指針傳遞兩種,C++函數(shù)又增加了一種:引用傳遞。
??值傳遞:形參是實(shí)參的拷貝,改變形參的值并不會(huì)影響外部實(shí)參的值。從被調(diào)用函數(shù)的角度來(lái)說(shuō),值傳遞是單向的(實(shí)參->形參),參數(shù)的值只能傳入,不能傳出。當(dāng)函數(shù)內(nèi)部需要修改參數(shù),并且不希望這個(gè)改變影響調(diào)用者時(shí),采用值傳遞。
??指針傳遞:形參為指向?qū)崊⒌刂返闹羔?#xff0c;當(dāng)對(duì)形參的指向操作時(shí),就相當(dāng)于對(duì)實(shí)參本身進(jìn)行的操作
??(C++)引用傳遞:形參相當(dāng)于是實(shí)參的“別名”,對(duì)形參的操作其實(shí)就是對(duì)實(shí)參的操作,在引用傳遞過(guò)程中,被調(diào)函數(shù)的形式參數(shù)雖然也作為局部變量在棧中開(kāi)辟了內(nèi)存空間,但是這時(shí)存放的是由主調(diào)函數(shù)放進(jìn)來(lái)的實(shí)參變量的地址。被調(diào)函數(shù)對(duì)形參的任何操作都被處理成間接尋址,即通過(guò)棧中存放的地址訪(fǎng)問(wèn)主調(diào)函數(shù)中的實(shí)參變量。正因?yàn)槿绱?#xff0c;被調(diào)函數(shù)對(duì)形參做的任何操作都影響了主調(diào)函數(shù)中的實(shí)參變量。
??實(shí)際上,這里的指針傳遞可以歸為值傳遞,下面給出解釋。在Pascal語(yǔ)言中,形參有兩種:值形參和變量形參,前者是值傳遞方式,后者是指針傳遞方式。在C語(yǔ)言中,只有“值形參”而無(wú)“變量形參”,全部采用值傳遞方式。C++把引用型變量作為函數(shù)形參,就彌補(bǔ)了這個(gè)不足。
從編譯的角度來(lái)闡述它們之間的區(qū)別:
??程序在編譯時(shí)分別將指針和引用添加到符號(hào)表上,符號(hào)表上記錄的是變量名及變量所對(duì)應(yīng)地址。指針變量在符號(hào)表上對(duì)應(yīng)的地址值為指針變量的地址值,而引用在符號(hào)表上對(duì)應(yīng)的地址值為引用對(duì)象的地址值。符號(hào)表生成后就不會(huì)再改,因此指針可以改變其指向的對(duì)象(指針變量中的值可以改),而引用對(duì)象則不能修改。
參數(shù)傳遞內(nèi)存問(wèn)題
??函數(shù)調(diào)用過(guò)程中,必然存在著內(nèi)存的開(kāi)辟與釋放。處理不好往往就會(huì)造成內(nèi)存泄露,甚至程序崩潰。
上圖中,用到了指針的引用。注意指針的引用的寫(xiě)法。
- 千萬(wàn)別返回指向“棧內(nèi)存”的指針、引用、包括數(shù)組,因?yàn)樵搩?nèi)存在函數(shù)結(jié)束時(shí)自動(dòng)消亡了,返回的指針是個(gè)野指針了。
- 可以返回指向堆的指針和引用,但是不推薦這樣做。上圖中,返回malloc分配的內(nèi)存,因?yàn)檫@是在堆上分配的,如果程序員不去釋放,將一直持續(xù)的程序結(jié)束,由操作系統(tǒng)回收,第二個(gè)函數(shù),返回棧上的變量,是錯(cuò)誤的!可以用函數(shù)返回值來(lái)傳遞動(dòng)態(tài)內(nèi)存,只能返回在堆上分配的內(nèi)存、全局變量?jī)?nèi)存、靜態(tài)變量
指針函數(shù)與函數(shù)指針
??辨別指針函數(shù)與函數(shù)指針最簡(jiǎn)單的方式就是看函數(shù)名前面的指針*號(hào)有沒(méi)有被括號(hào)包含,如果被包含就是函數(shù)指針,反之則是指針函數(shù)。
指針函數(shù)就是返回類(lèi)型是某一類(lèi)型的指針的函數(shù),形式如下:
類(lèi)型標(biāo)識(shí)符 *函數(shù)名(參數(shù)表);
函數(shù)指針就是指向函數(shù)的指針變量,即本質(zhì)是一個(gè)指針變量。形式如下:
類(lèi)型說(shuō)明符 (*函數(shù)名)(參數(shù)); 當(dāng)然 也可以定義函數(shù)指針數(shù)組: 類(lèi)型說(shuō)明符 (*函數(shù)名[ ])(參數(shù));
例如:我們定義一個(gè)函數(shù)指針數(shù)組:
定義和調(diào)用方式,如下圖:
地址跳轉(zhuǎn)(多出現(xiàn)在嵌入式C中)
再此之前,先看下面的例子:
??按照&運(yùn)算符本來(lái)的意義,它要求其操作數(shù)是一個(gè)對(duì)象,但函數(shù)名不是對(duì)象(函數(shù)是一個(gè)對(duì)象),本來(lái)&func是非法的,但很久以前有些編譯器已經(jīng)允許這樣做,c/c++標(biāo)準(zhǔn)的制定者出于對(duì)象的概念已經(jīng)有所發(fā)展的緣故,也承認(rèn)了&func的合法性。
??因此,對(duì)于func和&func可以這樣理解:func是函數(shù)的首地址,它的類(lèi)型是void(),&func表示一個(gè)指向函數(shù)void func(void)這個(gè)對(duì)象的地址,它的類(lèi)型是void(*)(),因此func和&func所代表的地址值是一樣的,但類(lèi)型不一樣。func是一個(gè)函數(shù),&func表達(dá)式的值是一個(gè)指針!
??這時(shí),我們來(lái)看一道嵌入式筆試題:想讓程序跳轉(zhuǎn)到絕對(duì)地址0x100000處執(zhí)行,該如何做?
??答案有兩種:(*(void(*)(void))0x100000)(); // 和上面的(*funcPtr)();是不是很像
或者((void(*)(void))0x100000)(); // 和上面的(funcPtr)(); 是不是很像
??首先,來(lái)看(void()(void),這就好比一個(gè)類(lèi)型,就像int是指向int的指針,那么(void(*)(void) 就是指向 void func(void)這樣函數(shù)的函數(shù)指針。這樣,就回到了我們的函數(shù)指針上。
??將地址0x100000轉(zhuǎn)換時(shí),其當(dāng)然是沒(méi)有參數(shù)和返回值的,因此:(void()(void))0x100000 // 這就和(int)a類(lèi)似了。
??與此同時(shí),(void()(void)是指向函數(shù)的指針,轉(zhuǎn)換后自然帶有函數(shù)特性,因此:(void()(void))0x100000 就是個(gè)函數(shù)指針
??最后,我們調(diào)用這個(gè)函數(shù)指針:就是出現(xiàn)了上面兩種答案了。
??可能有人會(huì)問(wèn),上面函數(shù)指針調(diào)用中還有個(gè)funcPtr(),這是不是就意味著,(void(*)(void))0x100000() 這也是正確的呢?實(shí)際上,這是不對(duì)的。
??在很多嵌入式代碼中,我們??吹饺缦麓a:
void(*reset)(void) = (void(*)(void))0;
??其中,void(reset)(void)就是函數(shù)指針定義,(void()(void))0是強(qiáng)制類(lèi)型轉(zhuǎn)換操作,將數(shù)值“0”強(qiáng)制轉(zhuǎn)換為函數(shù)指針地址“0”。通過(guò)調(diào)用reset()函數(shù),程序就會(huì)跳轉(zhuǎn)到程序執(zhí)行的“0”地址處重新執(zhí)行。在一些其他高級(jí)單片機(jī)Bootloader中,如NBoot、UBoot、EBoot,經(jīng)常通過(guò)這些Bootloader進(jìn)行下載程序,然后通過(guò)函數(shù)指針跳轉(zhuǎn)到要執(zhí)行程序的地址處。
??對(duì)于(*(void(*)(void))(0x30700000))();可以這樣理解:首先(void()(void))是一個(gè)強(qiáng)制類(lèi)型轉(zhuǎn)換符,他將后面的0x30700000這個(gè)無(wú)符號(hào)整數(shù)強(qiáng)制轉(zhuǎn)化為一個(gè)函數(shù)指針,該函數(shù)指針?biāo)赶虻暮瘮?shù)入口參數(shù)為void,返回值也是void。如果到這步你看懂了,那么設(shè)(void()(void))(0x30700000)為fp;那么上面的表達(dá)式就可以簡(jiǎn)化為(*fp)();
函數(shù)遞歸調(diào)用
??C++函數(shù)和C一樣,允許函數(shù)調(diào)用自己。(與C不同的是,C++不允許main調(diào)用自己)。遞歸函數(shù)必須要有結(jié)束條件,否者將一直調(diào)用下去。
內(nèi)聯(lián)函數(shù)(C99添加)
??內(nèi)聯(lián)函數(shù)是C++為了提高程序執(zhí)行速度而做的改進(jìn)(節(jié)省時(shí)間但是消耗空間),常規(guī)函數(shù)與內(nèi)聯(lián)函數(shù)的區(qū)別主要在于C++編譯器如何將他們組合到程序中。使用內(nèi)聯(lián)函數(shù)特性必須符合以下條件之一:
- 在函數(shù)聲明中加上關(guān)鍵字inline
- 在函數(shù)定義中加上關(guān)鍵字inline
??C++內(nèi)聯(lián)函數(shù)用來(lái)取代C語(yǔ)言中的宏函數(shù)。內(nèi)聯(lián)函數(shù)的參數(shù)傳遞方式為:值傳遞;宏函數(shù)則是文字替換。
C++函數(shù)重載
什么是函數(shù)重載
??函數(shù)重載是指在同一作用域內(nèi),可以有一組具有相同函數(shù)名,不同參數(shù)列表的函數(shù),這組函數(shù)被稱(chēng)為重載函數(shù)。重載函數(shù)通常用來(lái)命名一組功能相似的函數(shù),這樣做減少了函數(shù)名的數(shù)量,避免了名字空間的污染,對(duì)于程序的可讀性有很大的好處。
為什么需要函數(shù)重載
- 如果沒(méi)有函數(shù)重載機(jī)制,如在C中,你必須要這樣去做:為這個(gè)print函數(shù)取不同的名字,如print_int、print_string。這里還只是兩個(gè)的情況,如果是很多個(gè)的話(huà),就需要為實(shí)現(xiàn)同一個(gè)功能的函數(shù)取很多個(gè)名字,如加入打印long型、char*、各種類(lèi)型的數(shù)組等等。這樣做很不友好!
- 類(lèi)的構(gòu)造函數(shù)跟類(lèi)名相同,也就是說(shuō):構(gòu)造函數(shù)都同名。如果沒(méi)有函數(shù)重載機(jī)制,要想實(shí)例化不同的對(duì)象,那是相當(dāng)?shù)穆闊?#xff01;
- 操作符重載,本質(zhì)上就是函數(shù)重載,它大大豐富了已有操作符的含義,方便使用,如+可用于連接字符串等!
如何實(shí)現(xiàn)函數(shù)重載
??函數(shù)重載的關(guān)鍵是函數(shù)的參數(shù)列表,如果參數(shù)的個(gè)數(shù)不同或者類(lèi)型不同就可實(shí)現(xiàn)重載。注意引用形參和普通形參不能重載。注意:編譯器將類(lèi)型引用和類(lèi)型視作相同類(lèi)型,不能重載。
C++函數(shù)重寫(xiě)、重載、隱藏的區(qū)別
重寫(xiě)(override)
?覆蓋也稱(chēng)重寫(xiě),英文override,重寫(xiě)(覆蓋)的規(guī)則:
作用:
??基類(lèi)指針和引用在調(diào)用對(duì)應(yīng)方法時(shí),根據(jù)所指對(duì)象類(lèi)型實(shí)現(xiàn)動(dòng)態(tài)綁定。
重載(overload)
??overload是重載,一般是用于在一個(gè)類(lèi)內(nèi)實(shí)現(xiàn)若干重載的方法,這些方法的名稱(chēng)相同而參數(shù)形式不同。重載的規(guī)則:
作用:
??同一方法,根據(jù)傳遞消息的不同(類(lèi)型或個(gè)數(shù)),產(chǎn)生不同的動(dòng)作(相同方法名,實(shí)現(xiàn)不同)。
隱藏
總結(jié)
- 上一篇: C/C++之常用关键字
- 下一篇: C/C++之 C++ String(字符