函數(shù)基礎(chǔ)
- 函數(shù)定義:返回類型削解、函數(shù)名富弦、0個(gè)或多個(gè)形參組成的列表、函數(shù)體氛驮。
- 形參以逗號隔開腕柜。
- 形參列表位于一對圓括號內(nèi)。
- 函數(shù)執(zhí)行:調(diào)用運(yùn)算符矫废。
- 調(diào)用運(yùn)算符作用于函數(shù)或指向函數(shù)的指針盏缤。
- 圓括號內(nèi)為一個(gè)用逗號隔開的實(shí)參列表,用于對形參進(jìn)行初始化蓖扑。
- 調(diào)用表達(dá)式的類型即為函數(shù)的返回類型唉铜。
- 函數(shù)調(diào)用過程中,完成兩項(xiàng)工作:
- 用實(shí)參初始化對應(yīng)的形參律杠。
- 將程序控制權(quán)轉(zhuǎn)移給被調(diào)用函數(shù)潭流。
- 形參與實(shí)參:
- 實(shí)參的求值順序未被規(guī)定竞惋。
- 初始化過程中,實(shí)參應(yīng)與形參類型關(guān)聯(lián)灰嫉。
- 函數(shù)的形參列表:
- 形參列表可為空拆宛。
- 任意兩個(gè)形參不可同名,且不能與函數(shù)最外層作用域中的局部變量同名熬甫。
- 形參可以不命名胰挑,用來表示該形參在函數(shù)中不被使用,但此操作不影響實(shí)參個(gè)數(shù)椿肩。
- 函數(shù)的返回值:
- 可為void瞻颂。
- 不可以是數(shù)組或函數(shù),但可以是指向數(shù)組和指向函數(shù)的指針郑象。
- 局部靜態(tài)對象:在程序的執(zhí)行路徑第一次經(jīng)過對象定義語句時(shí)初始化贡这,直到程序終止時(shí)被銷毀。
- 在類型聲明前使用static關(guān)鍵字厂榛。
- 局部靜態(tài)變量沒有顯式的初始值時(shí)盖矫,初始化為0。
- 函數(shù)聲明:可以聲明多次击奶,但只能定義一次辈双。
- 函數(shù)聲明應(yīng)該在頭文件中,且源文件應(yīng)包含頭文件柜砾。
參數(shù)傳遞
- 調(diào)用類型:根據(jù)形參是否為引用分為引用傳遞(傳引用調(diào)用)和值傳遞(傳值調(diào)用)湃望。
- 參數(shù)類型:
- 傳值參數(shù):初始值被拷貝給變量,此時(shí)對變量的改動(dòng)不會(huì)影響初始值痰驱。
- 指針形參:可以通過指針間接訪問其所指的對象证芭。
- 傳引用參數(shù):形參與實(shí)參綁定,函數(shù)可以通過改變形參來間接改變實(shí)參担映。
- 使用引用废士,避免拷貝,更加高效蝇完。(無需修改參數(shù)時(shí)官硝,使用常量引用)
- 使用引用參數(shù)可以返回額外信息。
- const類型的形參與實(shí)參:實(shí)參初始化形參時(shí)會(huì)忽略頂層const限制短蜕。
//需要注意:
void func(const int i); //func能夠讀取i泛源,但不能向i寫值。
void func(int i); //由于頂層const被忽略忿危,此處屬于重復(fù)定義。
- 盡量將函數(shù)不會(huì)改變的形參定義為常量引用没龙。
- 數(shù)組形參:為函數(shù)傳遞一個(gè)數(shù)組時(shí)铺厨,實(shí)際上傳遞的是指向數(shù)組首元素的指針缎玫。
- 為函數(shù)提供數(shù)組尺寸信息的方法:
- 使用標(biāo)記指定數(shù)組長度:C風(fēng)格字符串中的結(jié)束符。
- 使用標(biāo)準(zhǔn)庫規(guī)范:傳遞指向數(shù)組首元素和尾后元素的指針(begin解滓、end函數(shù))赃磨。
- 顯示傳遞一個(gè)表示數(shù)組大小的形參:size_t類型。
- 數(shù)組引用形參:形參可以是數(shù)組的引用洼裤。
- 多維數(shù)組:數(shù)組第二維(以及后面所有維度)的大小都是數(shù)組類型的一部分邻辉,不能省略。
- 含有可變數(shù)目形參的函數(shù):如果實(shí)參類型相同腮鞍,可傳遞名為initializer_list的標(biāo)準(zhǔn)庫類型值骇;如果實(shí)參類型不同,則使用可變參數(shù)模板(后續(xù)介紹)移国。
- initializer_list可提供的操作:
initializer_list<T> lst; //默認(rèn)初始化吱瘩,T類型元素的空列表。
initializer_list<T> lst{a, b, c...}; //lst元素?cái)?shù)量與初始值一樣多迹缀,lst的元素是對應(yīng)初始值的副本使碾,列表中元素為const。
lst2(lst);
lst2 = lst; //拷貝或賦值一個(gè)initializer_list對象不會(huì)拷貝列表中的元素祝懂,拷貝后票摇,原始列表和副本共享元素。
lst.size(); //列表中的元素?cái)?shù)量砚蓬。
lst.begin(); //返回指向lst首元素的指針矢门。
lst.end(); //返回指向lst尾后元素的指針。
//Example
void error_msg(initializer_list<string> il);
//調(diào)用形式
if(expected != actual)
error_msg({"functionX", expected, actual});
else
error_msg({"functionX", "Okay"});
返回類型和return語句
- return語句形式:
- return ;
- return expression ;
- 無返回值函數(shù):無返回值的return語句只能用在返回類型是void的函數(shù)中怜械。
- 無返回值的函數(shù)不要求一定return語句颅和,函數(shù)會(huì)隱式執(zhí)行。
- 使用有返回值的return語句時(shí)缕允,要求expression必須是另一個(gè)返回值為void的函數(shù)峡扩,強(qiáng)行令void函數(shù)返回其他類型的表達(dá)式將引發(fā)編譯錯(cuò)誤。
- 有返回值函數(shù):
- 非void的函數(shù)必須返回一個(gè)值障本。
- 未返回值便結(jié)束函數(shù)執(zhí)行將引發(fā)未定義行為教届。
- 返回的之用于初始化調(diào)用點(diǎn)的一個(gè)臨時(shí)量,該臨時(shí)量即為函數(shù)調(diào)用的結(jié)果驾霜。
- 不要返回局部對象的引用或指針案训。
- 返回引用的函數(shù)將返回左值,但只有返回非常量引用時(shí)才可對其賦值粪糙。
- 函數(shù)可以返回花括號包圍的值的列表强霎。
- 返回值為int的main()函數(shù)可以沒有return語句,編譯器將隱式插入
return 0;
蓉冈。
- main()函數(shù)返回0值表示執(zhí)行成功城舞,其他值表示執(zhí)行失敗轩触。
- 遞歸:函數(shù)調(diào)用自身。
- 返回?cái)?shù)組指針方法:
- 使用類型別名家夺。
-
Type (*function(parameter_list))[dimension]
脱柱。
- 使用尾置返回類型:
auto function(parameter_list) -> Type(*)[dimension]
- 已知返回的指針將指向哪一個(gè)數(shù)組時(shí),使用decltype拉馋。
int odd[] = {1, 3, 5, 7, 9};
int even[] = {2, 4, 6, 8, 10};
decltype(odd) *arrPtr(int i) //decltype并不會(huì)將數(shù)組類型轉(zhuǎn)化為對應(yīng)的指針榨为,所以聲明中需要加*符號。
{
return (i % 2) ? &odd : &even;
}
函數(shù)重載
- 重載函數(shù)的形參數(shù)量煌茴、形參類型應(yīng)有所不同随闺,返回值類型不同不能作為重載函數(shù)。
- 函數(shù)重載時(shí)景馁,形參的頂層const屬性會(huì)被忽略板壮,但底層const屬性不會(huì)被忽略。
- const_cast在函數(shù)重載中的應(yīng)用:
//比較兩個(gè)string的長度合住,返回較短者的引用
const string &shorterString(const string &s1, const string &s2)
{
return s1.size() <= s2.size() ? s1 : s2;
}
//要求在實(shí)參不是常量時(shí)绰精,得到普通引用
string &shorterString(string &s1, string &s2)
{
auto &r = shorterString(const_cast<const string&>(s1), const_cast<string &>(s2));
return const_cast<string &>(r);
}
- 調(diào)用重載函數(shù)時(shí)的可能結(jié)果:最佳匹配,無匹配透葛,二義性調(diào)用笨使。
特殊用途語言特性
- 默認(rèn)實(shí)參:
- 一旦某個(gè)形參被賦予默認(rèn)值,其后出現(xiàn)的所有形參均應(yīng)該有默認(rèn)值(合理設(shè)置形參順序)僚害。
- 給定作用域內(nèi)硫椰,在函數(shù)的多次聲明中,一個(gè)形參只能被賦予一次默認(rèn)實(shí)參萨蚕。
- 局部變量不能作為默認(rèn)實(shí)參靶草。
string screen(sz, sz, char = ' ');
string screen(sz, sz, char = '*'); //False
string screen(sz = 24, sz = 80, char); //True
- 內(nèi)聯(lián)函數(shù):返回類型前加上inline關(guān)鍵字,聲明為內(nèi)聯(lián)函數(shù)岳遥,減少調(diào)用開銷奕翔。
- 適用于規(guī)模較小、流程直接浩蓉、頻繁調(diào)用的函數(shù)派继。
- 內(nèi)聯(lián)只是向編譯器發(fā)送的一個(gè)請求,編譯器可以忽略此請求捻艳。
- constexpr函數(shù):
- 函數(shù)的返回類型及所有形參的類型均應(yīng)為字面值類型驾窟。
- 函數(shù)體中有且只有一條return語句。
- 編譯器將constexpr函數(shù)隱式指定為內(nèi)聯(lián)函數(shù)认轨。
- 允許constexpr函數(shù)的返回值為非常量绅络。
- 內(nèi)聯(lián)函數(shù)和constexpr函數(shù)一般放在頭文件內(nèi)。
- 調(diào)試幫助:
- assert預(yù)處理宏:
assert(expr)
,expr為0時(shí)恩急,assert輸出信息并終止程序執(zhí)行节视,expr非0時(shí),不執(zhí)行操作假栓。
- NDEBUG預(yù)處理變量:如果定義了NDEBUG,則assert不執(zhí)行任何操作霍掺。
-
_ _func_ _
:當(dāng)前調(diào)試的函數(shù)名字匾荆。
-
_ _FILE_ _
:存放文件名的字符串字面值。
-
_ _LINE_ _
:存放當(dāng)前行號的整型字面值杆烁。
-
_ _TIME_ _
:存放文件編譯時(shí)間的字符串字面值牙丽。
-
_ _DATE_ _
:存放文件編譯日期的字符串字面值。
函數(shù)匹配
//Example
void f(); //(1)
void f(int); //(2)
void f(int, int); //(3)
void f(double, double = 3.14); //(4)
- 確定候選函數(shù)和可行函數(shù):
- 候選函數(shù):重載函數(shù)集兔魂,需與被調(diào)用函數(shù)同名且其聲明在調(diào)用點(diǎn)可見烤芦。
- 可行函數(shù):可被調(diào)用這組實(shí)參調(diào)用的函數(shù),要求形參數(shù)量與本次調(diào)用提供的實(shí)參數(shù)量相同析校,且類型相關(guān)构罗。
- 尋找最佳匹配:
- 實(shí)參類型與形參類型越接近,匹配越好智玻。
- 含有多個(gè)形參的函數(shù)最佳匹配需要滿足該函數(shù)的每個(gè)實(shí)參的匹配都不劣于其它可行函數(shù)需要的匹配遂唧,且至少有一個(gè)實(shí)參的匹配優(yōu)于其它可行函數(shù)提供的匹配。
- 調(diào)用錯(cuò)誤:無匹配函數(shù)吊奢、二義性調(diào)用盖彭。
- 實(shí)參類型轉(zhuǎn)換等級:
- 精確匹配,包括:
- 實(shí)參與形參類型相同页滚。
- 實(shí)參從數(shù)組召边、函數(shù)類型轉(zhuǎn)化為對應(yīng)的指針類型。
- 向?qū)崊⒃鰟h頂層const裹驰。
- 通過const轉(zhuǎn)換實(shí)現(xiàn)的匹配隧熙。
- 通過類型提升實(shí)現(xiàn)的匹配。
- 通過算數(shù)類型轉(zhuǎn)換或指針轉(zhuǎn)換實(shí)現(xiàn)的匹配邦马。
- 通過類類型轉(zhuǎn)換實(shí)現(xiàn)的匹配贱鼻。
函數(shù)指針
- 形式:
returnType (*function)(parameter_list)
- 使用函數(shù)指針:
- 當(dāng)函數(shù)名作為一個(gè)值使用時(shí),函數(shù)自動(dòng)轉(zhuǎn)化為指針(即取地址符可選)滋将。
- 可以直接通過指針調(diào)用函數(shù)邻悬,無需解引用指針。
- 指向不同類型的函數(shù)的指針之間無轉(zhuǎn)換規(guī)則随闽。
- 函數(shù)指針可賦值
0
或nullptr
父丰。
- 重載函數(shù)指針:指針類型必須與重載函數(shù)中的某一個(gè)精確匹配。
- 函數(shù)指針形參:可以使用類型別名或decltype簡化代碼。
void useBigger(const string &s1, const string &s2, bool pf(const string &, const string &));
//等價(jià)聲明
void useBigger(const string &s1, const string &s2, bool (*pf)(const string &, const string &));
//Func蛾扇、Func2是函數(shù)類型
typedef bool Func(const string &, const string &);
typedef decltype(lengthCompare) Func2;
//FuncP攘烛、FuncP2是指向函數(shù)的指針
typedef bool (*FuncP)(const string &, const string &);
typedef decltype(lengthCompare) *FuncP2;
//useBigger的等價(jià)聲明
void useBigger(const string &s1, const string &s2, Func);
void useBigger(const string &s1, const string &s2, Func2);
void useBigger(const string &s1, const string &s2, FuncP);
void useBigger(const string &s1, const string &s2, FuncP2);
- 返回指向函數(shù)的指針:
//直接定義
int (*f(int))(int *, int);
//類型別名
using F = int(int *, int);
using PF = int(*)(int *, int);
PF f(int);
F *f(int);
//尾置返回
auto f(int) -> int (*)(int *, int);
- 使用auto和decltype可簡化代碼書寫。