Re: [問題] 運算子多載一問

作者: Feis (永遠睡不著 @@)   2018-06-17 21:44:39
※ 引述《d630200x (DOGE)》之銘言:
: 在一般運算子多載中的宣告為下
: 傳回型別 operator運算子符號(.....)
: 然而看到比如要多載++前置或者是右移運算子>>時
: 宣告會變成
: 傳回型別& operator運算子符號(.....)
: 個人不太能理解這個&的意義,翻來翻去也沒有找到解答
首先先確定知道回傳的資料型別為 T& 時,& 表示其回傳的是 reference (參考)
因此其回傳的應為其中一個運算元的本尊,而非暫時物件,不然就會無中生有
下去的問題就變成什麼時候要傳本尊,什麼時候要產生暫時物件
這個跟我們期望這個運算子怎麼作用有關
以 a + b 的結果來說,回傳 a 本尊或 b 本尊都極其不合理.
因為這不只意味著 a + b 計算完之後其結果會存在 a 或 b 上,
也意味著 a + b = 3 這寫法是合法的 (你可以試著寫寫看)
你應該不會期望做完 a + b = 3 之後,是 a 或 b 其中一個會變成 3 吧
可以想成如果每次都回傳一個暫時物件表示計算結果是最簡單的,T& 反而麻煩
但是這樣會遇到一些困難:
1. 語意問題
int a = 3;
int b = 0;
int &c = b = a;
如果我們要讓這語法合法的話,b = a 的計算結果,也就是 operator= 必須回傳 b 本尊
這造就了基本上所有賦值運算都必須要回傳 T&
相對的,因為 ++b 也是種賦值運算
int &c = ++b;
要合法的前提也是 operator++ (pre-) 需要回傳 T&
operator++ (post-) 反而是例外,因為其回傳值與本尊的值就不一樣
int &c = b++; // 這邊的 c 參考的會是 +1 之前的 b,要嘛語意不合理,要嘛無中生有
2. 連鎖呼叫時的複製問題
當你有一種類別物件支援某種可以連鎖呼叫的運算子時,可能會在複製的時候發生問題
例如 cout << a << b << c << d << e;
在語意上是希望達到
cout << a; cout << b; cout << c; cout << d; cout << e;
的效果
這就必須讓 operator<< 的回傳值與其中一個運算元 (cout) 相同
於是我們一方面可能需要回傳時每次都複製一次 cout 造成效率問題,
另一方面也許 cout 根本就因為運作特性不能複製.
或者你根本期望他套用在同一個物件上
因此選擇回傳其中一個運算元 (cout) 的本尊 (reference, T&) 是最適當的方式
就結論來說,C++ 並沒有嚴格要求你是不是要回傳 reference
運算子多載重要的是讓使用者直覺的操作,不要做出不預期的運算
在考量使用者可能的使用情境後,選擇最適當的設計
作者: sarafciel (Cattuz)   2018-06-17 22:17:00
推一個 清楚明瞭
作者: dannypsnl (秦書)   2018-06-17 23:38:00
推,很清晰的說明
作者: handsome616 (豆花伯爵)   2018-06-20 00:00:00
https://ideone.com/Ipymxh為什麼24行可以直接給值,是怎麼運作的…有人可以解惑嗎,謝謝
作者: jerryh001   2018-06-20 00:35:00
*ptr是int 所以可以給 ptr是指標 不能直接給
作者: handsome616 (豆花伯爵)   2018-06-20 10:59:00
可是第18行不是只回傳一個數值回來嗎
作者: sarafciel (Cattuz)   2018-06-20 11:16:00
int operator *() { return *ptr; }<=這才是回傳數值int & operator *() {...}<=這是傳reference而reference這東西實際上是const pointer你單看大括號內的return *ptr可能有誤解實際上往外傳的時候對*ptr又做了一次取址只是這些部分被reference的operator藏起來了而已
作者: handsome616 (豆花伯爵)   2018-06-20 12:54:00
太感謝你!!

Links booklink

Contact Us: admin [ a t ] ucptt.com