---
# System prepended metadata

title: function 函式
tags: [程設班講義]

---

# 簡介
函式的功能跟數學的函數很像。(或是說一模一樣。)
在 `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。
}
```

# 例題
沒有例題，自己把主函式的東西放上去試試看。

###### 都看到這了難道不按個愛心支持一下嗎?