函數提高
3.1 函數預設參數
在C++中,函數的形參清單中的形參是可以有預設值的。
- 調用帶有預設參數值的函數時,如果不指定帶有預設值的參數,則該參數自動被賦為預設值
文法:
傳回值類型 函數名 (參數 = 預設值) { ... }
注意事項:
- 如果某個位置參數有預設值,那麼從這個位置往後,從左向右,必須都要有預設值
//int func(int a, int b = 10, int c) { //錯誤,b之後的參數c也要有預設參數 int test01(int a, int b = 10, int c = 10) { return a + b + c; }
- 如果函數聲明有預設值,函數實作的時候就不能有預設參數;反之亦然。
C++規定 (C++03/C++11): A default argument shall not be redefined by a later declaration (not even to the same value). (函數重定義/聲明時,不允許重定義預設參數 )
int func2(int a = 10, int b = 10); ... int func2(int a, int b) { return a + b; }
3.2 函數占位參數
C++中函數的形參清單裡可以有占位參數,用來做占位,調用函數時必須填補該位置
文法:
傳回值類型 函數名 (資料類型){}
示例:
//函數占位參數 ,占位參數也可以有預設參數
void func(int a, int) {
cout << "this is func" << endl;
}
int main() {
func(10,10); //占位參數必須填補
return 0;
}
作用:占位參數的一個作用,就是在重載自增
++
/自減
--
運算符的時候,區分前自增/自減(++a)還是後自增/自減(a++)
3.3 函數重載
3.3.1 函數重載概述
作用:函數名可以相同,提高複用性
函數重載滿足條件:
- 同一個作用域下
- 函數名稱相同
- 函數參數類型不同 或者 個數不同 或者 順序不同
注意: 函數的傳回值不可以作為函數重載的條件
示例:
//函數重載需要函數都在同一個作用域下
void func() { cout << "func 的調用!" << endl; }
void func(int a) { cout << "func (int a) 的調用!" << endl; }
void func(double a) { cout << "func (double a)的調用!" << endl; }
void func(int a ,double b) { cout << "func (int a ,double b) 的調用!" << endl; }
//函數傳回值不可以作為函數重載條件
//int func(int a, double b) { cout << "func (double a ,int b)的調用!" << endl; }
int main() {
func();
func(10);
func(3.14);
func(10,3.14);
return 0;
}
3.3.2 函數重載注意事項
- 引用作為重載條件的情況下
- 函數重載碰到函數預設參數
示例:
//1、引用作為重載條件
void func(int &a) {
cout << "func (int &a) 調用 " << endl;
}
void func(const int &a) {
cout << "func (const int &a) 調用 " << endl;
}
//2、函數重載碰到函數預設參數
void func2(int a, int b = 10) {
cout << "func2(int a, int b = 10) 調用" << endl;
}
void func2(int a) {
cout << "func2(int a) 調用" << endl;
}
int main() {
int a = 10;
func(a); //調用無const
func(10); //調用有const
//func2(10); //碰到預設參數産生歧義,需要避免
return 0;
}
3.4 内聯函數
3.4.1 普通函數的優缺點
- Pros(優點): 易讀易維護
- Cons (缺點): 調用時有開銷
函數調用時:參數及部分CPU寄存器的内容進棧,控制流跳轉
函數傳回時:傳回值及寄存器值出棧,控制流跳轉
3.4.2 定義内聯函數
文法:定義函數時,在函數類型前面加上
inline
關鍵字
一般而言,内聯函數的聲明和定義都在一起。我們很少将内聯函數的聲明和定義分開編寫。
// 定義内聯函數
inline int max (int a, int b) { return (a > b ? a : b); }
3.4.3 内聯函數的使用
目的:減小函數調用開銷
方法:編譯器在遇到内聯函數的調用時,會将内聯函數的函數體展開到調用位置,進而避免函數調用的開銷。
// Calling (調用内聯函數)
int x = max (3, 5);
int y = max (0, 8);
// Inline expansion (内聯展開)
int x = (3 > 5 ? 3 : 5);
int y = (0 > 8 ? 0 : 8);
結果:導緻程式變大
一般來說,内聯函數隻有在需要考慮程式運作性能的環境中才使用。
程式員所用的 inline 關鍵字,隻是對編譯器的一個請求。内聯函數是否展開,是由編譯器決定的。
3.4.4 将内聯函數的聲明和定義分離
在C++标準7.1.2.4節有如下說明
An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case (3.2). [ Note: A call to the inline function may be encountered before its definition appears in the translation unit. —end note ]
内聯函數應在每個翻譯單元中定義。在該翻譯單元中它遵循“單一定義規則(ODR)”,并且所有該内聯函數定義必須完全相同。[ 注釋:在翻譯單元中可能會在内聯函數定義出現之前就有調用該内聯函數的語句]
是以,内聯函數聲明和定義分類的用法如下:
#include <iostream>
inline void foo();
int main() {
foo();
return 0;
}
inline void foo() {
std::cout << "Hi\n";
}