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
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- title: 'Class 運用 - operator、friend、explicit' disqus: kyleAlien --- Class 運用 - operator、friend、explicit === ## OverView of Content 如有引用參考請詳註出處,感謝 :smile: [TOC] ## Refernce & 副本 * 返回使用 reference & 副本的差別在,副本是函式內創建靜態變數 (無連結),**在 ==Func 結束前會產生其副本== 讓呼叫的函式取得**,最後函式結束後釋放靜態區域變數 :::warning **使用哪個要依照需求而定,不能一味地看效率** ::: ```cpp= /** * 宣告 */ class Score { private: int score; public: Score(int score = 0); // 預設引數 const Score& Sum_Ref(Score& s) const; // Refernce 函數 const Score Sum_Cpy(const Score& s) const; // 副本 int getScore() { return score; }; }; // -------------------------------------------------------------------- /** * 實做 */ #include "TestClass.h" Score::Score(int score) { this->score = score; } const Score& Score::Sum_Ref(Score& s) const { // "1. " s.score += this->score; return s; } const Score Score::Sum_Cpy(const Score& s) const { // "2. " Score c; // default construct c.score = this->score + s.score; return c; // 返回前會呼叫 Score 複製函數 } // -------------------------------------------------------------------- /** * 客戶端使用 */ #include "TestClass.h" int main() { Score s1(30), s2(30), s3(30), s4(30); Score result_1 = s1.Sum_Ref(s2); //"3. " std::cout << "s1 score: " << s1.getScore() << ", s2 score: " << s2.getScore() << ", After Ref sum score: " << result_1.getScore() << std::endl; Score result_2 = s3.Sum_Cpy(s4); std::cout << "s3 score: " << s3.getScore() << ", s4 score: " << s4.getScore() << ", After Ref sum score: " << result_2.getScore() << std::endl; return 0; } ``` 1. `Sum_Ref` 宣告為**返回一個 Reference 物件**,並且引數為可改變的物件,==效率較高== 2. `Sum_Cpy` 宣告為返回一個物件,該物件是 **==新的物件==,其++生命週期在 Function 開始到結束++**,在**釋放記憶體前 return 物件,複製該物件內容到呼叫函數取得**,==效率較低== 3. 改變 s2 的內容,因為是傳 reference 進入不會新建物件 **--實作--** > ![](https://i.imgur.com/fWmTvzQ.png) ## operator 運算子多載 * operator 運算子多載可以讓使用起來更好看 (儘管 function name 就是 opeator 很奇怪) ;運算子函數的規格,**operator ==++op++==(argument...)**,**op 是運算符號,但++它還是一個函數++** :::warning **不能多載 C++ 沒有的運算子** ::: C++ 運算子可以有多種意義 (如同函數多載),**C++ 會依據==引數的數量== & ==型態==來決定使用哪個運算子** ```cpp= /** * 宣告 */ class Score { private: int score; public: Score(int score = 0); const Score& Sum_Ref(Score& s) const; const Score Sum_Cpy(const Score& s) const; const Score operator+(const Score& s) const; // 新增 int getScore() { return score; }; }; /** * 實作 新增 operator+,有無空白都可以 operator + 也可 */ const Score Score::operator+(const Score& s) const { //"1. " Score c; // default construct c.score = this->score + s.score; return c; } /** * 客戶端使用 */ #include "TestClass.h" int main() { Score s1(30), s2(50); Score result_1 = s1.Sum_Cpy(s2); std::cout << "After function sum score: " << result_1.getScore() << std::endl; Score result_2 = s1 + s2; //"1. " std::cout << "After + sum score: " << result_2.getScore() << std::endl; Score result_3 = s1.operator +(s2); //"2. " std::cout << "After operator+ sum score: " << result_3.getScore() << std::endl; return 0; } ``` 1. 其內部實現如同 `SumCpy`,創建一個新物件 2. 可以用 func 全名,**`operator+` 就是 func 名**,功能如同**使用 + 號**,\+ 號是 operator 的簡寫 **--實作--** > ![](https://i.imgur.com/ox2s4X9.png) ### operator 函數回傳值 - 重複使用 * 這要考慮到,**符號的==結合性==**,而 **加號的結合性為 ==左到右==**;如果上面使用 `s1 + s2 + s3` 會轉換成 1. **s1.opertor**(s2 + s3); > 由最左邊的 s1 開始轉換 operator() 2. s1.opertor(**s2.opertor**(s3)); 以此類推 > 再轉換到 s2 operator() ```cpp= #include "TestClass.h" int main() { Score s1(30), s2(50), s3(70); // 直接呼叫副本 Function Score result_1 = s1.Sum_Cpy(s2).Sum_Cpy(s3); std::cout << "After function sum score: " << result_1.getScore() << std::endl; // 使用運算符重載 Score result_2 = s1 + s2 + s3; std::cout << "After + sum score: " << result_2.getScore() << std::endl; // 呼叫運算符重載 function Score result_3 = s1.operator +(s2).operator +(s3); std::cout << "After operator+ sum score: " << result_3.getScore() << std::endl; return 0; } ``` **--實作--** > 新增 s3,並連續加法,三種方法都可以得到相同結果 > > ![](https://i.imgur.com/EF1KNRz.png) ### 多載限制 - operator 限制 1. **不能違反原始運算子的 ++語法規則++** ```cpp= int x; Score s; % x; // 原始操作 不合法 % s; // 使用 operator 複寫,但操作 不合法 ``` 2. **不能產生新的符號** > Ex: 想產生一個沒有的 `__` 符號 operator__(),這會導致編譯失敗 3. **引數至少要有一個使用者自定義型態**,這樣才不會與原始符號衝突 (也就是要有一個參數) > Ex: operator+(const Score& s) * 還有以下的符號 **不能重載 !** | 運算子 | 描述 | | ---------------- | ------------------------------ | | sizeof | 計算該類別佔多少 byte 記憶體 | | . | 成員運算子,struct、class 使用 | | .* | 成員指標 運算子 | | :: | ==範疇== 運算子 | | ?: | 三元條件 運算子 | | typeid | RTTI 運算子 | | const_cast | 轉換 const 型態 | | dynamic_cast | 轉換 dynamic 型態 | | reinterpret_cast | 轉換 reinterpret 型態 | | static_cast | 轉換 static 型態 | * 以下運算子 **++不能透過非成員函數++ 加載 (也就是 friend 函數不可加載)**,會破壞順序 | 運算子 | 描述 | | -------- | -------- | | = | 指定 運算子 | | () | 函數呼叫 運算子 | | [] | ==標註== 運算子 | | -> | 指標間接抓取 運算子 | ## friend 夥伴函數 之前有提到,**存取 private 成員資料的唯一方式是透過函數**,但還有一個方法可以提取到私有變量,就是 **使用 friend 宣告的函數,==friend 函數可取得 private 變量==** :::info 記憶:因為是好朋友,所以可以使用自身的私有物品 ::: * friend 有三種變形 1. 夥伴 **函數** 2. 夥伴 **類別** 3. 夥伴 **成員函數** * 需要 friend 的原因在於,類別多載二元運算時 (兩個引數稱二元) 產生的例外狀況 ```cpp= // 以上面的 Score 為例, 新增一個普通變數 // 原型 const Score operator+(const int i) const; // 實作 const Score Score::operator +(int i) const { Score c; // default construct c.score = this->score + i; return c; } // 客戶端 int main() { Score s1(30); Score result_1 = s1 + 10; // 一般的正常用法,但如果反過來加呢 ? 10 + s1 std::cout << "result: " << result_1.getScore() << std::endl; return 0; } ``` 該呼叫是透過 s1 的方法 `operator+()`,但是如果反向過來變成 `10 + s1`,以語意來說是正確的,但是 **10 並不是類型,它沒有 operator+()** !! ### friend 宣告 * **==friend 是非成員函數==,定義時++不使用 :: (範疇運算)++** > 非成員函數 : 不是用物件呼叫 (Call Function),它所擁有的引數都是顯示 (包括沒有 this) * 在**類別內宣告 friend 函數,該函數就可以使用 private 的成員** ```cpp= /** * 新增 10 + obj 的宣告 */ class Score { private: int score; public: Score(int score = 0); const Score& Sum_Ref(Score& s) const; const Score Sum_Cpy(const Score& s) const; const Score operator+(const Score& s) const; const Score operator+(const int i) const; // "1. " 新增 friend 非成員函數 friend const Score operator+(const int i, const Score & s); // const; int getScore() { return score; }; }; // -------------------------------------------------------------------- /** * 實現 */ // 這裡不能出現 friend 關鍵字 const Score operator +(const int i, const Score & s) { //return s.operator +(i); "Same as s + i" return s + i; //"2. " 反過來使用 Score 的 operator= 函數 } // -------------------------------------------------------------------- /** * 客戶端使用 */ #include "TestClass.h" int main() { Score s1(30); Score result_1 = s1 + 10; std::cout << "result: " << result_1.getScore() << std::endl; Score result_2 = 30 + s1; //"3. " std::cout << "result: " << result_2.getScore() << std::endl; Score result_3 = operator+(30, s1); std::cout << "result: " << result_3.getScore() << std::endl; return 0; } ``` **--實作--** > ![](https://i.imgur.com/FmVRwjD.png) 1. **宣告時需要 friend,定義時不用 firend**,**並且 ==非成員函數不可使用 [const 修飾 func](https://hackmd.io/32uk2K2ZSUKoCKYlidy-Dg?both#const-成員函數)==,因為沒有可以修飾的對象** ```cpp= // 不能用 const,因為 Score 非自身的物件 friend const Score operator+(const int i, const Score & s) const; ``` :::warning * **friend 這個關鍵字只能用 (出現) 在 class 中**,用在定義就會錯誤 (如下圖) > ![](https://i.imgur.com/BoxRNsg.png) ::: 2. 既然 `friend` 可以使用該對象的資源,代表也可以使用對象的 function,那就可以直接反向後使用 3. **`30 + s1` 等價於` operator*(30, s1)`** ### friend & OOP 關係 * ++乍看之下 friend 似乎破壞了 OOP 的資料隱藏規則++,但其實 **它應該看做類別的延伸介面**,因為 **如果沒有了 `friend` 宣告,使用者也不能使用,==`friend` 宣告即可看成介面的延伸==** * Class 宣告哪些函數可以存取 private 資料,而 `friend 函數非成員函數`、`類別函數`,**兩者是表示類別介面的兩種不同機制** ```cpp= // 類別函數、成員函數 const Score operator+(const int i) const; // 非成員函數 friend const Score operator+(const int i, const Score & s); ``` ### 多載輸出 `<<` 運算子 * `<<` 除了在 C 中的基礎位移 (向左位移);C++ 中的 `<<` 運算子還可以使用在多種基本型態,這是因為 **`<<` 運算子多載了許多基礎類型** ```cpp= // 在 Score 中多載 << 運算子,讓它自動輸出需要的資料 /* * 宣告 */ class Score { private: int score; public: Score(int score = 0); const Score& Sum_Ref(Score& s) const; const Score Sum_Cpy(const Score& s) const; const Score operator+(const Score& s) const; const Score operator+(const int i) const; // why use friend ? friend const Score operator+(const int i, const Score & s); // Write friend of new << friend std::ostream& operator<<(std::ostream &os, const Score & s); int getScore() { return score; }; }; /* * 定義 */ std::ostream& operator<<(std::ostream &os, const Score &s) { os << "score: " << s.score << " "; return os; } /* * 客戶端使用 */ #include "TestClass.h" int main() { Score s1(30); Score result_1 = s1 + 10; Score result_2 = 30 + s1; Score result_3 = operator+(80, s1); std::cout << result_1 << result_2 << result_3 << std::endl; return 0; } ``` 使用 firend 函數的原因:**不能使用類別函式,但是又必須使用 class 的成員 Score,所以使用 friend**;不用在 ostream 原因很簡單,因為不好維護,不可能因為新增一個類別就去修改 ostream 對象 > 類別函式 : 沒有人在使用 result_1 <<,所以不能使用 ### 成員函數 vs 非成員函數 | Type | 引數 | Example | | -------- | -------- | -------- | | 成員函數 | ==有隱式引數== | operator+(int i) + 隱式 this | | 非成員函數 | ==都是顯示引數== | operator+(int i, Object & o) 引數都是顯式 | * 並且不可同時定義兩個相同格式的函數,**會導致==模糊性錯誤==**,編譯期間就會錯誤 ```cpp= S1 = S2 + S3; S1 = S2.operator+(S3); // 成員函數 S1 = operator+(S2, S3); // 非-成員函數 ``` ## 類別自動轉換 & 類型轉換 * 類別的下一個主題是型態轉換,**C++ 內建型態轉換,++當一個敘述是標準型態,指定給另一個標準型態時可以自動轉換++** (**==前提兩個類型要相容==**) ```cpp= int main() { long count = 8; double time = 11; int side = 3.33; std::cout << "long : " << count << std::endl; std::cout << "double : " << time << std::endl; std::cout << "int : " << side << std::endl; int * p1 = 10; // "1. " int * p2 = (int *) 10; // "2. " std::cout << "ptr1 : " << p1 << std::endl; std::cout << "ptr2 : " << p2 << std::endl; // ptr2 : 0x0a return 0; } ``` 1. 類型不相同,無法相互轉換,`int *` **指標雖然在電腦中是使用整數儲存,但是 ==指標與整數的概念完全不一樣==** 2. 仍然有方法可以透過轉換,讓 10 (整數型態 int) 強制轉換成指標 `(int*)` **--實作--** > ![](https://i.imgur.com/UqSAmYQ.png) ### 類別型態建構 & 單一引數 & 轉換函數 * 在 C++ 中,**任何有 ++單一引數++ 的 construct,就像是==將該引數值,轉換成++類別型態++==**,該 **++單一引數的建構函數++ 就可作為 ==轉換函數==** :::info 透過**類別型態找尋建構函數,建構出物件的過程稱為 ==自動轉換==** ::: ```cpp= // 以下範例使用 石 & 磅 的轉換 /** * class 宣告 */ #include "iostream" class stonewt { private: static const int Lbs_per_stn = 14; // 石 : 磅 = 1 : 14 int t_value = 0;// test 值是否被複製 int stone; double p_lbs; // point lbs double t_lbs; // total lbs public: stonewt(); stonewt(double lbs); // 磅 //"4. " stonewt(int stone, double lbs); // 石 + 磅 ~stonewt(); void Set_Value(int v); void Show_Value(); void Show_Lbs(); void Show_Stone(); }; // ----------------------------------------------------------------- /** * 定義 */ #include "stonewt.h" stonewt::stonewt() { std::cout << "construct...empty" << std::endl; stone = t_lbs = p_lbs = 0; } stonewt::stonewt(double lbs) { std::cout << "construct...lbs" << std::endl; this->stone = int(lbs) / Lbs_per_stn; // 石 整數 this->p_lbs = (int(lbs) & Lbs_per_stn) + (lbs - int(lbs)); // 磅 小數 this->t_lbs = lbs; // 全部磅數 } stonewt::stonewt(int stone, double lbs) { std::cout << "construct...stone & lbs" << std::endl; this->stone = stone; this->p_lbs = lbs; this->t_lbs = stone * Lbs_per_stn + lbs; } stonewt::~stonewt() { std::cout << "...destruct, address: " << this << std::endl; } void stonewt::Show_Lbs() { std::cout << "total lbs: " << t_lbs << std::endl; } void stonewt::Show_Stone() { std::cout << "total stone: " << stone << "." << p_lbs << std::endl; } void stonewt::Set_Value(int v) { t_value = v; } void stonewt::Show_Value() { std::cout << "value: " << t_value << std::endl; } // ----------------------------------------------------------------- /** * 客戶端使用 */ #include "./typeChange/stonewt.h" int main() { stonewt s; // "1. " s.Set_Value(100); s.Show_Value(); std::cout << "原來物件地址: " << &s << std::endl; std::cout << "\n使用 \"=\" 指定" << std::endl; s = 19.6; // "2. " 19.6 會創建 暫時物件! s.Show_Value(); // "3." return 0; } ``` 1. 使用 default 建構函數創建 (無引數 construct) 2. 當在使用 **==等號==賦予值,就會==再次創建一次暫時物件==,並使用 double 引數的創建函數,並使用 19.6 作為初始值,該物件只是暫時的** > 暫時物件在賦予後立刻會銷毀 3. 這是為了測試,**證明++暫時物件 (19.6) 會複製到原本物件 s++,這種過程稱為==自動轉換==** > 原本賦予值得 value = 100,暫時物件初始化 value = 0,暫時物件呼叫 `stonewt(double lbs)` 建構函數,只會複製其他成員,而沒有複製 value 4. 使用 `=` 會自動判斷類別型態,呼叫對應的建構函數,而 **double 就是類別型態** **--實作結果--** > 從結果也可以看到 **暫時物件會先被銷毀** > > ![](https://i.imgur.com/RXGTeyi.png) ### explicit 顯式型態 * **explicit 可以==關閉自動轉換==**,也就是關閉自動透過型態搜尋建構函數的功能 :::warning **`explicit` 必須定義在 class 宣告中,不可用於定義中** ::: * function 傳值會產生暫時物件,它會呼叫**複製建構函數** ```cpp= #include "iostream" class stonewt { private: static const int Lbs_per_stn = 14; // 石 : 磅 = 1 : 14 int stone; double p_lbs; // point lbs double t_lbs; // total lbs public: stonewt(); explicit stonewt(double lbs); // 磅; 在宣告中使用 `explicit`,禁止自動轉換 stonewt(int stone, double lbs); // 石 + 磅 ~stonewt(); void Show_Lbs() const; void Show_Stone() const; }; ``` > ![](https://i.imgur.com/Ngti9wK.png) ### 函數 - 暫時物件 * **暫時物件是==隱式轉換的一個中間產物==**,在 function 中同樣可以使用 ```cpp= class stonewt { ... public: ... void Show_Stone() const; // 新增 } void stonewt::Show_Stone() const { std::cout << "total stone: " << stone << "." << p_lbs << std::endl; } // --------------------------------------------------------------------- /** * 使用者 */ #include "./typeChange/stonewt.h" using std::cout; using std::endl; void display_1(const stonewt &s); void display_2(const stonewt s); int main() { cout << "\n display_1 只使用引數傳入" << endl; display_1(422.3); //"1. " cout << "\n display_2 只使用引數傳入" << endl; display_2(422.3); return 0; } void display_1(const stonewt &s) { //"2. " s.Show_Stone(); } void display_2(const stonewt s) { s.Show_Stone(); } ``` 1. `display_1` & `display_2` 的第一個引數是 stonewt 物件,遇到 **double 的引數傳入時編譯器會 ==++自動尋找++配對的上的建構函數==**,並呼叫對應的建構函數 (如上一個小節所說) 2. 接收 reference,使用原物件 (以目前來講就是使用 `暫時物件` 的引用) > ![](https://i.imgur.com/l0Z41AU.png) ### 反轉函數 - conversion function * 一般來說我們會把數值轉換為物件,但相同 **的物件也可以反轉為另一個使用者需要的值**;**C++ 的運算子函數格式稱為 ==反轉函數==** ```cpp= stonewt s1(275.3); // 一般使用,將 275.3 轉換為 stonewt 物件 double d = s1; // 反轉 ``` * 函數格式 : **==operator <類型>()==;++<類型> 代表了轉換的目標型態++**,並且轉換函數遵循以下條件 1. 必須是 **類別成員** 2. 不能指定回傳值 (有一定的格式) 3. 不能有引數 ```cpp= #include <iostream> //using namespace std; using std::cout; using std::endl; class MyClass { private: int studentCount; public: MyClass(int count = 0); ~MyClass(); // 反轉函數 operator int(); operator std::string(); }; MyClass::MyClass(int count) : studentCount(count) { cout << "MyClass construct." << endl; } MyClass::operator int() { return studentCount; } MyClass::operator std::string() { return std::to_string(studentCount); } MyClass::~MyClass() { cout << "MyClass deconstruct." << endl; } int main() { MyClass clz = 10; int val = clz; // 呼叫反轉函數 cout << "convert int: " << val << endl; std::string valStr = clz; // 呼叫反轉函數 cout << "convert string: " << valStr << endl; return 0; } ``` > ![](https://i.imgur.com/XK5ZLX4.png) * 反轉函數的使用又分為,**^1.^ ++隱性指定(implicit)++、^2.^ ++明確指定(explicit)++** * ==**隱性指定**==:**指定++反轉函數 operator int/double 類型++** ```cpp= int i1 = s1; double d1 = s1; ``` * ==**顯示指定**==:呼叫目標對象 ```cpp= int i2 = int(s1); double d2 = (double)s1; ``` ```cpp= /** * class 宣告 */ class stonewt { private: static const int Lbs_per_stn = 14; // 石 : 磅 = 1 : 14 int stone; double p_lbs; // point lbs double t_lbs; // total lbs public: stonewt(); stonewt(double lbs); // 磅 stonewt(int stone, double lbs); // 石 + 磅 ~stonewt(); stonewt(int v); void Show_Lbs() const; void Show_Stone() const; // convert func "1. " operator int() const; // const 可有可無 operator double() const; explicit operator float() const; // "3." 關閉隱式轉換 }; /** * class 定義 */ stonewt::operator int() const { return int(t_lbs + 0.5); // 四捨五入 } stonewt::operator double() const { return t_lbs; } stonewt::operator float() const { return t_lbs; } /** * 客戶端 使用 */ #include "./typeChange/stonewt.h" using std::cout; using std::endl; int main() { stonewt s1(275.3); s1.Show_Lbs(); // 隱式指定 int i1 = s1; cout << "int i1 = s1 : " << i1 << endl; double d1 = s1; cout << "double d1 = s1 : " << d1 << endl; int i2 = int(s1); cout << "int i2 = int(s1) : " << i2 << endl; double d2 = double(s1); cout << "double d2 = double(s1) : " << d2 << endl; double d3 = int(s1); cout << "double d3 = int(s1) : " << d3 << endl; float f1 = float(s1); cout << "float f1 = float(s1) : " << f1 << endl; //float f2 = s1; //"3. " can't implicit change, because use explicit return 0; } ``` 1. **反轉函數++沒有回傳值++、沒有引數,如果有使用 const function 描述會讓使用者使用的更加放心** 2. 顯式指定,由使用者規定自己需要的轉型,可規定轉型 int,但用 double 參數接收,結果會是 operator int funtion 的操作結果 3. 可以**使用 explicit 關閉隱式自動轉換** **--實做--** > ![](https://i.imgur.com/zhOfCGC.png) ### 成員函數 & friend 夥伴函數 * `成員函數`、`friend` 兩種方法都可重新定義符號操作 ```cpp= /** * 宣告 */ class stonewt { private: ... public: ... //member const stonewt operator+(const stonewt& s) const; // friend friend const stonewt operator+(const stonewt& s, const stonewt& s2); // 非成員函數不可使用 const }; /** * 定義新增 */ // member const stonewt stonewt::operator+(const stonewt& s) const { std::cout<< "member..." << std::endl; stonewt newS = s.t_lbs + this->t_lbs; return newS; } // friend const stonewt operator+(const stonewt& s1, const stonewt& s2) { std::cout<< "friend..." << std::endl; stonewt newS = s1.t_lbs + s2.t_lbs; return newS; } ``` * 上面定義兩個相同功能的函數,**==功能相同導致 candidate (候選) 發生==**,**會產生++混淆錯亂++** > ![](https://i.imgur.com/QCAkgt8.png) ## Appendix & FAQ :::info ::: ###### tags: `C++` `friend & operator` `explicit`

    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