[C++ Primer Note5] 函數(shù)

  1. 大多數(shù)類型都能用作函數(shù)的返回類型,一種特殊的返回類型是void絮识,它表示函數(shù)不返回任何值。函數(shù)的返回類型不能是數(shù)組類型或函數(shù)類型嗽上,但可以是指向數(shù)組或函數(shù)的指針笋除。
  2. 在C++中,名字有作用域炸裆,對象有生命周期:
  • 名字的作用域是程序文本的一部分,名字在其中可見
  • 對象的生命周期是程序執(zhí)行過程中該對象存在的一段時間
  1. 對于普通局部變量對應(yīng)的對象來說鲜屏,當函數(shù)的控制路徑經(jīng)過變量定義語句時創(chuàng)建該對象烹看,當?shù)竭_定義所在的塊末尾時銷毀它。我們把只存在于塊執(zhí)行期間的對象稱為自動對象(automatic object)洛史。當塊的執(zhí)行結(jié)束后惯殊,塊中創(chuàng)建的自動對象的值就變成未定義的了。
  2. 某些時候也殖,有必要令局部變量的生命周期貫穿函數(shù)調(diào)用及之后的時間土思。可將局部變量定義成static類型從而獲得這樣的對象忆嗜。局部靜態(tài)對象(local static object)在程序執(zhí)行流第一次經(jīng)過對象定義語句時初始化己儒,并且知道程序終止時才被銷毀,即使對象所在的函數(shù)結(jié)束執(zhí)行也不會對它有影響捆毫。
    5.和其他名字一樣闪湾,函數(shù)的名字也必須在使用之前聲明。類似于變量绩卤,函數(shù)只能定義一次途样,但可以聲明多次。函數(shù)的聲明和函數(shù)的定義非常類似濒憋,唯一的區(qū)別是函數(shù)聲明無須函數(shù)體何暇,用一個分號替代即可。函數(shù)的三要素(返回類型凛驮,函數(shù)名裆站,形參類型)描述了函數(shù)的接口,說明了調(diào)用該函數(shù)所需的全部信息辐烂,函數(shù)聲明也稱作函數(shù)原型(function prototype)
  3. 函數(shù)應(yīng)該在頭文件中聲明而在源文件中定義遏插,同時定義函數(shù)的源文件應(yīng)該把含有函數(shù)聲明的頭文件包含進來,編譯器負責驗證函數(shù)的定義和聲明是否匹配纠修。
  4. 當形參是引用類型時胳嘲,我們說它對應(yīng)的實參被引用傳遞(passed by reference)。當實參的值被拷貝給形參時扣草,形參和實參是兩個相互獨立的對象了牛。我們說這樣的實參被值傳遞(passed by value)
  5. 指針的行為和其他非引用類型一樣颜屠,當執(zhí)行指針拷貝操作時,拷貝的是指針的值鹰祸,兩個指針是不同的指針甫窟。因為指針可以使我們間接地訪問它所指的對象,所以通過指針可以修改它所指對象的值蛙婴,但本質(zhì)上還是屬于值傳遞粗井。
  6. 在C++中,建議使用引用類型的形參替代指針來訪問外部對象街图。
  7. 拷貝大的類類型對象或者容器對象比較低效浇衬,甚至有的類類型(包括IO類型在內(nèi))根本不支持拷貝操作。這種情況下函數(shù)只能通過引用形參訪問該類型的對象餐济。
  8. 如果函數(shù)無需改變引用形參的值耘擂,最好將其聲明為常量引用
  9. 一個函數(shù)只能返回一個值絮姆,然而有時函數(shù)需要同時返回多個值醉冤,引用形參為我們一次返回多個結(jié)果提供了有效的途徑。我們可以利用引用形參來保存需要返回的多個值篙悯。
  10. 當用實參初始化形參時會忽略掉形參的頂層const蚁阳,傳給它常量對象或者非常量對象都是可以的。
  11. 數(shù)組的兩個特殊性質(zhì)對我們定義和使用作用在數(shù)組上的函數(shù)有影響辕近,這兩個性質(zhì)分別是韵吨,不允許拷貝數(shù)組以及使用數(shù)組時通常會將其轉(zhuǎn)換成指針。所以當我們?yōu)楹瘮?shù)傳遞一個數(shù)組時移宅,實際上傳遞的是指向數(shù)組首元素的指針归粉。盡管不能以值傳遞的方式傳遞數(shù)組,但是我們可以形參寫成類似數(shù)組的形式:
  • void print(const int*)
  • void print(const int[])
  • void print(const int[10]) 這里的維度只是我們期望的漏峰,實際上不一定
    盡管表現(xiàn)形式不同糠悼,但上面的三個函數(shù)是等價的:每個函數(shù)的唯一實參都是const int*類型的。
  1. 因為數(shù)組是以指針的形式傳遞給函數(shù)的浅乔,所以一開始函數(shù)并不知道數(shù)組的確切尺寸倔喂,調(diào)用者應(yīng)該為此提供一些額外的信息。管理指針形參有三種常用的技術(shù):
  • 使用結(jié)束標記:比如C風格字符串
  • 使用標準庫規(guī)范:傳遞指向數(shù)組首元素和尾后元素的指針
  • 傳遞一個表示數(shù)組大小的形參
  1. 當函數(shù)不需要對數(shù)組元素執(zhí)行寫操作時靖苇,數(shù)組形參應(yīng)該是指向const的指針
  2. C++允許將變量定義成數(shù)組的引用席噩,基于同樣的道理,形參也可以是數(shù)組的引用贤壁。此時悼枢,引用形參綁定到數(shù)組上。但此時函數(shù)只能作用于固定大小的數(shù)組脾拆。
    //形參是數(shù)組的引用馒索,維度是類型的一部分
    void print(int (&arr)[10]){
        for (auto elem : arr)
            cout<<elem<<endl;
    }
  1. 當將多維數(shù)組傳遞給函數(shù)時莹妒,真正傳遞的是指向數(shù)組首元素的指針,所以首元素本身就是一個數(shù)組绰上。指針就是一個指向數(shù)組的指針旨怠,數(shù)組第二維(以及后面所有維度)的大小都是數(shù)組類型的一部分,不能省略蜈块。
  void print(int (*matrix)[10]),int roSize);

