kyle shanks
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    1
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- title: '類別 & 動態記憶體 & 拷貝' disqus: kyleAlien --- 類別 & 動態記憶體 & 拷貝 === ## OverView of Content 如有引用參考請詳註出處,感謝 :smile: > 在類別中配置動態記憶體,要十分注意記憶體配置釋放,以及它載入時使用的順序 [TOC] ## 類別 - 靜態成員 ### 靜態元素 - static * static 成員特性:static 是 **[指示字](https://hackmd.io/uf-tHfltRVCV45D1h6ZiGA#指示字、修飾字)**,**不管產生多少的物件,每個物件都是使用同一個靜態成員** * **==不能在宣告中定義 static==**,會編譯期間出錯,這樣其實滿合理的,否則每 include 一次就會導致 static 變數重算 (guess) ```cpp= // 抽象 Class #ifndef CLASS___NEW_STRINGBAD_H_ #define CLASS___NEW_STRINGBAD_H_ class stringbad { private: static int objectCount; // static int objectCount = 0; // Error public: stringbad(); virtual ~stringbad(); }; #endif /* CLASS___NEW_STRINGBAD_H_ */ // ----------------------------------------------------------- // 定義 Class #include "stringbad.h" int stringbad::objectCount = 0; ``` > 靜態元素定義在 Class 中會編譯失敗 > > ![](https://i.imgur.com/KqhgJEX.png) :::warning * class 內它只能存在於宣告中,**在==定義中必須移除 static==不能使用指示字**,否則會在編譯期出錯 > ![](https://i.imgur.com/2mxmvVH.png) ::: ### 常量元素 - static & const * **const 可以讓 static 變量定義在 class 中**,但因為 **const 只能定義一次不能更改**,針對需求做出不同的使用方案 ```cpp= #ifndef CLASS___NEW_STRINGBAD_H_ #define CLASS___NEW_STRINGBAD_H_ class stringbad { ... const static int constant = 20; public: stringbad(); virtual ~stringbad(); }; #endif /* CLASS___NEW_STRINGBAD_H_ */ ``` ## 類別 & 動態記憶體 動態類別申請的記憶體在 **堆** 中,它並不會自動釋放,所以要 **配合類別的 ++析構函數++ 使用** ```cpp= // Class 抽象宣告 #ifndef CLASS___NEW_STRINGBAD_H_ #define CLASS___NEW_STRINGBAD_H_ #include <iostream> #include <cstring> using namespace std; class stringbad { char *str; // 字串內容指標 int strLen; // 子串長度 static int objectCount; const static int constant = 20; public: stringbad(); stringbad(char* str); virtual ~stringbad(); friend ostream& operator << (ostream& o, const stringbad& str); }; #endif /* CLASS___NEW_STRINGBAD_H_ */ // ------------------------------------------------------------------ // Class 定義 #include "stringbad.h" int stringbad::objectCount = 0; // 定義靜態成員初始化 (不能使用 static) stringbad::stringbad() : stringbad((char*)"C++") { // 呼叫指定建構函數 cout << "default construct" << endl; } stringbad::stringbad(char* str) { cout << "setting construct: " << str << endl; this->strLen = strlen(str); // 使用動態創建 new char[] (就是 new[]),+ 1 是為了加入字串的最後一碼 '\0' this->str = new char[this->strLen + 1]; strcpy(this->str, str); this->str[strLen] = '\0'; objectCount++; } stringbad::~stringbad() { cout << "deconstruct: " << str << endl; // 對等使用,在建構函數中建立 new[],在析構函數內 delete[] delete[] str; objectCount--; } ostream& operator << (ostream& o, const stringbad& str) { o << "-----> " << str.str << endl; return o; } int main() { return 0; } ``` ### 函數引數 & 動態規劃 - 複製物件 * 這裡要結合之前 [**函數引數**](https://hackmd.io/7Csy-1LVTouQFl2e2sBvtA#%E5%87%BD%E6%95%B8%E5%BC%95%E6%95%B8) 概念 & 新的動態規劃的概念一起思考 ```cpp= void callMethod_Ref(stringbad & s) { // 使用原物件 cout << "In Reference: " << s << endl; } void callMethod_Val(stringbad s) { //"2. " 會產生形式變數 cout << "In Value: " << s << endl; } int main() { // create 3 object of stringbad stringbad st1((char*)"Hey Pan, how's going on?"); stringbad st2((char*)"Today is Saturday"); stringbad st3((char*)"I read book at friend's coffee shop for prepare find new job"); cout << "\n" << st1; operator<<(cout, st2); cout << st3 << endl; // call reference function callMethod_Ref(st1); //"1. " cout << "After call reference function: " << st1 << endl; // call value function callMethod_Val(st2); //"3. " cout << "After call value function: " << st2 << endl; cout << "Implicit copy" << endl; stringbad st4 = st3; // "4. " cout << st3 << endl;; cout << st4 << endl; return 0; } ``` 1. 使用 reference 由於是使用原本的物件,不會導致析構 > ![](https://i.imgur.com/1bRTWvj.png) 2. **產生暫時物件**:**暫時物件會複製原來物件 str 的成員函數,但++不包括 static 成員++**,而 **暫時物件的產生,又是透過==複製建構函數== 建構出來** :::info 複製建構函數之後說明 ::: 3. 在 `2` 中建構的暫時物件,會在 function 結束後自動釋放,而 **==它的釋放又會呼叫到 st2 的析構函數==,++導致 st2 new[] 出的空間被刪除++,在後面要求要顯示該物件的內容錯誤,無法正常顯示** (空字串) > ![](https://i.imgur.com/4pfb1Nt.png) 4. 這個方式又是另一個呼叫複製建構函數的方式 :::info 複製建構函數不使用一般的 construct ::: > ![](https://i.imgur.com/RTdAUmX.png) ### GPF (General Protection Fault) * GPF 代表,當程式 **試圖想要存取不屬於它的記憶體空見範圍的資料** > 上面範例可看到,**delete[] 超過的物件原本的數量**,有些變異程式 or 作業系統會**在 -1 之前阻止該程式繼續運行** ### 建構函數中 new - 注意事項 * 在建構函數中使用 new,就必須在解構函數中使用 delete (對稱使用);像是 `new` & `delete`、`new[]` & `delete[]` 必須 **成對使用** :::info **delete 可操作在空指標上**,不會異常 ::: ```cpp= class P { private: char * str; public: P(); ~P(); }; P::P() { str = nullptr; //C++11 使用 // str = 0; 同上 } P::~P() { delete[] str; // ok, delete 可操作在空指標上 } int main() { P p; return 0; } ``` * **讓一個物件初始化另一個物件時必須要==覆寫建構函數==**,並做深層拷貝 (下面會詳細說) * **讓一個==暫時物件==(轉換函數) 初始化另一個物件時必須要 ==覆寫建構函數==**,並做深層拷貝 (下面會詳細說) ## 特殊成員函數 若程式設計師沒有去定義以下成員函數,**C++ 將會 ==自動提供==** :::success 1. 預設 **建構函數** -> `Object()` 2. **複製建構函數** -> `Object(const Object &)` 3. **指定運算子** -> `operater =` (等號) 4. **解構函數** -> `~Object()` 5. **位置運算子** -> `this` (每個 class 自帶) ::: ### 預設建構函數 * 無引數 & 不做任何事情,當然也可以去自己定義,但是 **當有預設函數時,兩者不能相互存在** :::info 預設建構函數的存在是因為 **物件都需要建構函數** ::: ```cpp= stringbad::stringbad() { // 預設建構函數 } stringbad::stringbad(int len = 0) { // 預設建構函數 + 預設函數,在函數簽名解釋起來會相互衝突的 } ``` ### 複製建構函數 複製建構函數,原型如下,**默認會複製成員變數** ```cpp= class stringbad { ... public: ... // 固定格式 stringbad(const stringbad &); } // ------------------------------------------------------------------- // 實現 stringbad::stringbad(const stringbad &s) { this->str = s.str; this->strLen = s.strLen; cout << "copy construct: " << this->str << endl; } ``` :::info 複製函數又做了哪些事情 ? 複製了成員變量,**但 ==靜態成員不複製==** (畢竟它是共用的),這種行為又稱為 **==淺拷貝==** ::: * 複製的建構函數,它的觸發方式 ==++**分為 2 個,觸發關鍵**++==,隱式、顯式 1. **顯式觸發**:直接賦予值,最常見以下幾種狀況,**將新物件透過 ++已存在物件++ 初始化,++不會產生暫時物件++** ```cpp= void explicitCopy() { stringbad st1((char*) "Hello World"); cout << "\nst2(st1), "; stringbad st2(st1); cout << "\nst3 = st1, "; stringbad st3 = st1; cout << "\nst4 = stringbad(st1), "; stringbad st4 = stringbad(st1); cout << "\n*st5 = new stringbad(st1), "; stringbad *st5 = new stringbad(st1); // 動態 } ``` > ![](https://i.imgur.com/vYKRzlH.png) 2. **隱式觸發**:Function 呼叫,在 Function 產生新物件,並要返回時,**會 ++產生暫時物件++** + 複製物件的行為 ```cpp= const stringbad testObject() { stringbad s("123 站著穿"); return s; // 產生暫時物件! 返回 } int main() { cout << "Main Start" << endl; testObject(); cout << "Main finish" << endl; return 0; } ``` > ![](https://i.imgur.com/9koBHR7.png) :::warning * 返回時,物件複製到哪裡,又在何時被解構 ? ^1.^ 返回前呼叫複製建構函數,將資料到某個記憶體位置、^2.^ 解構暫時物件、^3.^ 回來原來函數呼叫的地方,到指定記憶體為只取值 ::: * 以下使用複寫++複製建構函數++,**觀察 ==複製建構函數何時會被呼叫==** ```cpp= /* * 宣告 */ #include <iostream> class stringbad { ... public: ... stringbad(const stringbad & s); // 新增建構函數宣告 ... }; /** * 定義複製建構函數 */ stringbad::stringbad(const stringbad & s) { std::cout << ++objCount << "------call copy construct" << std::endl; } // ---------------------------------------------------------------------- /** * 客戶端 使用 */ #include "stringbad.h" using std::cout; using std::endl; void callMethod_Ref(stringbad & s) { cout << "In Reference:" << s << endl; } void callMethod_Val(stringbad s) { cout << "In Value:" << s << endl; } int main() { stringbad st1; // 呼叫建構函數 cout << st1 << ", addr: " << &st1 << "\n"; st1 = "Hello World 123"; // "1. " 建立暫時物件 cout << st1 << ", addr: " << &st1 << "\n"; stringbad st2("!!!AAAA"); // 呼叫建構函數 cout << st2 << ", addr: " << &st2 << "\n"; stringbad st3 = st2; // "2. " 呼叫建構函數 cout << st3 << ", addr: " << &st3 << "\n"; callMethod_Val("HHRRRDDD"); // "3. " stringbad st4("!!!BBBB"); callMethod_Val(st4); // "4. " return 0; } ``` 1. 字串會建構暫時物件,**++自動搜尋引數++ (符合一個引數的建構函數),此暫時物件會立刻解析**,之後也不會透過複製建構函數 2. **顯式把原有的物件 `st2`,複製到新物件 `st3`**,所以會呼叫 **複製建構函數** > ![](https://i.imgur.com/8KAZCi4.png) 3. 傳入 ++**引數**++,**建立暫時物件** (因為引數不匹配),不呼叫複製函數 4. 傳入 ++**引數**++ 再建立 ++**暫時物件**++,**隱式把 `st4` 複製到 `callMethod_Val` 函數中的引數 s**,會呼叫複製函數 > ![](https://i.imgur.com/lPCUWjr.png) | 方法 | 複製建構函數 | 一般建構函數 | | -------- | -------- | -------- | | st1 = "123" (隱式匹配、暫時變數) | No | Yes | | st1 = st2 | Yes 顯式 | No | | 呼叫方法(傳入 物件) | Yes 隱式 | No | | 呼叫方法(傳入 變數) (隱式匹配、暫時變數) | No | Yes | * **結論 : ==建構函數 & 複製建構函數不會同時使用==,==++有暫時物件不代表就會使用複製函數++==** ### 淺拷貝 & 深拷貝 * **預設的`複製建構函數`、`指定運算子` 都是淺拷貝,++==不拷貝 static 成員==++** 深拷貝都必須自己覆寫 :::success * 寫 ^1.^ `operator=` 指定運算子、^2.^ 複製建構函數,**才能確保有完整的深度拷貝** ::: * 另外還要注意的一點是,**拷貝函數的觸發情景** > ![](https://hackmd.io/_uploads/SyDtOZQD2.png) 1. **建構函數被賦予相同對象**,符合拷貝建構語法(`構造函數(const 類& other)`)所以會觸發: ```cpp= // 概念程式 Apple apple; Apple apple2(apple); ``` 2. **使用 `=` 賦予值**:複寫操作符 `=` 的意義,包含了拷貝、構造兩個概念 ```cpp= // 概念程式 Banana banana; Banana banana2 = banana; ``` 3. **function 傳入參數是實體類,也會觸發拷貝函數**: ```cpp= // 概念程式 void myFunc(Car car) { // 觸發 } void myFuncRef(Car& car) { // 引用不會觸發 } ``` 4. **返回的值事實體類時**,也會觸發拷貝函數 ```cpp= // 概念程式 Car myFunc() { // 觸發 return Car(); } Car& myFuncRef() { // 引用不會觸發 return & car; } ``` ### 重寫複製函數 - 深層拷貝 * **重寫複製函數** 深層拷貝 ```cpp= /** * 重寫 複製運算子 */ stringbad::stringbad(const stringbad & s) { //"1. " this->len = s.len; this->str = new char[this->len + 1]; // + 1 for '\0' std::strcpy(this->str, s.str); std::cout << ++objCount << "------call copy construct" << std::endl; } /** * 客戶端 使用 */ #include "stringbad.h" using std::cout; using std::endl; void callMethod_Val(stringbad s); int main() { stringbad st1("Hey, it's Show time"); cout << st1 << ", addr: " << &st1 << "\n"; stringbad st2 = st1; cout << st2 << ", addr: " << &st2 << "\n"; cout << "-----分隔線-----" << "\n\n"; callMethod_Val(st1); cout << "-----分隔線-----" << "\n\n"; return 0; } void callMethod_Val(stringbad s) { cout << "In Value:" << s << endl; } ``` * 這裡的重點在 1. **動態創建 棧 空間,並儲存 棧 的指標** (淺拷貝只會拷貝相同的地址) 2. **`std::strcpy` 複製內容** > 成功複製所有自串內容,並且 obj 數量也正確 > > ![](https://i.imgur.com/NnLoNSj.png) ### 指定運算子 - 顯式深層拷貝 :::info 指定運算子 就是 `=` (等號) ::: * 使用 指定運算子 除了是顯式,它也 **==避免暫時物件的產生 & 刪除==**;要 **==重載等號必須是函數成員==,[= (等號) 不能用 friend 加載](https://hackmd.io/Roh5BF4MRN2YPgmZZ7c3Sw?view#多載限制-operator)** > **物件 ++初始化++ 時不一定會使用到指定運算子** ```cpp= stringbad s = s1; // 使用複製建構函數 ``` :::warning * `operator=` 加載的實作要注意三點 1. 避免不要加載自己,==**比對指標,不是物件!**== 2. 釋放原來申請 堆 的動態空間 3. **返回 reference**,方便於++串接指定++ ::: ```cpp= /** * 宣告 */ #include <iostream> class stringbad { private: static int objCount; char *str; int len; public: stringbad(); stringbad(const char *str); stringbad(const stringbad & s); // 複製函數 ~stringbad(); // 重載 = const stringbad & operator=(const stringbad &s); // operator << friend std::ostream & operator<<(std::ostream & o, const stringbad & s); }; // -------------------------------------------------------------------------- /** * 實作 */ const stringbad & stringbad::operator =(const stringbad & s) { cout << "operator =, new address: " << &s << ", this address: " << this; if(&s == this) { return *this; // 相同物件則忽略 } delete[] this->str; // 刪除原本申請的空間 this->len = s.len; this->str = new char(this->len + 1); // 創建新空間 strcpy(this->str, s.str); // 複製新數據 return *this; // 返回對象 } /** * 客戶端使用 */ void overrideOperator() { stringbad st1; // 呼叫預設建構函數 st1 = "1111111"; // 呼叫指定建構函數 (轉換函數) cout << st1 << ", addr: " << &st1 << "\n"; cout << "-----分隔線-----" << "\n\n"; } ``` * 這分為三個部分 (並且依照順序) 1. 使用單一引數的建構函數,可以做為 [**轉換函數**](https://hackmd.io/Roh5BF4MRN2YPgmZZ7c3Sw?view#類別型態建構-amp-單一引數-amp-轉換函數),自動找尋符合的建構函數 2. 轉換函數找到對應的建構函數後,建構出暫時對象,再使用 `operator=` 重載指定運算子 3. 刪除暫時物件 ("11111" 創建出的暫時物件) * **結論 : ==如果沒重寫 operator= 的話,++轉換函數++ 創建出來的對象 就不會使用複製建構函數==,導致沒辦法深度拷貝** **--實作--** > ![](https://i.imgur.com/Mh2tyAy.png) ### 類別成員拷貝 * 若類別成員有其他類別 A,當你複製參數時,要**選擇 A 的 ++拷貝建構子++,這在類別繼承會說到** ```cpp= /** * 宣告 */ class stringbad { private: static int objCount; char *str; int len; // 新增 string 元素 std::string str2; public: stringbad(); stringbad(const char *str); stringbad(const string str2); stringbad(const stringbad & s); // 複製建構函數 ~stringbad(); const stringbad & operator=(const stringbad &s); // operator << friend std::ostream & operator<<(std::ostream & o, const stringbad & s); }; /** * 定義 */ stringbad::stringbad(const std::string str2) { this->str2 = str2; len = this->str2.length(); str = 0; } stringbad::stringbad(const stringbad & s) { std::cout << "重載 copy construct" << std::endl; this->len = s.len; this->str = new char[this->len + 1]; // + 1 for '\0' std::strcpy(this->str, s.str); // string 並沒有自己複製該物件,必須顯是呼叫複製建構函數 ! this->str2 = s.str2; std::cout << ++objCount << "------call copy construct" << std::endl; } std::ostream & operator<<(std::ostream & o, const stringbad & s) { //o << s.str; o << s.str2; return o; } /** * 使用 */ #include "stringbad.h" using std::cout; using std::endl; int main() { std::string str("Hey Boy~"); cout << "string: "<< str << endl; stringbad strbad_1(str); cout << "strbad_1: "<< strbad_1 << endl; stringbad strbad_2 = strbad_1; cout << "strbad_2: "<< strbad_2 << endl; return 0; } ``` **--實做--** > 可以看到 console 就沒有辦法輸出 strbad_2 的值,因為物件沒有拷貝成功 > ![reference link](https://i.imgur.com/4BvayuC.png) ## 回傳物件 > 回傳物件有分為 4 種,要看狀況而使用 1. `const object&` 2. `object&` 3. `object` 4. `const object` ### 回傳 const 物件的 reference * 回傳 const reference 大部分的**理由是考慮到效率,避免物件的複製**,**==回傳一個物件會呼叫到++複製建構函數++==,而回傳一個 ref 就不會** ```cpp= #include "stringbad.h" using std::cout; using std::endl; const stringbad & callMethod_Ref(const stringbad & s); const stringbad callMethod_Val(const stringbad & s); int main() { stringbad str("123 站著穿"); cout << callMethod_Ref(str) << endl; cout << callMethod_Val(str) << endl; return 0; } const stringbad & callMethod_Ref(const stringbad & s) { cout << "In Reference:" << s << endl; return s; } const stringbad callMethod_Val(const stringbad & s) { cout << "In Value:" << s << endl; return s; 回傳物件,會呼叫複製建構函數產生暫時物件 ! 導致效率下降 } ``` **--實作--** > ![](https://i.imgur.com/shLJIh3.png) ### 回傳非 const 物件的 reference * 回傳 ref 主要是**看有沒有這個需要**;可拿 cout 為例子,**cout 使用 << 運算子就必須回傳 ostream ref** (因為可能會修改內容) ```cpp= // ostream 成員函數 operator<< friend const ostream & operator<<(ostream &, const char *); ``` * 如果是需要改動到 ref 就需要使用這種方式 ```cpp= int main() { stringbad s1("123 站著穿"); stringbad s2, s3; s3 = s2 = s1; cout << "s1: " << s1 << endl; cout << "s2: " << s2 << endl; cout << "s3: " << s3 << endl; return 0; } ``` **--實作--** > ![](https://i.imgur.com/VrSguGi.png) ### 回傳 object * **一般來說多載運算子 ==operator 屬於這種範疇==** * 若回傳物件屬於區域變數時,就必須使用回傳物件,因為當**函數結束時該物件就會被釋放**,**==++區域變數回傳++不會使用 copy construct==** ```cpp= stringbad getString() { stringbad s1("123 站著穿"); return s1; // no call copy construct } int main() { stringbad s2 = getString(); stringbad s3 = s2; // call copy construct cout << "s2: " << s2 << endl; cout << "s3: " << s3 << endl; return 0; } ``` ### 回傳 const object * 防止 operator 的特性被濫用 ```cpp= net = f1 + f2; //"1. " f1 + f2 = net; // 濫用 "2. " ``` 1. `f1.operator+(f2)`,並返回新物件,賦予給 net 2. **`f1.operator+(f2)` 後產生暫時物件,再由 `暫時物件.operator=(net)`** * 如果使用 const 修飾回傳物件,代表回傳物件不可被更改,就可防止濫用的情況,上面的例子來說就是 f1.operator+(f2) 產生的暫時物件 ## Appendix & FAQ :::info ::: ###### tags: `C++`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully