C++學習筆記——函數(shù)

函數(shù)基礎

  1. 函數(shù)定義:返回類型、函數(shù)名、0個或多個形參組成的列表、函數(shù)體。
    • 形參以逗號隔開。
    • 形參列表位于一對圓括號內(nèi)。
  2. 函數(shù)執(zhí)行:調(diào)用運算符。
    • 調(diào)用運算符作用于函數(shù)或指向函數(shù)的指針。
    • 圓括號內(nèi)為一個用逗號隔開的實參列表,用于對形參進行初始化。
    • 調(diào)用表達式的類型即為函數(shù)的返回類型。
  3. 函數(shù)調(diào)用過程中,完成兩項工作:
    • 用實參初始化對應的形參。
    • 將程序控制權轉(zhuǎn)移給被調(diào)用函數(shù)。
  4. 形參與實參:
    • 實參的求值順序未被規(guī)定。
    • 初始化過程中,實參應與形參類型關聯(lián)。
  5. 函數(shù)的形參列表:
    • 形參列表可為空。
    • 任意兩個形參不可同名,且不能與函數(shù)最外層作用域中的局部變量同名。
    • 形參可以不命名,用來表示該形參在函數(shù)中不被使用,但此操作不影響實參個數(shù)。
  6. 函數(shù)的返回值:
    • 可為void。
    • 不可以是數(shù)組或函數(shù),但可以是指向數(shù)組和指向函數(shù)的指針。
  7. 局部靜態(tài)對象:在程序的執(zhí)行路徑第一次經(jīng)過對象定義語句時初始化,直到程序終止時被銷毀。
    • 在類型聲明前使用static關鍵字。
    • 局部靜態(tài)變量沒有顯式的初始值時,初始化為0。
  8. 函數(shù)聲明:可以聲明多次,但只能定義一次。
    • 函數(shù)聲明應該在頭文件中,且源文件應包含頭文件。

參數(shù)傳遞

  1. 調(diào)用類型:根據(jù)形參是否為引用分為引用傳遞(傳引用調(diào)用)和值傳遞(傳值調(diào)用)。
  2. 參數(shù)類型:
    • 傳值參數(shù):初始值被拷貝給變量,此時對變量的改動不會影響初始值。
    • 指針形參:可以通過指針間接訪問其所指的對象。
    • 傳引用參數(shù):形參與實參綁定,函數(shù)可以通過改變形參來間接改變實參。
    • 使用引用,避免拷貝,更加高效。(無需修改參數(shù)時,使用常量引用)
    • 使用引用參數(shù)可以返回額外信息。
  3. const類型的形參與實參:實參初始化形參時會忽略頂層const限制。
//需要注意:
void func(const int i);  //func能夠讀取i,但不能向i寫值。
void func(int i);  //由于頂層const被忽略,此處屬于重復定義。
  • 盡量將函數(shù)不會改變的形參定義為常量引用。
  1. 數(shù)組形參:為函數(shù)傳遞一個數(shù)組時,實際上傳遞的是指向數(shù)組首元素的指針。
  2. 為函數(shù)提供數(shù)組尺寸信息的方法:
    • 使用標記指定數(shù)組長度:C風格字符串中的結(jié)束符。
    • 使用標準庫規(guī)范:傳遞指向數(shù)組首元素和尾后元素的指針(begin、end函數(shù))。
    • 顯示傳遞一個表示數(shù)組大小的形參:size_t類型。
  3. 數(shù)組引用形參:形參可以是數(shù)組的引用。
  4. 多維數(shù)組:數(shù)組第二維(以及后面所有維度)的大小都是數(shù)組類型的一部分,不能省略。
  5. 含有可變數(shù)目形參的函數(shù):如果實參類型相同,可傳遞名為initializer_list的標準庫類型;如果實參類型不同,則使用可變參數(shù)模板(后續(xù)介紹)。
  6. initializer_list可提供的操作:
