[分享] c++ member function 和 non-member function

看板C_and_CPP (C/C++)作者 (human)時間14年前 (2011/11/16 15:54), 編輯推噓8(8038)
留言46則, 6人參與, 最新討論串1/2 (看更多)
最近看書提到運算子何時該是member function或non-member function. 因此整理一下給大家參考,也希望大家指導錯誤的地方 1.member function 和 non-member function的差異 A.non-member function 都是定義在class外面, 也被稱為global function. member function其實也有放在class的外面的機會, 通常會放在實作檔這邊,但是必須註明class的名稱. 反之non-member function不用在函式前面註明class的名字. 例如: test.h class myarray { int myfunction(int a, int b); } test.cpp //member function int myarray::myfunction(int a, int b) { ... } //non-member function int myfunction(int a, int b) B.兩者在main函式呼叫的方法不同 例如: int main() { int i; myarray a; //declare a myarray object i=myfunction(3,2); //non-member function i=a.myfunction(3,2); //member function } 2.理解兩者在運算子上的使用差異 以下面所舉二元運算子為例, <lhs> <op> <rhs> A.如果是member function來 overload, 左邊的 operand 一定是所屬的物件, 右邊的 operand 就是傳進來的參數, 編譯器實際上呼叫方式是lhs.operator<op>(rhs) B.如果是non-member function來overload, 要註明左邊跟右邊的運算元類型. 它的寫法是T operator<op>(T1 lhs, T2 rhs), T是傳回的類型,可以跟參數類型一樣. 編譯器實際上呼叫方式是operator<op>(lhs, rhs) 3.使用準則(用來決定運算子該是member function或non-member function) A.一元運算子是members B.= [] ()和->必須是members C.assignment版的運算子(+=,-+等)必須是members D.其他所有二元運算子都應該是nonmembers 參考資料 1.http://www.cs.uregina.ca/Links/class-info/210/Overloading/membervsregular.html 2.http://www.programmer-club.com.tw/ShowSameTitleN/c/31905.html 3.Exceptional C++ 國際中文版: 47個工程難題`編程疑問`及其解決方法/Herb Sutter原著;侯捷 譯 -台北市:普林帝斯霍爾,2000[民89] -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.220.204.217

11/16 16:13, , 1F
我對3-D有疑惑, 可以請問"應該"的理由嗎?
11/16 16:13, 1F
ex: 當operator +為member function時 Object obj; double x; double y; x=obj+y;->x=obj.operator+(y)//這是ok 但是x=y+obj;->x=y.operator+(obj);//這是無法辦到的 上一行的結果是不自然的, 你不能要求使用者永遠只能用x=obj+y;去撰寫程式. 實際上作者也知道implict的問題,因此它用多載來解決. 至於shadow0326遲遲無法完全接這理由, 還有一個原因.我沒有拿<<和>>當例子.(><因為我無法理解書中的解釋,只能請其他人舉例) ps: 拍謝,引用tropical72為例子

11/16 16:37, , 2F
因為 members => 看得到 private => 高耦合吧
11/16 16:37, 2F

11/16 16:51, , 3F
Object obj;double x,y; x=obj+y; x=obj.operator+(y)
11/16 16:51, 3F

11/16 16:51, , 4F
此使 memmber 即可, 考慮 x=y+obj;
11/16 16:51, 4F

11/16 16:51, , 5F
( x=y.operator+(obj); 錯誤), 需用 global overload
11/16 16:51, 5F

11/16 16:51, , 6F
為考量x=y+obj/x=obj+y 均可正常執行,故建議用
11/16 16:51, 6F

11/16 16:51, , 7F
global overload operator.
11/16 16:51, 7F

11/16 16:54, , 8F
想問一下,private data就只好用friend解嗎?這樣會比較好?
11/16 16:54, 8F

11/16 17:10, , 9F
試想一下如果 class string 要支援 strlen() 的話怎做?
11/16 17:10, 9F

11/16 17:11, , 10F
別把 friend 視作會破壞oo,擅用它會使得oo更好.
11/16 17:11, 10F

11/16 17:19, , 11F
唔, 要滿足交換率的前提應該是能掌握好implict轉換的結
11/16 17:19, 11F

11/16 17:20, , 12F
果吧, 反過來說, 如果implict轉換會造成非預期的結果,
11/16 17:20, 12F

11/16 17:20, , 13F
non-member似乎反而會造成麻煩?
11/16 17:20, 13F

