# OOP note using C++
紀錄考試筆記
## ***Access Modifiers***
**public**: 能被物件以及使用物件的地方使用
**private**: 只能在物件內被使用
**protected**: 只能在物件內被使用,也可以被繼承(inheritance)該物件的物件使用
> https://www.geeksforgeeks.org/access-modifiers-in-c/
```c++=
class Parent
{
protected:
int id_protected;
};
class Child : public Parent
{
public:
void setId(int id) {
id_protected = id;
}
void displayId() {
cout << "id_protected is: " << id_protected << endl;
}
};
int main() {
Child obj1;
obj1.setId(81);
obj1.displayId();
return 0;
}
```

---
## ***class***
1. ### **constructor v.s. destructor**
> https://learn.microsoft.com/zh-tw/cpp/cpp/destructors-cpp?view=msvc-170
* constructor : 自訂類別初始化其成員的方式,或在建立類別的物件時叫用函式
* destructor: 解構函式是成員函式,當**物件超出範圍**或由 或**呼叫delete**明確終結時,會自動叫用。
* 解構子就是建構子的相反,不過建構子可以overload,解構子不行 (只能有一個解構子)。compiler會自動解構子,所以就算不寫也會解構。
寫法:
```c++=
class A{
~A(){ /**<---這就是解構子,加一個波浪**/
}
};
```
2. ### **this**
- points to the object
ex:
```c++=
private:
int num;
public:
void setNum(int num){
this->num = num;
}
```
3. ### **const**

4. ### **static member**
* #### 使用在一個member variable前面
全部object的這個變數都是同一個memory address
* #### 使用在一個member function前面
看瞴中...
5. ### **friend**
* 不是同個class中的member,但可使用private的東東
6. ### **copy constructor**
* Student s2 = s1 or Student s2(s1),s1的東東會複製給s2
* 當有使用pointer時會出錯 (因為pointer指向地址,會造成複製後指向地址依然相同)
解法: 自己重建pointer
```c++=
class CpClass
{
int *p;
public:
CpClass(const CpClass &obj)
{ p = new int; *p = *obj.p; }
CpClass(int v = 0)
{ p = new int; *p = v; }
~CpClass(){delete p;}
};
```
7. ### **inheritance**
ex:
```
class Base{
};
class Derived : public Base{
};
```
protector & public 內的member可在繼承後拿到
8. ### **virtual** & **override**
>https://medium.com/theskyisblue/c-%E4%B8%AD%E9%97%9C%E6%96%BC-virtual-%E7%9A%84%E5%85%A9%E4%B8%89%E4%BA%8B-1b4e2a2dc373
>https://viml.nchc.org.tw/archive_blog_547/
*virtual* : 被用在修飾member function,代表若有 derived class 的話,該函式可以被 redefined
*override* : 只要在衍生類別裡面、要覆寫函式後面加上「override」、告訴編譯器這個函式是要用來覆寫基礎類別的虛擬函式就可以了。
ex:
```c++=
class Base{
public:
virtual void func1() {}
virtual void func2() {}
void nonVirtualFunc() {}
};
class Derived : public Base{
public:
virtual void func2() override {}
void nonVirtualFunc() {}
};
Base myBase;
```
關係圖:

沒有virtual的function不可被改寫
9. ### **pure virtual function**
> https://medium.com/@s9224914/oop-%E4%BB%80%E9%BA%BC%E6%98%AF%E6%8A%BD%E8%B1%A1-virtual-function-with-c-example-e4d386866709
ex:

Base 類別中的 showInfo() 為 pure virtual function,
意味著 Base 類別不可被實體化成 instance;繼承Base的衍生類別**必須**實作 showInfo() 函式。
ex:



File_filter內做了pure virtual function : transform
其他兩個class必須實作 transform 這個function(如果有.h檔,必須實作在.h檔內,不能實作在.cpp)
---
## ***struct***
ex:
```c++=
struct Student{
int studentID;
string name;
};
```
* 使用 "." 運算 refer to members of struct variables
ex: Student s1; s1.name = "tavha";
* or 可以直接initial
ex: Student s1 = {s1088888, "tavha"};
可以 s1 = {s1088888}; // 只宣告第一個
但不行 s1 = {, "tavha"}; //不可跳過member
* A struct with constructor
ex:
```c++=
struct Dimensions
{
int length, width, height;
// Constructor
Dimensions(int L=0, int W=0, int H=0)
{length = L; width = W; height = H;}
};
```
---
## ***Overload***
1. ### ***overload constructor***
* 重載的建構函數本質上具有**相同的名稱**(類別的確切名稱),但**參數的數量和類型不同**。
* **根據傳遞的參數的數量和類型**呼叫建構函數。
* 建立物件時,必須傳遞參數以讓編譯器知道需要呼叫哪個建構子。
> https://www.geeksforgeeks.org/constructor-overloading-c/
```c++=
class construct {
public:
float area;
construct() {
area = 0;
}
construct(int a, int b) {
area = a * b;
}
};
```
2. ### ***overloading operator***
使用類別成員來超載二元運算子時,會有一個限制,就是運算子的左邊一定要是原物件。
使用 *friend*函式重載二元運算子時,您要指定兩個參數型態,分別表式運算子左右邊的運算元型態。
* **"+"**
> https://openhome.cc/Gossip/CppGossip/friendOverLoadOperator.html
ex:
```c++=
OpClass OpClass::operator+(OpClass r){
OpClass sum;
sum.x = this->x + r.x;
return sum;
}
OpClass a, b, s;
s = a + b;
```

```c++=
//定義Point2D.h:
class Point2D {
public:
friend Point2D operator+(const Point2D&, int);
friend Point2D operator+(int, const Point2D&);
private:
int _x;
int _y;
};
//再實作Ball.cpp:
#include "Point2D.h"
Point2D operator+(const Point2D &p, int i) {
Point2D tmp(p._x + i, p._y + i);
return tmp;
}
Point2D operator+(int i, const Point2D &p) {
Point2D tmp(i + p._x, i + p._y);
return tmp;
}
//接著您就可以直接如下進行運算:
Point2D p1(5, 5);
Point2D p2;
p2 = 10 + p1;
```
* **"="**
ex:
```c++=
CpClass CpClass::operator=(CpClass r){
*p = *r.p;
return *this;
};
```
* **"=="**
ex:

* **"++"** & **"--"**
//考完試補
* **"<<"** & **">>"**
ex:
在class的.h檔建friend function

在.cpp檔實做(記得要兩個reference)

* conversion
//考完試補
---
## ***Something special*** (* ~ *)
### 1. Type Conversion
> https://www.scaler.com/topics/cpp/type-conversion-in-cpp/
* **Implicit type conversion (automatic)**
編譯器自動完成型別轉換的地方。
編譯器會自動將**所有資料類型轉換為表達式中存在的最高資料類型**。
ex:
```c++=
int main() {
int int_var = 50;
char char_var = 'a';
int_var = int_var + char_var;
cout << "The value of (50 + 'a') is: " << int_var << endl;
float float_var = int_var * 1.5;
cout << "The value of float_var is: " << float_var << endl;
return 0;
}
```
output:
```c++=
The value of (50 + 'a') is: 147
The value of float_var is: 220.5
```

* **Explicit type conversion**
顯式類型轉換是由程式設計師手動完成的那些轉換。
* Using the Assignment Operator
ex: int_var = (int) char_var;
* Using the **Cast** Operator
1. *static_cast*
方式和上面差不多
ex:
```c++=
double num = 3.7;
int cast_var;
cast_var = static_cast <int> (num);
```
2. *dynamic_cast*
當我們從父類別(Base)到衍生類別(Derived)進行類型轉換時才能使用此轉換。如果轉換失敗,該表達式將傳回 NULL 值。
ex:
```c++=
class Base {
public:
virtual void print() {}
};
class Derived: public Base {};
int main() {
Base* b = new Derived;
Derived* d = dynamic_cast <Derived*> (b);
if (d != NULL) {
cout << "dynamic_cast done" << endl;
}
else {
cout << "dynamic_cast not done" << endl;
}
return 0;
}
```
3. *const_cast*
通常用在具有一個或多個物件的程式中,這些物件具有一些常數值,需要在程式中的某個時刻進行更改。
ex:
```c++=
int main() {
const int var1 = 10;
const int* ptr1 = &var1;
cout << "The old value of ptr1 is: " << *ptr1 << endl;
int* ptr2 = const_cast <int*> (ptr1);
*ptr2 = 3;
cout << "The new value of ptr1 is: " << *ptr1 << endl;
return 0;
}
```

