---
# System prepended metadata

title: C++ 進階程式設計 Day2
tags: [c++]

---

C++ 進階程式設計 Day2
===
###### tags: `c++`

### Recall
- `auto` 作為函式宣告可以視為 `template`
```cpp=
void f(auto a){
    auto b = 7; // 語法角度幫忙推論
    std::cout << a << std::endl;
}
int main(){
    f(7); // 字面常數 可以推論為整數型態
}
```
- 等同
```cpp=
template<typename T>
void f(T a){
    T b = 7; // 語法角度幫忙推論
    std::cout << a << std::endl;
}
int main(){
    f(7); // 字面常數 可以推論為整數型態
}
```
#### 資工實作一遍會比別人還深入 算法的優缺點
- 範例學習是起點，背後動機是什麼才會用
- 他是指用新工具的哪個文件的函式 - 函式多載
- [sort 文件](https://en.cppreference.com/w/cpp/algorithm/sort) 知道範例是用哪個例子嗎？深入瞭解

- 以下是 編譯錯誤？實作定義？未定義行為？
    - 實作定義：編譯器定義
```cpp=
int main(){
    int i;
    cout << i << endl;
    return 0;
}
// 未定義行為
```
- 那以下是？
```cpp=
int i;
int main(){
    cout << i << endl;
    return 0;
}
// 全域變數在編譯時候必須被算出 所以會是0
```
- Question
```cpp=
int main(){
    double a = 1000000000000;
    int b = a;
    cout << b << endl;
    return 0;
    // 實作定義 ，塞不下會選擇long long...
}
```
## 賦值運算
- C語言預設：複製內容值
- 賦值運算子 `=` 優先順序是由右到左

```cpp=
#define a 3
// 取代a 為3
int main(){
    int b[a];
}
```
#### `constexpr`
- `constexpr` 表示值或傳回值為 constant，而且可能的話，會在編譯時期計算。


```cpp=
f(){
    return 3;
}
int main(){
    const int b = f();
}
// 編譯器一開始會知道b嗎？ 難道編譯期要去呼叫 f()? 
// 會導致編譯器工作量過大, constexpr，或是MACRO 
// 可以保證在編譯時期計算
```
```cpp=
constexpr f(){
    return 3;
}
int main(){
    const int b = f();
}
```
### Question 3 > 2 > 1 ?
1. `3 > 2 True`
2. `True > 1 ` ? `bool` 可以跟 `int` 比嗎？
3. 為了跟 `C` 相容，會存在隱性轉型
    - `true` -> `1`
    - `false` -> `0`

### Q: 編譯時期一定要確保的事情有
1. 型態，陣列大小就是型態
2. 如果要讓編譯器知道，可以做很多事such as `MACRO`, `meta programming`

### 短路求值
```cpp=
int main(){
    int a = 0;
    if( a!=0 && 3/a==0){
        cout << "Hello" << endl;
    }
}
//執行 a!=0 就結束 
```
```cpp=
int main(){
    int a = 0;
    if(3/a==0 && a!=0){
        cout << "Hello" << endl;
    }
}
// 3/a==0 未定義行為
```
## 複合資料型態
### Pointer
- 儲存「記憶體位置」的資料型態
- `&a` “產生”暫時物件的記憶體位置
### 指標相關運算
- (T*): 儲存記憶體位置的資料型態
- & ：取得記憶體起始位置
- (*) ：取得記憶體上的起始物件

### 無法取得位置
1. 字面常數
```cpp=
//編譯錯誤
int main(){
    int *b = &3;
    return 0;
    // 編譯器思維：如果字面常數跑的時候都可以取得位置。
    // lvalue 才可以取值，lvalue未必是變數
}
```
- `lvalue`記憶體空間可以被賦值
2. 暫時物件
```cpp=
//編譯錯誤
int main(){
    int a = 1;
    int *b = &(a + 1);
    return 0;
}
```
- _**HINT**_:`C++` 編譯器世界難寫的，只有那幾套。
### &&a
1. &a 是一個暫時物件。
2. &暫時物件，編譯錯誤

### 參考概念，產生新的物件還是不要產生新的物件
- _**Ans**_ 不產生新的物件
```cpp=
int main(){
    int a = 1;
    int &b = a; // b 就是 a 的別名
    b = 5;
    cout << a << endl
    cout << b << endl;
    return 0;
    // ** 對 b 操作就是對 a 操作
}
```
### 不存在參考的參考 &&a
### 陣列元素不能是參考
### C++ 開了恐怖的窗 `rvalue` 可以被 `const T&`參考
```cpp=
int main(){
    const int& a = 1;
    const int& b = a + 1;
    cout << a << endl
    cout << b << endl;
    return 0;
    // 唯獨的參考最為廣泛使用
}
```
- ? 唯獨的參考最為廣泛使用? 後面自定義類別，範型需要

### 5 - 80
```cpp=
int main(){
    int a = 3;
    const double& b = a; // 隱性轉型成暫時物件 b 
    const long long& c = a;// 隱性轉型成暫時物件 c
    return 0;
}
```
- `const T&` 可以參考暫時物件

## 陣列型態
- `int var[3]` 一個父物件，三個子物件
### 初始化的方式
```cpp=
int main(){
    int a[3] = {1, 2, 3};
    int b[3]{1, 2, 3};
    
    return 0;
}
```
### 對陣列使用的範圍
```cpp=
int main(){
    int a[3] = {1, 2, 3};
    int b[3]{1, 2, 3};
    for(auto v:b){
        cout << v<< endl;
        // 這裡是做複製
    }
    for(auto& v:b){
        v = 0; // 全部被設定
        cout << v<< endl;
    }
    return 0;
}
```
### 陣列不可以直接複製 Ｃ語言規定
```cpp=
int main(){
    int a[3] = {1, 2, 3};
    int *b = a; //隱性轉型成第一個陣列的記憶體位置
    // int *b = &a[0];
    for(int i = 0; i!=3; i++){
        cout << b[i] << endl;
        cout << *(b+i) << endl;
    }
}
```
- **HINT** `int *b = a`隱性轉型成第一個陣列的記憶體位置

## 函式的宣告定義
- 有宣告沒有定義，連結錯誤
- 有定義沒有宣告，編譯錯誤
### 函式呼叫，函式參數以引述進行初始化
```cpp=
void Print(const char*);

int main(){
    Print("Hello");
    return 0;
}
void Print(const char* str){
    cout << str << endl;
}
```

### Function Overloading
```cpp=
void Print(const char*);
void Print(char*)

int main(){
    Print("Hello"); //編譯的時候就知道了
    Print('\n');   //編譯的時候就知道了
    return 0;
}
void Print(const char* str){
    cout << str << endl;
}
void Print(char str){
    cout << str << endl;
}
```
- 依照傳的`argument`與`parameter`的相似性決定呼叫哪一個函式
- `Python`沒辦法保證編譯的時候知道所有事

### 傳遞物件到函式內 -> C++ 參考
```cpp=
void Swap(int&, int&);

int main(){
    int a = 1;
    int b = 2;
    Swap(a,b);
}
void Swap(int& a, int& b){
    int t = a;
    a = b;
    b = t;
}
```
### 函式的回傳值是暫時物件
```cpp=
int f(){
    return 1;
}
int main(){
    f() = 5;
};
// 編譯錯誤 暫時物件不能被賦予
```
```cpp=
int& f(){
    return 1;
}
int main(){
    f() = 5;
};
// 編譯錯誤 規則：字面常數不能被參考
```
```cpp=
int f(){
    int a = 1
    return a;
}
int main(){
    f() = 5;
};
// 編譯錯誤 生命週期
```
```cpp=
int& f(int& a){
    return a;
}
int main(){
    int a = 1;
    f(a) = 5;
};
// 編譯過 參考到`main` 裡面的 a ，回傳原本`main` a
```