看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《wtchen (沒有存在感的人)》之銘言: : 問題(Question): : 目前正在寫一個可以進行加減乘除的大數class。 : 有一個關於operator overloading的問題: : 據我所知可以使用method(寫在class裏面)或function(class外面) : 請問一般情況下使用method還是function好呢? : 我想要overload的operator包括 : +, -, *, /, +=, -/, *=, /=, % : 目前我唯二知道需要用function解決的有兩種情況: : - operator 作用於 class 跟另一種 class : ex: Complex a; double b; Complex c = a * b; : - 需要用到cout << : ex: Complex a(1,1); cout << a << endl; : 謝謝。 就 C++ 而言,在成員或非成員函式取捨時我的想法大概是這樣的順序: 1. 語法限制: 有些情況下你根本沒得選 情況一: operator=, operator[], operator() 和 operator-> 在標準規定是不能用 非成員函式多載。此時只能用成員函式。 情況二: 當你為二元運算子時,如果左運算元的類別定義無法更改。例如你提到 cout << a; 。此時只能用非成員函式。 情況三: 當你為一元運算子時,如果運算元為 enum 型態,此時只能用非成員函式。 2. 安全考量: 避免隱性轉型。 情況: 當你為二元運算子時,如果左運算元為內建型態或 enum,則優先使用非成員 函式。 3. 封裝考量: 一般非成員函式的優點在於保證其無法存取私有成員。所以從封裝來看, 如果可以的話,非成員函式應該優先。 問題發生在當我們需要存取私有成員時會有兩個選擇: 一個是使用成員函 式,另一個則是使用 friend 的非成員函式。 情況一: 如果是一元運算子,或者是二元運算子但是兩個運算元的類別相 同時,我傾向用成員函式。主要是因為從屬性蠻明確的。 情況二: 如果是二元運算子且兩個運算元的類別不同。則此時看其兩運算 元角色是否一樣,例如其是否遵守交換律,也就是兩個運算元交 換位置是否會得到一樣的結果。如果遵守交換律我會選用非成員 函式 (加 friend),反之則通常是因為會修改到左運算元的內容 (例如 operator +=),此時我會使用成員函式。當然其他情況 就看自己覺得哪個合理 Orz. 依照我的想法,原 po 的 +, - , *, /, % 我會用非成員函式, +=, -=, *= 和 /= 會 用成員函式。不過我相信每個人看法一定有所差異。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.122.83.198 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1432481647.A.068.html
azureblaze: 就封裝而言「非成員非friend」是比較好的 05/24 23:41
azureblaze: 掛了個friend上去他的存取權就跟成員沒兩樣了 05/24 23:41
Feis: 此外原 po 也可能參考 std::complex http://goo.gl/yOCkb3 05/24 23:46
Feis: *可以參考 05/24 23:46
Feis: 發現自己少寫了一個情況. 補了一下二元運算子但類別一樣的 05/24 23:58
※ 編輯: Feis (140.122.83.198), 05/25/2015 00:27:41
wtchen: 問個問題,當二元運算子跟非同類別之物件作用時 05/25 01:41
wtchen: 例如complex a, double b, complex c = a*b 05/25 01:42
wtchen: 跟complex c = b*a結果會一樣嗎?我是說只要用非成員函式 05/25 01:43
wtchen: 就會自動遵守交換律嗎(有點搞混狀態) 05/25 01:43
LPH66: Feis 說的是語意上的交換律, 編譯器永遠當被 overload 的 05/25 01:51
LPH66: operator 是不可交換的 05/25 01:51
wtchen: 所以若我要讓交換律成立,我得寫兩個非成員函式? 05/25 02:08
wtchen: const complex operator*(double a, BigNumber& b) 05/25 02:09
wtchen: 和const complex operator*(BigNumber& b, double a) ? 05/25 02:09
wtchen: (抱歉,BigNumber是我正在寫的大數物件) 05/25 02:11
LPH66: 你要直接寫確實是這樣沒錯, 不過這裡如我前篇推文說的 05/25 04:06
LPH66: 一般來說會寫 BigNumber(double) 以及 05/25 04:08
LPH66: BigNumber operator* (const BigNumber&,const BigNumber&) 05/25 04:08
LPH66: 讓編譯器碰到這種狀況時先用前者建立暫時 BigNumber 物件 05/25 04:09
LPH66: 再使用後者進行計算, 這樣同一段程式就不用寫兩次 05/25 04:10
LPH66: 然後, operator* 一般會再使用 operator *= 來寫 05/25 04:11
LPH66: 同樣也是為了同一段程式不用寫兩次 05/25 04:11
LPH66: 這時的 operator* 會變成用傳值進來再直接 *= 後回傳 05/25 04:12