Path: utzoo!utgpu!news-server.csri.toronto.edu!rutgers!tut.cis.ohio-state.edu!zaphod.mps.ohio-state.edu!sol.ctr.columbia.edu!ira.uka.de!fuchs From: fuchs@it.uka.de (Harald Fuchs) Newsgroups: comp.lang.c++ Subject: Re: friend operator +(l,r) vs. operator +(r) Message-ID: Date: 24 Nov 90 19:12:23 GMT References: <11759@hubcap.clemson.edu> <1939@m1.cs.man.ac.uk> Sender: news@ira.uka.de (USENET News System) Organization: University of Karlsruhe, FRG Lines: 100 jk@cs.man.ac.uk (John Kewley ICL) writes: >In article <11759@hubcap.clemson.edu> grimlok@hubcap.clemson.edu (Mike Percy) writes: >>I've tried and tried to get a handle on this question from various >>sources, but haven't been enlightened... >> >>What semantic/operational and/or stylistic differences are there >>between these two definitions? >> >>class foo { >>... >>public: >> foo& operator +(foo& rhs); >>} >> >>and >> >>class foo { >>... >>public: >> friend foo& operator +(foo& lhs, foo&rhs); >>} >> >>I must be missing something, because to me these effectively are the >>same thing, but the first can operate on this. >Implicit type coersions are not permitted on the LHS of the non-friend version. >e.g. 1 + x is not allowed for the member but would be valid for the friend, >assuming a coersion from int -> foo. Yes, that's the main difference between the two. >A friend can also be used for a function to operate on two objects of >different classes. It would be declared as friend within each class. No. A member function of one class can be a friend of another one. >If the function + is defined in C (or another language), the friend version >would be neccessary. ... unless your C compiler doesn't grok a function named 'operator+' :-) >In the non-operator case, friends have a different syntax (less object-oriented) >so functions such as print can be called as print(foobar) rather than >foobar.print(). "Less object-oriented"? That's debatable. It's just another syntax, and many object-oriented languages do use that syntax (passing 'this' as the first argument of a member function). At least you have the main benefits of C++ OO'ness in both versions: - Locality of information: by reading the class definition, you see what (member or friend) fucntions are allowed to access the private members. - No namespace pollution: there are already several operator+ versions hanging around, so it doesn't matter if you add another one by a friend declaration. >All this being said it is often unclear whether to declare a function as a >friend or a member. Where there is no over-riding need I prefer members. I think it's good style to use member notation if the first argument is changed, e.g. foo& foo::operator+= (const foo&) unless you must use the friend version because the class comes from a library, e.g ostream& operator<< (ostream&, const foo&) and to use the friend version if you create a new object, e.g. foo operator+ (const foo&, const foo&) Note the use of '&': operator+= returns just a reference to *this, while operator+ creates a new object, presumably not related to its first argument. Not also the use of 'const': I could have said something like foo operator+ (foo, foo) but if your foo is large it's more efficient to pass it by reference, and const tells us that operator+ really doesn't want to change its arguments as it could have done if you omit the 'const'. I _never_ use foo& operator+ (const foo&, const foo&) (returning a reference) because this can lead to dangling references. The returned value can't refer to an object on the stack because the stack is popped when returning from operator+. It cannot refer to a local static variable inside operator+ because in this case something like foo f1 = f2 + f3 + f4; would give the wrong result. It _could_ refer to an object on heap (allocated via 'new'), but this might lead to a memory leak: when should you delete this object? The returning of a value rather than a reference might be less efficient because it calls the copy constructor foo::foo (const foo&) but a good compiler could be able to optimize it away (unless there are side effects), and I think if the copy constructor (and the assignment operator) are performance bottlenecks one should rewrite the class anyway (using counted pointers or something like that). -- Harald Fuchs ... *gulp*