上述聲明將matrix聲明成指向含有10個整數(shù)的數(shù)組的指針鉴腻。

  1. 命令行選項通過兩個(可選的)形參傳遞給main函數(shù):
  int main(int argc,char *argv[]){...}
  1. 為了編寫能處理不同數(shù)量實參的函數(shù),C++11標準提供了兩種主要方法:如果所有實參類型相同百揭,可以傳遞一個initializer_list的標準庫類型拘哨;如果類型不同,我們可以編寫一種特殊的函數(shù)信峻,也就是所謂的可變參數(shù)模板。除此以外瓮床,還有一種省略符形參盹舞,不過一般用于與C函數(shù)交互的接口程序。
  2. 返回void的函數(shù)不要求非得有return語句隘庄,因為這類函數(shù)最后一句后面會隱含執(zhí)行return
  3. 在含有return語句的循環(huán)后面應(yīng)該也有一條return語句踢步,因為循環(huán)中的return不一定會被執(zhí)行到
  4. 函數(shù)返回的值用于初始化調(diào)用點的一個臨時量,該臨時量就是函數(shù)調(diào)用的結(jié)果丑掺。如果返回引用類型获印,則不需要拷貝。
  5. 必須要注意的是街州,千萬不要返回局部對象的引用或指針兼丰,因為函數(shù)完成后,它所占用的存儲空間也隨之被釋放掉唆缴,所以要想確保返回值安全鳍征,我們不妨提問:引用所引的是在函數(shù)之前已經(jīng)存在的哪個對象?
  6. C++11標準規(guī)定函數(shù)可以返回花括號包圍的值的列表(這與之前所述的列表初始化語法實際上相照應(yīng))面徽,比如用于返回一個vector<int>類型艳丛。如果返回內(nèi)置類型則花括號只能包含一個值。
  7. 之前介紹過趟紊,如果函數(shù)的返回值不是void氮双,那么它必須返回一個值。但這條規(guī)則有一個例外:我們允許main沒有return語句結(jié)束霎匈。如果控制流到達了main函數(shù)的結(jié)尾處而沒有return語句戴差,編譯器將隱式地插入一條返回0的return語句。
  8. 因為數(shù)組不能被拷貝唧躲,所以函數(shù)不能返回數(shù)組造挽,但是可以返回數(shù)組的指針和引用碱璃。使用類型別名可以簡化聲明過程。
  typedef int arrT[10];    //arrT表示含有10個整數(shù)的數(shù)組
  arrT* func(int i);    //func返回一個指向含有10個整數(shù)的數(shù)組的指針