11/16 17:20, , 14F
其實tropical72的解釋比我好,你問這個問題時,我還真不知
11/16 17:20, 14F

11/16 17:22, , 15F
到如何回答.基本上non-member也可以用多載來解決
11/16 17:22, 15F

11/16 17:22, , 16F
ex:operator+(const complex& lhs,const double & rhs)
11/16 17:22, 16F

11/16 17:23, , 17F
operator+(const double& lhs,const const & rhs)
11/16 17:23, 17F

11/16 17:23, , 18F
當然也可以寫兩個多載來避免implict, 不過我是覺得不一
11/16 17:23, 18F

11/16 17:23, , 19F
有必要為了滿足交換率而做到這種地步...
11/16 17:23, 19F

11/16 17:24, , 20F
更正: 不一定
11/16 17:24, 20F

11/16 17:26, , 21F
但是當你把相加的結果assign時,就必須是non-member
11/16 17:26, 21F

11/16 17:27, , 22F
結果的assign是由operator的回傳型態決定的吧?
11/16 17:27, 22F

11/16 17:28, , 23F
不對喔,你要先看看2A.它實際上是怎樣呼叫的
11/16 17:28, 23F

11/16 17:30, , 24F
它實際上是用物件(lhs)呼叫operator+.然後用rhs當參數
11/16 17:30, 24F

11/16 17:30, , 25F
那基本上還是是否滿足交換率的問題吧, 和結果的關係是?
11/16 17:30, 25F

11/16 17:34, , 26F
你可以參考tropical72的解釋.y.operator+(obj);<--
11/16 17:34, 26F

11/16 17:36, , 27F
而且2A說過了左邊的運算元一定是所屬的物件.
11/16 17:36, 27F

11/16 17:39, , 28F
回文討論吧,推文裡的東西版上都還沒有,可以討論很久.
11/16 17:39, 28F

11/16 17:42, , 29F
我覺得有點鬼打牆了 XD 我知道operator的呼叫方式, 也
11/16 17:42, 29F

11/16 17:42, , 30F
理解建議non-memeber的理由 (後者要感謝t大和a大)
11/16 17:42, 30F

11/16 17:43, , 31F
我只是想說non-member可能付出的代價(implict的問題)
11/16 17:43, 31F

11/16 17:44, , 32F
以及是否有必要為了滿足交換率特地寫兩條實作幾乎相同
11/16 17:44, 32F

11/16 17:44, , 33F
我能理解 shadow0326 考量在哪,但那問題在複載二元運算
11/16 17:44, 33F

11/16 17:45, , 34F
的overload. (當然我支持有些時候non-member真的較好)
11/16 17:45, 34F

11/16 17:45, , 35F
子時就一定要考量,甚至必要時也會提供 static_cast<T>
11/16 17:45, 35F

11/16 17:45, , 36F
之複載.
11/16 17:45, 36F

11/16 17:48, , 37F
shadow0326,我引用tropical72的例子來解釋理由,看看還有
11/16 17:48, 37F

11/16 19:28, , 38F
疑問嗎? 也希望其他人幫忙多找問題和回答
11/16 19:28, 38F
※ 編輯: angleevil 來自: 61.220.204.217 (11/17 08:25) ※ 編輯: angleevil 來自: 61.220.204.217 (11/17 11:35)

11/18 04:47, , 39F
幾乎同樣的實作?func(lhs,rhs){ func(rhs,lhs) }
11/18 04:47, 39F

11/18 04:48, , 40F
看這樣會不會好點,加個兩行滿足需求
11/18 04:48, 40F

11/18 04:52, , 41F
implict的問題是比較麻煩點,不過根據use case好像可以避開
11/18 04:52, 41F

11/18 07:14, , 42F
樓上可以講解更清楚嗎?直接給func(lhs,rhs)不知是member
11/18 07:14, 42F

11/18 07:15, , 43F
or nonmember case? 還是說用一個member function的功能
11/18 07:15, 43F

11/18 07:19, , 44F
取代operatior overloading? ><而且我不太知道use case
11/18 07:19, 44F

11/18 07:19, , 45F
的意思是什麼? 麻煩大家解惑一下
11/18 07:19, 45F

11/18 10:18, , 46F
我想c大的意思是例如 operator + (l,r){return r+l}
11/18 10:18, 46F
文章代碼(AID): #1EmsmTYX (C_and_CPP)
文章代碼(AID): #1EmsmTYX (C_and_CPP)