# 簡介
函式的功能跟數學的函數很像。(或是說一模一樣。)
在 `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。
}
```
# 例題
沒有例題,自己把主函式的東西放上去試試看。
###### 都看到這了難道不按個愛心支持一下嗎?