initializer_list<T> lst;  //默認初始化,T類型元素的空列表。
initializer_list<T> lst{a, b, c...};  //lst元素數(shù)量與初始值一樣多,lst的元素是對應初始值的副本,列表中元素為const。
lst2(lst);
lst2 = lst;  //拷貝或賦值一個initializer_list對象不會拷貝列表中的元素,拷貝后,原始列表和副本共享元素。
lst.size();  //列表中的元素數(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語句

  1. return語句形式:
    • return ;
    • return expression ;
  2. 無返回值函數(shù):無返回值的return語句只能用在返回類型是void的函數(shù)中。
    • 無返回值的函數(shù)不要求一定return語句,函數(shù)會隱式執(zhí)行。
    • 使用有返回值的return語句時,要求expression必須是另一個返回值為void的函數(shù),強行令void函數(shù)返回其他類型的表達式將引發(fā)編譯錯誤。
  3. 有返回值函數(shù):
    • 非void的函數(shù)必須返回一個值。
    • 未返回值便結(jié)束函數(shù)執(zhí)行將引發(fā)未定義行為。
  4. 返回的之用于初始化調(diào)用點的一個臨時量,該臨時量即為函數(shù)調(diào)用的結(jié)果。
    • 不要返回局部對象的引用或指針。
    • 返回引用的函數(shù)將返回左值,但只有返回非常量引用時才可對其賦值。
  5. 函數(shù)可以返回花括號包圍的值的列表。
  6. 返回值為int的main()函數(shù)可以沒有return語句,編譯器將隱式插入return 0;。
    • main()函數(shù)返回0值表示執(zhí)行成功,其他值表示執(zhí)行失敗。
  7. 遞歸:函數(shù)調(diào)用自身。
  8. 返回數(shù)組指針方法:
    • 使用類型別名。
    • Type (*function(parameter_list))[dimension]。
    • 使用尾置返回類型:auto function(parameter_list) -> Type(*)[dimension]
    • 已知返回的指針將指向哪一個數(shù)組時,使用decltype。
int odd[] = {1, 3, 5, 7, 9};
int even[] = {2, 4, 6, 8, 10};
decltype(odd)  *arrPtr(int i)  //decltype并不會將數(shù)組類型轉(zhuǎn)化為對應的指針,所以聲明中需要加*符號。
{
  return (i % 2) ? &odd : &even;
}

函數(shù)重載

  1. 重載函數(shù)的形參數(shù)量、形參類型應有所不同,返回值類型不同不能作為重載函數(shù)。
  2. 函數(shù)重載時,形參的頂層const屬性會被忽略,但底層const屬性不會被忽略。
  3. const_cast在函數(shù)重載中的應用:
//比較兩個string的長度,返回較短者的引用
const string &shorterString(const string &s1, const string &s2)
{
  return s1.size() <= s2.size() ? s1 : s2;
}
//要求在實參不是常量時,得到普通引用
string &shorterString(string &s1, string &s2)
{
  auto &r = shorterString(const_cast<const string&>(s1), const_cast<string &>(s2));
  return const_cast<string &>(r);
}
  1. 調(diào)用重載函數(shù)時的可能結(jié)果:最佳匹配,無匹配,二義性調(diào)用。

特殊用途語言特性

  1. 默認實參:
    • 一旦某個形參被賦予默認值,其后出現(xiàn)的所有形參均應該有默認值(合理設置形參順序)。
    • 給定作用域內(nèi),在函數(shù)的多次聲明中,一個形參只能被賦予一次默認實參。
    • 局部變量不能作為默認實參。
string screen(sz, sz, char = ' ');
string screen(sz, sz, char = '*');  //False
string screen(sz = 24, sz = 80, char);  //True
  1. 內(nèi)聯(lián)函數(shù):返回類型前加上inline關鍵字,聲明為內(nèi)聯(lián)函數(shù),減少調(diào)用開銷。
    • 適用于規(guī)模較小、流程直接、頻繁調(diào)用的函數(shù)。
    • 內(nèi)聯(lián)只是向編譯器發(fā)送的一個請求,編譯器可以忽略此請求。
  2. constexpr函數(shù):
    • 函數(shù)的返回類型及所有形參的類型均應為字面值類型。
    • 函數(shù)體中有且只有一條return語句。
    • 編譯器將constexpr函數(shù)隱式指定為內(nèi)聯(lián)函數(shù)。
    • 允許constexpr函數(shù)的返回值為非常量。
  3. 內(nèi)聯(lián)函數(shù)和constexpr函數(shù)一般放在頭文件內(nèi)。
  4. 調(diào)試幫助:
    • assert預處理宏:assert(expr),expr為0時,assert輸出信息并終止程序執(zhí)行,expr非0時,不執(zhí)行操作。
    • NDEBUG預處理變量:如果定義了NDEBUG,則assert不執(zhí)行任何操作。
    • _ _func_ _:當前調(diào)試的函數(shù)名字。
    • _ _FILE_ _:存放文件名的字符串字面值。
    • _ _LINE_ _:存放當前行號的整型字面值。
    • _ _TIME_ _:存放文件編譯時間的字符串字面值。
    • _ _DATE_ _:存放文件編譯日期的字符串字面值。