4. *reinterpret_cast*
用於將一種**指標類型**轉換為另一種指標類型,無論這些類別是否相關。它不檢查指標類型和指標所指向的資料是否相同。
主要用於處理位元。
ex:
```c++=
int main() {
int* ptr = new int(98);
char* ch = reinterpret_cast <char*> (ptr);
cout << "The value of *ptr is: " << *ptr << endl;
cout << "The value of ptr is: " << ptr << endl;
cout << "The value of *ch is: " << *ch << endl;
cout << "The value of ch is: " << ch << endl;
return 0;
}
```

在上面的例子中,我們聲明了一個指向值98的整數指標ptr。
列印這些值後,我們可以觀察到*ch 列印“b”,
因為“b”相當於 ASCII 中的 98。值ch包含98。
### 2. string .data()
str.data() 直接以數組方式返回string的內容,
其大小爲size()的返回值,結尾並沒有\0字符。
### 3. enum
ex:
```c++=
enum Tree {ASH, ELM, OAK} tree1, tree2;
// 代表 0 1 2
tree1 = ASH // == (tree1 = 1)
```
* 用在case中能對choice取名字
ex:
```c++=
switch(tree1)
{
case ASH: cout << "Ash";
break;
case ELM: cout << "Elm";
break;
case OAK: cout << "Oak";
break;
}
```
* enum class (又稱strong type enum)
> https://viml.nchc.org.tw/archive_blog_720/
ex:

也就是說一般的enum可以在不同群之間使用(因為都會被翻成int),但enum class只能在自己的小圈圈用
### 4. File operation
* **fstream** : 檔案操作的library
>https://hackmd.io/@voidism/ry4GNk78-?type=view
ex:
```c++=
#include<fstream>
ifstream inFile;
ofstream outFile;
//開檔
inFile.open("inventory.dat");
outFile.open("report.txt");
//拿data
while(!infile.eof()){
infile.get(ch);
cout << ch;
}
//關檔
inFile.close();
outFile.close();
```
or
ex:
```c++=
fstream file;
file.open("myfile.dat", ios::in);
file.open("myfile.dat", ios::out);
//或者可以
file.open("myfile.dat", ios::in|ios::out);
```
開檔方式:

* **peek**:看inputstream但不拿出
ex:
```c++=
ifstream inFile; char ch;
inFile.open("myFile");
ch = inFile.peek();
cout << "Got " << ch;
ch = inFile.peek();
cout << "Got " << ch;//same output
```
* **seek**


* 結構化寫入寫出:
ex:
store(write to file)
```c++=
void menu::store(ofstream &out){
//write string
int Length = item_description.length();
out.write(reinterpret_cast<char *>(&Length), sizeof(int));
out.write(item_description.data(), Length);
//write int
out.write(reinterpret_cast<char*>(&quantity_on_hand),
sizeof(quantity_on_hand));
out.write(reinterpret_cast<char*>(&wholesale_cost),
sizeof(wholesale_cost));
out.write(reinterpret_cast<char*>(&retail_cost),
sizeof(retail_cost));
out.write(reinterpret_cast<char*>(&date_added),
sizeof(date_added));
}
```
load(read from file)
``` c++=
void menu::load(ifstream &in){
//read string
static char buffer[256];
int Length;
in.read(reinterpret_cast<char *>(&Length), sizeof(int));
in.read(buffer, Length);
buffer[Length] = '\0';
item_description = buffer;
//read int
in.read(reinterpret_cast<char*>(&quantity_on_hand),
sizeof(quantity_on_hand));
in.read(reinterpret_cast<char*>(&wholesale_cost),
sizeof(wholesale_cost));
in.read(reinterpret_cast<char*>(&retail_cost),
sizeof(retail_cost));
in.read(reinterpret_cast<char*>(&date_added),
sizeof(date_added));
}
```
用array儲存多筆資料
```c++=
menu m[2];
ifstream in("Menu.dat", ios::binary);
in.close();
ofstream out("Menu.dat", ios::binary);
m[1].add(out, description, Quantity, Wholesale, Retail, Date);
out.close();
```
note:好像要先關一個再開另一個才不會錯
### 5. iomanip有關


### 6. extern
> https://wucodingroad.blogspot.com/2017/05/Cplusplus-extern.html
``` 用來聲明此變數只是一個宣告,它的定義在別處,可能在同一個文件,也可能在別的文件,告知程式去尋找。 ```
### 7. volatile
> https://ithelp.ithome.com.tw/articles/10308388
* **修飾變數**
強制編譯器直接讀取變數的記憶體value,而不是讀取其暫存器的值(防止變數變化太快而出錯)