Try   HackMD

OOP note using C++

紀錄考試筆記

Access Modifiers

public: 能被物件以及使用物件的地方使用
private: 只能在物件內被使用
protected: 只能在物件內被使用,也可以被繼承(inheritance)該物件的物件使用

https://www.geeksforgeeks.org/access-modifiers-in-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; }

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


class

  1. constructor v.s. destructor

    https://learn.microsoft.com/zh-tw/cpp/cpp/destructors-cpp?view=msvc-170

    • constructor : 自訂類別初始化其成員的方式,或在建立類別的物件時叫用函式

    • destructor: 解構函式是成員函式,當物件超出範圍或由 或呼叫delete明確終結時,會自動叫用。

    • 解構子就是建構子的相反,不過建構子可以overload,解構子不行 (只能有一個解構子)。compiler會自動解構子,所以就算不寫也會解構。

      寫法:

      ​​​​​​​​class A{ ​​​​​​​​ ~A(){ /**<---這就是解構子,加一個波浪**/ ​​​​​​​​ } ​​​​​​​​};
  2. this

    • points to the object
      ex:
      ​​​​​​​​private: ​​​​​​​​ int num; ​​​​​​​​public: ​​​​​​​​ void setNum(int num){ ​​​​​​​​ this->num = num; ​​​​​​​​ }
  3. const

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  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
      ​​​​​​​​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-中關於-virtual-的兩三事-1b4e2a2dc373
    https://viml.nchc.org.tw/archive_blog_547/
    virtual : 被用在修飾member function,代表若有 derived class 的話,該函式可以被 redefined
    override : 只要在衍生類別裡面、要覆寫函式後面加上「override」、告訴編譯器這個函式是要用來覆寫基礎類別的虛擬函式就可以了。
    ex:

    ​​​​class Base{ ​​​​ public: ​​​​ virtual void func1() {} ​​​​ virtual void func2() {} ​​​​ void nonVirtualFunc() {} ​​​​}; ​​​​class Derived : public Base{ ​​​​ public: ​​​​ virtual void func2() override {} ​​​​ void nonVirtualFunc() {} ​​​​}; ​​​​Base myBase;

    關係圖:

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    沒有virtual的function不可被改寫

  9. pure virtual function

    https://medium.com/@s9224914/oop-什麼是抽象-virtual-function-with-c-example-e4d386866709
    ex:

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    Base 類別中的 showInfo() 為 pure virtual function,
    意味著 Base 類別不可被實體化成 instance;繼承Base的衍生類別必須實作 showInfo() 函式。
    ex:
    螢幕擷取畫面 2024-06-16 021230

    螢幕擷取畫面 2024-06-16 021249

    螢幕擷取畫面 2024-06-16 021308

    File_filter內做了pure virtual function : transform
    其他兩個class必須實作 transform 這個function(如果有.h檔,必須實作在.h檔內,不能實作在.cpp)


struct

ex:

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:
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/

    ​​​​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:

      ​​​​​​​​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

      ​​​​​​​​//定義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:

      ​​​​​​​​CpClass CpClass::operator=(CpClass r){ ​​​​​​​​ *p = *r.p; ​​​​​​​​ return *this; ​​​​​​​​};
    • "=="
      ex:

      螢幕擷取畫面 2024-06-16 012235

    • "++" & ""
      //考完試補

    • "<<" & ">>"
      ex:
      在class的.h檔建friend function

      螢幕擷取畫面 2024-06-16 013444
      在.cpp檔實做(記得要兩個reference)
      螢幕擷取畫面 2024-06-16 013429

    • conversion
      //考完試補


Something special (* ~ *)

1. Type Conversion

https://www.scaler.com/topics/cpp/type-conversion-in-cpp/

  • Implicit type conversion (automatic)
    編譯器自動完成型別轉換的地方。
    編譯器會自動將所有資料類型轉換為表達式中存在的最高資料類型
    ex:
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:

The value of (50 + 'a') is: 147 The value of float_var is: 220.5

data-loss-chart

  • Explicit type conversion
    顯式類型轉換是由程式設計師手動完成的那些轉換。
    • Using the Assignment Operator
      ex: int_var = (int) char_var;

    • Using the Cast Operator

      1. static_cast
        方式和上面差不多
        ex:
      ​​​​​​​​double num = 3.7; ​​​​​​​​int cast_var; ​​​​​​​​cast_var = static_cast <int> (num);
      1. dynamic_cast
        當我們從父類別(Base)到衍生類別(Derived)進行類型轉換時才能使用此轉換。如果轉換失敗,該表達式將傳回 NULL 值。
        ex:
      ​​​​​​​​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; ​​​​​​​​}
      1. const_cast
        通常用在具有一個或多個物件的程式中,這些物件具有一些常數值,需要在程式中的某個時刻進行更改。
        ex:
      ​​​​​​​​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

      1. reinterpret_cast
        用於將一種指標類型轉換為另一種指標類型,無論這些類別是否相關。它不檢查指標類型和指標所指向的資料是否相同。
        主要用於處理位元。
        ex:
      ​​​​​​​​​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

      ​​​​​​​​​​  在上面的例子中,我們聲明了一個指向值98的整數指標ptr。
      ​​​​​​​​​​  列印這些值後,我們可以觀察到*ch 列印“b”,
      ​​​​​​​​​​  因為“b”相當於 ASCII 中的 98。值ch包含98。
      

2. string .data()

​​​​ str.data() 直接以數組方式返回string的內容,
​​​​ 其大小爲size()的返回值,結尾並沒有\0字符。

3. enum

ex:

enum Tree {ASH, ELM, OAK} tree1, tree2; // 代表 0 1 2 tree1 = ASH // == (tree1 = 1)
  • 用在case中能對choice取名字
    ex:
    ​​​​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
    也就是說一般的enum可以在不同群之間使用(因為都會被翻成int),但enum class只能在自己的小圈圈用

4. File operation

  • fstream : 檔案操作的library

    https://hackmd.io/@voidism/ry4GNk78-?type=view
    ex:

    ​​​​#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:

    ​​​​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

  • peek:看inputstream但不拿出
    ex:

    ​​​​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
    螢幕擷取畫面 2024-06-16 173438

  • 結構化寫入寫出:
    ex:
    store(write to file)

    ​​​​void menu::store(ofstream &out){ ​​​​ //write stringint 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)

    ​​​​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儲存多筆資料

    ​​​​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
螢幕擷取畫面 2024-06-16 150647

6. extern

https://wucodingroad.blogspot.com/2017/05/Cplusplus-extern.html
用來聲明此變數只是一個宣告,它的定義在別處,可能在同一個文件,也可能在別的文件,告知程式去尋找。

7. volatile

https://ithelp.ithome.com.tw/articles/10308388

  • 修飾變數
    強制編譯器直接讀取變數的記憶體value,而不是讀取其暫存器的值(防止變數變化太快而出錯)