函數(shù)匹配

//Example
void f();  //(1)
void f(int);  //(2)
void f(int, int);  //(3)
void f(double, double = 3.14);  //(4)
  1. 確定候選函數(shù)和可行函數(shù):
    • 候選函數(shù):重載函數(shù)集,需與被調(diào)用函數(shù)同名且其聲明在調(diào)用點可見。
    • 可行函數(shù):可被調(diào)用這組實參調(diào)用的函數(shù),要求形參數(shù)量與本次調(diào)用提供的實參數(shù)量相同,且類型相關。
  2. 尋找最佳匹配:
    • 實參類型與形參類型越接近,匹配越好。
    • 含有多個形參的函數(shù)最佳匹配需要滿足該函數(shù)的每個實參的匹配都不劣于其它可行函數(shù)需要的匹配,且至少有一個實參的匹配優(yōu)于其它可行函數(shù)提供的匹配。
  3. 調(diào)用錯誤:無匹配函數(shù)、二義性調(diào)用。
  4. 實參類型轉(zhuǎn)換等級:
    • 精確匹配,包括:
      • 實參與形參類型相同。
      • 實參從數(shù)組、函數(shù)類型轉(zhuǎn)化為對應的指針類型。
      • 向?qū)崊⒃鰟h頂層const。
    • 通過const轉(zhuǎn)換實現(xiàn)的匹配。
    • 通過類型提升實現(xiàn)的匹配。
    • 通過算數(shù)類型轉(zhuǎn)換或指針轉(zhuǎn)換實現(xiàn)的匹配。
    • 通過類類型轉(zhuǎn)換實現(xiàn)的匹配。

函數(shù)指針

  1. 形式:returnType (*function)(parameter_list)
  2. 使用函數(shù)指針:
    • 當函數(shù)名作為一個值使用時,函數(shù)自動轉(zhuǎn)化為指針(即取地址符可選)。
    • 可以直接通過指針調(diào)用函數(shù),無需解引用指針。
    • 指向不同類型的函數(shù)的指針之間無轉(zhuǎn)換規(guī)則。
    • 函數(shù)指針可賦值0nullptr。
  3. 重載函數(shù)指針:指針類型必須與重載函數(shù)中的某一個精確匹配。
  4. 函數(shù)指針形參:可以使用類型別名或decltype簡化代碼。
void useBigger(const string &s1, const string &s2, bool pf(const string &, const string &));
//等價聲明
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的等價聲明
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);
  1. 返回指向函數(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);
  1. 使用auto和decltype可簡化代碼書寫。
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,688評論 1 51
  • 指針是C語言中廣泛使用的一種數(shù)據(jù)類型。 運用指針編程是C語言最主要的風格之一。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu); ...
    朱森閱讀 3,618評論 3 44
  • 原文地址:C語言函數(shù)調(diào)用棧(一)C語言函數(shù)調(diào)用棧(二) 0 引言 程序的執(zhí)行過程可看作連續(xù)的函數(shù)調(diào)用。當一個函數(shù)執(zhí)...
    小豬啊嗚閱讀 4,974評論 1 19
  • 隨著30歲生日的悄悄過去,猛然發(fā)現(xiàn)自己已到而立之年,有些許的迷茫,悲傷。這個年紀正是大家口中所說的事業(yè)成功的時間,...
    一生最美的美好閱讀 374評論 1 0

友情鏈接更多精彩內(nèi)容