# 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; } ``` ![螢幕擷取畫面 2024-06-12 150154](https://hackmd.io/_uploads/SygzupLHC.png) --- ## ***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** ![螢幕擷取畫面 2024-06-15 230320](https://hackmd.io/_uploads/SyRrpmsrA.png) 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; ``` 關係圖: ![螢幕擷取畫面 2024-06-16 015829](https://hackmd.io/_uploads/HyfDULjBA.png) 沒有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: ![螢幕擷取畫面 2024-06-16 020222](https://hackmd.io/_uploads/rJ9nw8ir0.png) Base 類別中的 showInfo() 為 pure virtual function, 意味著 Base 類別不可被實體化成 instance;繼承Base的衍生類別**必須**實作 showInfo() 函式。 ex: ![螢幕擷取畫面 2024-06-16 021230](https://hackmd.io/_uploads/HJFX5UjrC.png) ![螢幕擷取畫面 2024-06-16 021249](https://hackmd.io/_uploads/SJJe5IjHR.png) ![螢幕擷取畫面 2024-06-16 021308](https://hackmd.io/_uploads/H1yxqIorC.png) 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; ``` ![螢幕擷取畫面 2024-06-16 011659](https://hackmd.io/_uploads/r1Y2hBor0.png) ```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: ![螢幕擷取畫面 2024-06-16 012235](https://hackmd.io/_uploads/SJZgRHjSA.png) * **"++"** & **"--"** //考完試補 * **"<<"** & **">>"** ex: 在class的.h檔建friend function ![螢幕擷取畫面 2024-06-16 013444](https://hackmd.io/_uploads/BycybLjrC.png) 在.cpp檔實做(記得要兩個reference) ![螢幕擷取畫面 2024-06-16 013429](https://hackmd.io/_uploads/HJUvb8jBC.png) * 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 ``` ![data-loss-chart](https://hackmd.io/_uploads/B1kdsCIHR.png) * **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; } ``` ![螢幕擷取畫面 2024-06-12 162405](https://hackmd.io/_uploads/H1gBoALrR.png) 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; } ``` ![螢幕擷取畫面 2024-06-12 163907](https://hackmd.io/_uploads/ryQpR0LS0.png) 在上面的例子中,我們聲明了一個指向值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: ![螢幕擷取畫面 2024-06-15 224807](https://hackmd.io/_uploads/SJ5TKXjr0.png) 也就是說一般的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); ``` 開檔方式: ![螢幕擷取畫面 2024-06-16 150127](https://hackmd.io/_uploads/B1JNRZ3SC.png) * **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** ![螢幕擷取畫面 2024-06-16 173123](https://hackmd.io/_uploads/HJt6b4nHR.png) ![螢幕擷取畫面 2024-06-16 173438](https://hackmd.io/_uploads/SyF6W43HA.png) * 結構化寫入寫出: 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有關 ![螢幕擷取畫面 2024-06-16 150631](https://hackmd.io/_uploads/ryYSJM2r0.png) ![螢幕擷取畫面 2024-06-16 150647](https://hackmd.io/_uploads/H1KByz2rR.png) ### 6. extern > https://wucodingroad.blogspot.com/2017/05/Cplusplus-extern.html ``` 用來聲明此變數只是一個宣告,它的定義在別處,可能在同一個文件,也可能在別的文件,告知程式去尋找。 ``` ### 7. volatile > https://ithelp.ithome.com.tw/articles/10308388 * **修飾變數** 強制編譯器直接讀取變數的記憶體value,而不是讀取其暫存器的值(防止變數變化太快而出錯)