---
tags: books, note
---
# Advanced function
## Function overload
:::info
又稱函式多載、函式重載、函式超載
:::
即使是用同樣的函數名稱,有的時候會呼叫到的是不同的函式
e.g.
```cpp=
float f = 1.5;
auto result = round(f);
cout << typeid(decltype(result)).name() << endl;
```
```result: f```
```cpp=
double f = 1.5;
auto result = round(f);
cout << typeid(decltype(result)).name() << endl;
```
```result: d```
```cpp=
long double f = 1.5;
auto result = round(f);
cout << typeid(decltype(result)).name() << endl;
```
```result: e```
由上述例子我們可以知道即使是同一個函式名稱,內建函式round還是有至少三種版本
1. ```float round(float value);```
2. ```double round(double value);```
3. ```long double round(long double value);```
那要多載一個函數也很簡單,只要確定函數的參數不一樣就可以讓多個版本同時存在
```cpp=
int add(int a, int b) {
return a + b;
}
int add(int* a, int* b) {
return *a + *b;
}
int main() {
int a = 3, b = 5;
cout << "add(int, int) " << add(a, b) << endl;
cout << "add(int*, int*) " << add(&a, &b) << endl;
return 0;
}
```
```
add(int, int) 8
add(int*, int*) 8
```
除了參數型態不一樣,參數數量不一樣也可以
```cpp=
int add(int a, int b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
int main() {
int a = 3, b = 5, c = 7;
cout << "add(int, int) " << add(a, b) << endl;
cout << "add(int, int, int) " << add(a, b, c) << endl;
return 0;
}
```
```
add(int, int) 8
add(int, int, int) 15
```
---
## Operator overload
:::info
又稱運算子多載、運算子重載
:::
在開始前我們先來了解一下運算子的呼叫方式
像如果要做一個字串串接,我們應該會用這種形式
e.g.
```cpp=
string a = "123", b = "456";
cout << a + b << endl;
```
```result: 123456```
那其實我們也可以用類似函式呼叫的方式來進行
e.g.
```cpp=
cout << operator+(a, b) << endl;
```
```result: 123456```
除了一般的函式可以多載外,運算子某種意義來說也算是函式的一種
所以**運算子大部分都可以多載**
:::info
這裡舉出一些不能被多載的運算子
```::``` 範疇解析運算子
```.``` 成員存取運算子
```dynamic_cast``` 執行時檢查類型轉換運算子(?)
```static_cast``` 未經檢查的類型轉換運算子(?)
```reinterpret_cast```重定義類型轉換運算子(?)
```const_cast``` 更改非常數屬性運算子(?)
```typeid```取得類型資訊運算子(?)
```sizeof```取大小運算子(?)
```.*``` 成員物件選擇運算子(?)
```c?t:f```三元條件運算子
```throw```丟擲異常運算子
:::
多載的方法就跟函式多載基本上一樣,不過你不能覆蓋已經存在的運算子
:::warning
e.g.
```cpp=
int operator+(int a, int b){
return a + b + 10;
}
```
因為`int`跟`int`的加法運算已經被定義過了,所以就會編譯錯誤
:::
:::danger
error: 'int operator+(int, int)' must have an argument of class or enumerated type
:::
因此需要有至少一個引數是自訂`class`或`enum`
```cpp=
struct itype {int x;};
itype operator+(itype a, itype b) {
return {a.x + b.x + 10};
}
int main() {
cout << (itype{5} + itype{6}).x << endl;
return 0;
}
```
```result: 21```
因為幾乎每個運算子都有固定的引數數量,所以多載的時候要注意引數有幾個
:::warning
e.g.
```cpp=
struct itype {int x;};
itype operator+(itype a, itype b, itype c) {
return {a.x + b.x + c.x + 10};
}
```
:::
:::danger
error: 'itype operator+(itype, itype, itype)' must take either one or two arguments
:::
### 習慣用法
可以透過多載`operator<`來讓自訂類別可以`sort`
```cpp=
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct two_element {
int first, second;
};
bool operator<(two_element a, two_element b) {
if (a.first != b.first)
return a.first > b.first;
else
return a.second > b.second;
}
int main() {
vector<two_element> v{{2, 2}, {3, 1}, {2, 1}};
sort(v.begin(), v.end());
for (const auto& i : v)
cout << i.first << ' ' << i.second << endl;
return 0;
}
```
```
result:
3 1
2 2
2 1
```
---
## Default Arguments
:::info
又稱預設參數、預設引數
:::
如果今天有個函數```add```
需要進行兩個數的加法或三個數的加法
那我們可以用上面學過的 [Function overload](#Function-overload)來實現
i.e.
```cpp=
int add(int a, int b){
return a + b;
}
int add(int a, int b, int c){
return a + b + c;
}
```
但是這樣類似的東西就寫了兩次,既慢又不好看
那接下來就要介紹其中一個解決辦法: Default Arguments
正如名字裡敘述的,這個解決辦法就是將引數設預設值
講明白一點就是讓不指定引數值時,有一個預設的值可以用
剛剛那個例子就可以這樣改
i.e.
```cpp=
int add(int a, int b, int c = 0) {
return a + b + c;
}
```
在第三個引數`c`沒有用到時讓它預設為 $0$
就可以達到跟上面多載兩個`add`一樣的效果
另外,Default Arguments 使用上需要注意的地方
e.g.
```cpp=
int add(int a, int b = 0, int c) {
return a + b + c;
}
```
:::danger
error: default argument missing for parameter 3 of 'int add(int, int, int)'
:::
像是這樣,中間有預設引數但後面沒有就會導致編譯錯誤
所以要將第一個用 Default Arguments 後的所有引數都設 Defalut argement才合法
e.g.
```cpp=
int add(int a, int b = 0, int c = 0) {
return a + b + c;
}
```
> [color=#4ee0b9][name=9th進階教學$] [time=Sat, May 16, 2020 11:56 AM]