如果不使用類型別名饭入,返回數(shù)組指針的函數(shù)形式如下:

  int (*func(int i)) [10];

這里的*表示函數(shù)func的返回結(jié)果可以執(zhí)行解引用操作嵌器。

  1. C++11標準中有一種可以簡化上述func聲明的方法,就是使用尾置返回類型(trailing return type)
  auto func(int i) -> int (*)[10];
  1. 還有一種情況谐丢,如果我們知道函數(shù)返回的指針指向哪個數(shù)組爽航,就可以使用decltype關(guān)鍵字聲明返回類型:
  int odd[]={1,3,5,7,9};
  int even[]={0,2,4,6,8};
  decltype(odd) *arrPtr(int i){
    return (i%2) ? &odd : &even;
  }

decltype并不負責把數(shù)組類型轉(zhuǎn)換成對應(yīng)的指針,所以decltype的結(jié)果是一個數(shù)組乾忱,要想表示返回指針還必須在聲明時加一個 *讥珍。

  1. 對于重載而言,頂層const不影響傳入函數(shù)的對象窄瘟。一個擁有頂層const的形參無法和另一個沒有頂層const的形參區(qū)分開來衷佃。
  2. 對于底層const,形參是某種類型的指針或引用蹄葱,則可以區(qū)分const氏义。即使非常量也能被底層const所指,但是編譯器會優(yōu)先非常量版本的函數(shù)图云。
  3. 可以將const_cast和重載搭配起來使用
  4. 當有多個重載函數(shù)可以匹配調(diào)用但每一個都不是明顯的最佳選擇時也將發(fā)生錯誤惯悠,稱為二義性調(diào)用(ambiguous call)
  5. 在不同的作用域中無法重載函數(shù)名
  6. C++同樣支持默認參數(shù)竣况,默認參數(shù)必須在參數(shù)列表的最右邊
  string screen(int hz=24,int wid=80,char backgrnd=' ');
  1. 在給定作用域中一個形參只能被賦予一次默認參數(shù)克婶,后續(xù)聲明智能給沒有默認值的形參添加默認實參。
  2. 只要表達式的值能轉(zhuǎn)換成形參所需的類型丹泉,該表達式就能作為默認實參情萤。
  3. 將函數(shù)指定為內(nèi)聯(lián)函數(shù)(inline),通常就是將它在調(diào)用點”內(nèi)聯(lián)地“展開摹恨。只需要在函數(shù)的返回類型前面加上關(guān)鍵字inline紫岩。內(nèi)聯(lián)函數(shù)一般用于優(yōu)化規(guī)模較小,流程直接睬塌,頻繁調(diào)用的函數(shù)泉蝌。
  4. constexpr函數(shù)是指能用于常量表達式的函數(shù),函數(shù)的返回值和所有形參類型都得是字面值類型揩晴。
  5. assert是一種預處理宏勋陪,assert宏用一個表達式作為它的條件:
  assert(expr);

