From: Jerry Coffin on 8 Dec 2009 18:41 In article <7bSdnQj0_PPCZYHWnZ2dnUVZ8gCdnZ2d(a)bt.com>, francis.glassborow(a)btinternet.com says... [ ... ] > No, the real reason for friends is efficiency. It allows a function to > cut corners and directly access an instances data rather than go through > access functions. I would say rather the reverse: it allows the designer of a class to give public access only to what should really be public. Just for example, consider an overloaded operator<<, that's supposed to do output to a stream. It can't be a member function, because the left operand is going to be the stream, not the item being inserted in the stream. If we don't make the operator<< a friend of the class, then nearly our only alternative is to give (at least indirect) access to the object's externals to the whole world. Clearly giving that access only to the operator<< is drastically superior. While it's (theoretically) possible for this to have some effect on run-time efficiency as well, it's 1) fairly unlikely to happen at all, and 2) likely to be extremely trivial on the rare occasion that it does happen. > A friend function is essentially part of the classes > interface and will need modification any time that the class designer > elects to change the data representation. > > In general, inexperienced programmers would be well advised to keep > clear of friend functions until they understand when they are desirable > and hence worth paying the maintenance cost. In most cases, there is no maintenance cost. Despite the fact that syntactically it's a free function, the friend is logically part of the class itself. The fact that the function you have to modify to account for changes to the internals of the class doesn't have "classname::" at the beginning of its name adds nothing to the difficulty of the modification. [ ... ] > It would be very rare that this was the case. Mostly the class > public access functions will be sufficient. Only when performance > issues become a major issue should you revisit the use of friend > versus public access functions. Quite the contrary: most of the time that you have to do such a thing, you should use the friend function, and _eliminate_ the public access functions. The world at large should not normally have access to the object's internals, even via access functions. -- Later, Jerry.
From: Francis Glassborow on 8 Dec 2009 19:17 Jerry Coffin wrote: > In article <7bSdnQj0_PPCZYHWnZ2dnUVZ8gCdnZ2d(a)bt.com>, > francis.glassborow(a)btinternet.com says... > > [ ... ] > >> No, the real reason for friends is efficiency. It allows a function to >> cut corners and directly access an instances data rather than go through >> access functions. > > I would say rather the reverse: it allows the designer of a class to > give public access only to what should really be public. Just for > example, consider an overloaded operator<<, that's supposed to do > output to a stream. It can't be a member function, because the left > operand is going to be the stream, not the item being inserted in the > stream. > > If we don't make the operator<< a friend of the class, then nearly > our only alternative is to give (at least indirect) access to the > object's externals to the whole world. Clearly giving that access > only to the operator<< is drastically superior. > class xyz { public: void write(ostream &)const; // rest of class definition }; inline ostream & operator << (ostream & out; xyz const & inst){ inst.write(out); return out; } Note that I can make write() a virtual function (and that, for me, is the most significant reason for avoiding friends). I can also write: template<class T> inline ostream & operator << (ostream & out; T const & inst){ inst.write(out); return out; } And that will work for every class that I provide a write function for. No friend required. In addition access functions do not necessarily give direct access to the data, only to the external concept. I can rewrite the internals to my hearts content and never have to touch the external functions. If I take the friend route I have to re-implement every friend function when I change the internals of my class. friend is much over-rated and frequently over-used.
From: Kaz Kylheku on 8 Dec 2009 21:02 On 2009-12-09, Francis Glassborow <francis.glassborow(a)btinternet.com> wrote: > Jerry Coffin wrote: >> In article <7bSdnQj0_PPCZYHWnZ2dnUVZ8gCdnZ2d(a)bt.com>, >> francis.glassborow(a)btinternet.com says... >> >> [ ... ] >> >>> No, the real reason for friends is efficiency. It allows a function to >>> cut corners and directly access an instances data rather than go through >>> access functions. >> >> I would say rather the reverse: it allows the designer of a class to >> give public access only to what should really be public. Just for >> example, consider an overloaded operator<<, that's supposed to do >> output to a stream. It can't be a member function, because the left >> operand is going to be the stream, not the item being inserted in the >> stream. >> >> If we don't make the operator<< a friend of the class, then nearly >> our only alternative is to give (at least indirect) access to the >> object's externals to the whole world. Clearly giving that access >> only to the operator<< is drastically superior. >> > > class xyz { > public: > void write(ostream &)const; > // rest of class definition > }; > > inline ostream & operator << (ostream & out; xyz const & inst){ > inst.write(out); > return out; > } Goofball, With this, you are not at all making the effective counterexample to Jerry's informative posting that you /think/ you are. You were not able to write the << operator as a non-friend, non-member function, such that /it/ actually does all the work. That part of your operator << which actually does the operation had to be moved into the body of a new function, namely xyz::write, which /is/ a privileged member of the class. So your point reduces to ``Every overloaded operator can be a trivial non-member, non-friend inline function wrapper which calls some other function (that /is/ itself a friend or member function). Therefore, an overloaded operator never has to be a friend. Q. E. D. Worship my stunning C++ brilliance!''
From: Jerry Coffin on 10 Dec 2009 13:28 In article <mMadnZncP8l9cYPWnZ2dnUVZ8qmdnZ2d(a)bt.com>, francis.glassborow(a)btinternet.com says... [ ... ] > class xyz { > public: > void write(ostream &)const; > // rest of class definition > }; > > inline ostream & operator << (ostream & out; xyz const & inst){ > inst.write(out); > return out; > } Ideally, a class interface should be minimal, yet complete -- this is clearly redundant. It's perfectly fine to have a write member function -- but the user should only see operator<<, so the correct formulation is: class xyz { // protected:? void write(ostream &) const; public: friend ostream &operator<<(ostream &, xyz const &); }; > Note that I can make write() a virtual function (and that, for me, is > the most significant reason for avoiding friends). It's not a reason to avoid using a friend at all. Quite the contrary, as Herb Sutter argued years ago[1], there are actually pretty good reasons for virtual functions to be private or protected. Most people consider this more or less a solution in search of a real problem -- and I _tend_ to agree. The usual argument against it is simply the multiplication of functions, with what's usually seen as minimal or nonexistent benefit. Nonetheless, in this case we can do the right thing with no extra effort. We're going to have a virtual function and a non-member, non- virtual "front end" anyway -- so making the virtual function private or improves the interface in two completely separate ways. There is no benefit to 'write()' being public. [1] http://www.gotw.ca/publications/mill18.htm I can also write: > template<class T> > inline ostream & operator << (ostream & out; T const & inst){ > inst.write(out); > return out; > } > > And that will work for every class that I provide a write function for. > No friend required. It requires no friend, but it still exposes a redundant 'write()' function as part of the interface. > In addition access functions do not necessarily give direct access to > the data, only to the external concept. I can rewrite the internals to > my hearts content and never have to touch the external functions. If I > take the friend route I have to re-implement every friend function when > I change the internals of my class. This is, of course, utterly false. Making 'write()' a private member function causes _no_ change in 'operator<<' at all, neither when it is written nor when the implementation of 'write()' is changed. > friend is much over-rated and frequently over-used. Public member functions, _especially_ virtual public member functions, are much more so. -- Later, Jerry.
From: Alf P. Steinbach on 10 Dec 2009 17:42 * Jerry Coffin: > as Herb Sutter argued years ago[1], there are actually pretty good > reasons for virtual functions to be private or protected. It's just stupid to have virtual functions private except in some very special cases. You loose the ability to assert that you're overriding something existing. And you introduce a bug-vector or at least a dang-again-vector, since whatever's introduced up in some base class, even though not accessible to you, can be inadvertently overridden by you. I remember that Herb argued something silly (handwaving a lot) about it. It was on a par with and was essentially the same story as his use of std::auto_ptr for PIMPL idiom; he corrected neither. Cheers & hth., - Alf
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 Prev: Multiplying a complex number by a constant? Next: operator[] in a std::vector like class |