# 簡介 函式的功能跟數學的函數很像。(或是說一模一樣。) 在 `C++` 中引入的 `pow( )` 、 `abs( )` 、 `max()` ... ... 就是函式。 在寫程式時可以直接使用這些函數,是因為有引入標頭檔,而這些東西都被寫好放在他所對應的函式庫當中。 如果想處理的特定問題,就可以使用函式(就是之前提過演算法定義的概念。),也可以寫成自訂函式,需要用時再呼叫。 用函式可以增加可讀性,如果全部的東西都放在主函式中會過於雜亂,而且在有問題時也更容易去除錯,所以還是建議各位養成習慣。 # 語法 自訂函式須宣告於主函式外,有需要時再呼叫。 ```cpp= 傳回型別 函式名稱(參數){ // 程式碼。 return ; } ``` ## 回傳型態 ### 回傳值型別 像是 `int` , `string` ... ... 各種資料型態,其為函式結束時用 `return` 回傳該資料型態。 ```cpp= #include<iostream> using namespace std ; int f(int x) { //定義成 int 型態。 x++ ; return x ; } int main() { int n = f(10) + 10 ; // f(n) 為 11 且是 int 型態。 cout << n ; } ``` ### 函式名稱 :::warning 盡量不要和現有的函式重複。 ::: ### 參數 為使用函式時被輸入的值,代替輸入做運算,依照所需來增減數量。 當函式被呼叫時會從主函式複製一份來做運算,而要被輸入的變數是區域變數,所以與主函式名字重複不會編譯錯誤。 ### 程式碼 :::warning 只要回傳值不是 `void` ,程式碼每一個可能的結束都必須 `return` ,否則會編譯錯誤。 ::: ```cpp= int function(int x) { if (x == 48763) { cout << x ; //程式跑進 if 之後就沒有之後了,沒有 return 會編譯錯誤。 } else return 48763 ; } ``` ```cpp= int function(int x) { x++ ; return x ; } int main() { int n = 10 ; cout << function(n) ; //輸出11。 cout << function(n + 1) + 2 ; //函式輸入為11,輸出14。 } ``` ## 不回傳型態 回傳值除了常見的型別之外也有不回傳的 `void`,只會執行函式內的程式。 ```cpp= void function() { cout << "HelloWorld"; } ``` `void` 不一定要 `return` ,`return` 雖然不會回傳值,但會直接結束函式。 ```cpp= void function(int x) { cout << "Hello World" ; return ; cout << "Hi" ; //此行不執行。 } ``` ```cpp= #include<iostream> using namespace std ; void function(int arr[]) { for(int i = 0; i < 5; i++){ cout << arr[i] << ' ' ; } } int main(){ int arr[5] = {1, 2, 3, 4, 5} ; function(arr) ; } ``` :::info :::spoiler 改變函式中的變數。 輸入進函式的值是從其他區域複製過來的,兩個變數是存在不同的記憶體區域,換句話說兩個是分別獨立的,所以在函式內對輸入的變數操作不會影響原本的變數。 ```cpp= #include<iostream> using namespace std ; int function(int x) { x++ ; return x ; } int main(){ int a = 2 ; a = function(a) ; cout << a ; // 輸出3。 } ``` ```cpp= #include<iostream> using namespace std ; int function(int x) { x++ ; return x ; } int main(){ int a = 2 ; function(a) ; cout << a ; // 輸出2。 } ``` 如果想透過函式修改變數的值可以用全域變數或是參考`&`。 (之後應該會細說。) #### 全域變數 ```cpp= #include<iostream> using namespace std ; int a = 2 ; void function(int x){ x++ ; return ; } int main(){ function(a) ; cout << a ; // 輸出3。 } ``` #### 參考 ```cpp= #include<iostream> using namespace std; void function(int &x){ { x++ ; return ; } int main(){ int a = 2 ; function(a) ; cout << a ; // 輸出3。 } ``` ::: # 宣告地點 通常在宣告並定義在,命名空間以下,主函式之上。 如果不想定義在上面,或是函式要互相取用,就要先宣告再定義函式。 ```cpp= #include<iostream> using namespace std ; int function(int x, int y) ; // 宣告。 int main() { int a = 5, b = 10 ; cout << function(a, b) ; // 輸出15。 } int function(int x, int y) { // 定義。 int ans ; ans = x + y ; return ans ; } ``` # 預設參數 一般函式會有多個參數,如果參數沒有輸入的話,就用預設值來運算。 ```cpp= int function(int a, int b, int c = 0) { return a + b + c ; } int main() { cout << function(10, 5) ; // 輸出15。 cout << function(10, 5, 3) ; // 輸出18。 } ``` 預設參數必須在設定參數的最後面,也就是說不能先普通參數,再預設參數,再普通參數。 ```cpp= int function(int a, int b, int c) // 可編譯。 int function(int a, int b = 0; int c = 0) // 可編譯。 int function(int a, int b = 0, int c) // 編譯錯誤。 ``` # 函式多載 函式的名字重複。 當多載時,只要參數的型態不一樣或數量不相同,編譯器會自行判斷要使用哪個函式。 ```cpp= #include<iostream> using namespace std ; int function(int a, int b) { return a + b ; } int function(int a) { return a ; } int main() { int n = 5, m = 10 ; cout << function(n); // 輸出5。 cout << function(n, m); // 輸出15。 } ``` # Template 樣板 一般情況下,函式都有指定的輸入,但有些演算法不論輸入的資料型態可以輸出一樣的答案,這時可以用樣板來讓使用者來決定要輸入的型態。 ## 宣告 函式樣板被宣告在函式之前,宣告樣板和宣告函式之間不能有程式碼,並且只有它之下的函式可以使用。 樣板名稱可以自己取,其中樣板型別除了常見的型別之外有 `typename` 和 `class` 兩種泛型別,可以自由輸入,或是在使用時單獨定義。 宣告完的樣板型別可以用作函式的參數宣告,甚至是回傳值。 ```cpp= #include<iostream> using namespace std ; template <typename T> T function(T n, T m) { return n + m ; } int main() { int n = 10, m = 5 ; cout << function(n, m) << endl ; // 輸出15。 double a = 5.3, b = 10.6; cout << function(a, b) << endl ; // 輸出15.9。 string str1 = "Hello", str2 = "World" ; cout << function(str1, str2) << endl ; // 輸出HelloWorld。 } ``` 在呼叫函式的時候以角括號指定樣板的型別。 ```cpp= #include<iostream> using namespace std ; template <typename T> T function(T n, T m) { return n + m ; } int main() { int n = 10, m = 5 ; cout << function<int>(n, m) << endl ; // 輸出15。 double a = 5.3, b = 10.6 ; cout << function<double>(a, b) << endl ; // 輸出15.9。 string str1 = "Hello", str2 = "World" ; cout << function<string>(str1, str2) << endl ; // 輸出HelloWorld。 } ``` 同一個樣板只能代表一個型別,如果要輸入兩種型別就要兩個樣板。 ```cpp= #include<iostream> using namespace std ; template <typename T> T function(T n, T m) { return n + m ; } template <typename T, typename L> T function2(T n, L m) { return n + m ; } int main() { int n = 10 ; double d = 5.3 ; cout << function(n, d) << endl ; // 編譯錯誤。 cout << function2(n, d) << endl ; // 輸出15。 cout << function2(d, n) << endl ; // 輸出15.3。 } ``` 如果樣板宣告的泛型別不能在編譯時期被推斷型別會編譯錯誤。 ```cpp= #include<iostream> using namespace std; template <typename T, typename L> T function(L n, L m) { return n + m; } int main() { int n = 10, m = 5; cout << function(n, m) << endl ; // 編譯錯誤, T 無法推斷型別。 cout << function<int>(n, m) << endl ; // 輸出15。 } ``` # 例題 沒有例題,自己把主函式的東西放上去試試看。 ###### 都看到這了難道不按個愛心支持一下嗎?