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;
}
```
### 陣列不可以直接複製 C語言規定
```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
```