如果表達式為假,assert輸出信息并終止程序執(zhí)行硫兰;如果為真诅愚,assert什么也不做。

  1. assert的行為依賴于一個名為NDEBUG的預處理變量的狀態(tài)劫映。如果定義NDEBUG违孝,assert什么也不做刹前。默認情況下沒有定義NDEBUG,此時assert執(zhí)行運行時檢查雌桑。
  2. 函數(shù)指針指向的是函數(shù)而非對象喇喉。和其他指針一樣,函數(shù)指針指向某種特定類型校坑。函數(shù)的類型由它的返回類型形參類型共同決定拣技,與函數(shù)名無關(guān)。要想聲明一個可以指向函數(shù)的指針耍目,只需要用指針替換函數(shù)名即可膏斤。
  bool (*pf)(const string &,const string &);
  1. 當我們把函數(shù)名作為一個值使用時,該函數(shù)自動轉(zhuǎn)換成指針邪驮。此時取地址符是可選的莫辨。
  2. 我們還能直接使用指向函數(shù)的指針調(diào)用該函數(shù),無須提前解引用指針毅访。
  3. 指向不同函數(shù)類型的指針不存在轉(zhuǎn)換規(guī)則衔掸,但是我們可以和往常一樣為函數(shù)指針賦一個nullptr或者值為0的整型常量表達式,表示該指針沒有指向任何一個函數(shù)俺抽。
  4. 如果定義了指向重載函數(shù)的指針,指針類型必須與重載函數(shù)中的某一個精確匹配较曼。
  5. 和數(shù)組類似磷斧,雖然不能定義函數(shù)類型的形參,但是形參可以是指向函數(shù)的指針捷犹。此時弛饭,形參看起來是函數(shù)類型,實際上卻是當成指針使用:
  void test(int pf(int));   //等價的聲明
  void test(int (*pf)(int));

我們可以直接把函數(shù)名作為實參使用萍歉,此時它會自動轉(zhuǎn)換成指針侣颂。

  1. 類型別名和decltype能讓我們簡化聲明:
  //Func和Func2是函數(shù)類型
  typedef bool Func();
  typedef decltype(test) Func2();
  //FuncP和FuncP2是指向函數(shù)的指針
  typedef bool (*FuncP)();
  typedef decltype(test) *Func2();

因為decltype返回函數(shù)類型,所以要加上*才能得到指針枪孩。

  1. 和數(shù)組類似憔晒,雖然不能返回一個函數(shù),但是能返回指向函數(shù)類型的指針蔑舞。與往常一樣拒担,最簡單的方法是聲明一個類型別名,但此時返回類型不會自動轉(zhuǎn)換成指針攻询,我們必須顯式地將返回類型指定為指針从撼。
  int (*f1(int)) (int *,int);  //也能直接聲明一個函數(shù)指針返回值

我們還可以使用尾置返回類型的方式聲明一個返回函數(shù)指針的函數(shù):

  auto f1(int)->int (*)(int*,int);
  1. 如果我們明確知道返回的函數(shù)哪一個,可以參考上文所述返回數(shù)組指針一樣使用decltype簡化書寫函數(shù)指針返回類型的過程钧栖。但記得要顯式加上*表示我們需要返回指針低零。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末婆翔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子掏婶,更是在濱河造成了極大的恐慌啃奴,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件气堕,死亡現(xiàn)場離奇詭異纺腊,居然都是意外死亡,警方通過查閱死者的電腦和手機茎芭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門揖膜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人梅桩,你說我怎么就攤上這事壹粟。” “怎么了宿百?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵趁仙,是天一觀的道長。 經(jīng)常有香客問我垦页,道長雀费,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任痊焊,我火速辦了婚禮盏袄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘薄啥。我一直安慰自己辕羽,他們只是感情好,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布垄惧。 她就那樣靜靜地躺著刁愿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪到逊。 梳的紋絲不亂的頭發(fā)上铣口,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機與錄音觉壶,去河邊找鬼枷踏。 笑死,一個胖子當著我的面吹牛掰曾,可吹牛的內(nèi)容都是我干的旭蠕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼掏熬!你這毒婦竟也來了佑稠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤旗芬,失蹤者是張志新(化名)和其女友劉穎舌胶,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疮丛,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡幔嫂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了誊薄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片履恩。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖呢蔫,靈堂內(nèi)的尸體忽然破棺而出切心,到底是詐尸還是另有隱情,我是刑警寧澤片吊,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布绽昏,位于F島的核電站,受9級特大地震影響俏脊,放射性物質(zhì)發(fā)生泄漏全谤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一爷贫、第九天 我趴在偏房一處隱蔽的房頂上張望认然。 院中可真熱鬧,春花似錦沸久、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至威酒,卻和暖如春窑睁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背葵孤。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工担钮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尤仍。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓箫津,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子苏遥,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容