Tuesday, January 19, 2010

When to use friend functions over member methods

There are several arguments both for and against friend methods. Some of these arguments hold true in all cases and some only hold true depending on the context of programmer and his environment. Here is a summary of how I determine when to use friend functions or member methods.

1) Use member methods when it makes it much easier to see what methods are available
If you work in an organisation and you use an IDE where the member methods of each class are obvious, but the friend functions of the class are not obvious, use member functions. I've seen arguments on the web that say you should use non member friend functions to enforce encapsulation of the class and that crappy IDEs should not affect your decision. However in the commercial world where your company has invested in such and IDE, you can't afford to hide functionality from your colleagues.


2) If first arg cannot be a pointer to 'this', then a friend function will be easier to use 
For example consider operator<<

Say we have a class C which contains an int (e.g. 5) and a char (e.g. 'X') and we want to override operator<< to produce the result :5-X
int main() {
    C obj(5,'X');
    std::cout << "The value representing obj is " << obj << std::endl; // obj should be represented by 5-X

    return 0;
} 
If we define the class C with a the friend function operator<<, it should look like this:
class C { 
    friend std::ostream& operator<< (std::ostream&, const C&);
    public:
        C(int i, char c) : foo(i), bar(c)  {}; 
    private:
        int foo;
        char bar;

};
std::ostream& operator<< (std::ostream& ostr, const C& c) {
    ostr << c.foo << "-" << c.bar;
}
and the output is
The value representing obj is 5-X
Having the friend operator<< defined like this means we have the logical easy to read syntax of
std::cout << "The value representing obj is " << obj << std::endl;
We could have also used this syntax
std::cout << "The value representing obj is "; operator<<(std::cout, obj) << std::endl;
In the above, we are just more explicit in defining the arguments for operator<< Now say instead that we define operator<< as a member method:
class C {
    public:
        C(int i, char c) : foo(i), bar(c)  {};
        std::ostream& operator<< (std::ostream&);
    private:
        int foo;
        char bar;

};
std::ostream& C::operator<< (std::ostream& ostr) {
    ostr << foo << "-" << bar;
}
The only way to call this is
std::cout << "The value representing obj is "; obj.operator<<(std::cout) << std::endl;
Therefore defining operator<< to be a friend function is a much better option to using member methods. Some useful links:
http://www.faqs.org/faqs/alt.comp.lang.learn.c-c++/C++_FAQ_%28part_05_of_11%29/
read chapter [14.5] Should my class declare a member function or a friend function?


Also of interest
http://www.faqs.org/faqs/alt.comp.lang.learn.c-c++/C++_FAQ_(part_05_of_11)/#ixzz0cyteOeXg

No comments: