views:

125

answers:

3

hey, i got something that i cannot understand ,there are two types of solutions for overloading this operator 1 is including the friend at the start of the method and the other 1 goes without the friend. i would very much like if some1 explain whats the difference between them advantages / disadvantages. for example overloading the operator << in class rational:

class Rational:
{
    private: int m_t,m_b;
    ...
    friend ostream& operator<<(ostream& out,const Rational& r) // option 1
    { return out << r.m_t << "/" <<r.m_b;}  // continue of option 1

    ostream& operator<<(ostream& out,const Rational& r){return r.print();} // option 2
    virtual ostream& print(ostream& out) const // continue of option 2
    { //
      return out<<m_t << "/" << m_b;
    } //
};

i was told that the second option isnt correct , if some1 can correct me about it i would much appriciate it. thanks in advance.

+4  A: 

The short answer: Option #2 actually isn't an option, but a syntax error, because it tries to define a binary operator as a member passing two operands.

The somewhat longer answer: If you make the second operand a free function (not a member of the class), this will work. Which one is preferable depends on the circumstances and your preferences. For starters: The disadvantage of the first is that it allows operator<< to access everything in Rational (including private helper functions), while the disadvantage of the second is that you introduce a function to the class' public API that nobody needs.

sbi
is there a way to correct it so it will work ?
Nadav Stern
from what i heard about friend in c++ it got its drawbacks
Nadav Stern
and does the first option works with polymorphisem ?
Nadav Stern
@Nadav: A) I've meanwhile added how to fix the second version. B) There's no special drawback of `friend` in C++, except for the general drawback of it breaking encapsulation. But C++ has always been rather pragmatic about that. C) That's a good issue I forgot to mention: Option #2 is the only one where the class can be polymorphic, since #1 doesn't work through calling a member function, and member functions are needed for polymorphism in C++.
sbi
@Nadav: Be careful about not using a language feature because you hear it has problems. `friend` also tends to be misunderstood outside C++ circles, and lots of people erroneously claim it breaks encapsulation. In fact, it includes things outside the class in the encapsulation, which is potentially both good and bad.
David Thornley
A: 

Consider a function that should output the num and den of Rational:

ostream& operator<<(ostream& out, const Rational& r)
{
    return out;
}

Unfortunately, this is just a global function. Like any other global function, it cannot access the private members of Rational. To make it work with Rational objects, you need to make it friend of Rational:

class Rational
{
    private: int m_t,m_b;

    // ...

    friend ostream& operator<<(ostream& out, const Rational& r);
};

ostream& operator<<(ostream& out, const Rational& r)
{
    out << r.m_t << "/" <<r.m_b;
    return out;
}

The friend ostream& operator<<(ostream& out, const Rational& r); inside Rational class indicates that ostream& operator<<(ostream& out, const Rational& r) function can directly use Rational's private members.

Now when you write:

Rational r(1, 2);  // Say, it sets num and den
cout << r;

the following function call is made:

operator<<(cout, r);

Can you write operator<< as a member function of Rational? That's simply not possible because of the above conversion where cout has to be first parameter. If you make operator<< as a member of Rational:

class Rational
{
    private: int m_t,m_b;

    // ...

    public:

    ostream& operator<<(ostream& out) const
    {
        out << r.m_t << "/" <<r.m_b;
        return out;
    }
};

you need to call it this way:

Rational r(1, 2);
r.operator<<(cout);

which is ugly.

Donotalo
+1  A: 

operator<< (for ostream) needs to be a free function (since the left-hand argument is a stream, not your class).

The friend keyword makes it a free function (a free function that has access to the private members).

However, if this functionality can be implemented in terms of the public interface, it is better to do so and just use a non-friend free function.

class Rational:
{
    private: int m_t,m_b;
    public:
    ...
    virtual ostream& print(ostream& out) const
    { 
      return out<<m_t << "/" << m_b;
    } 
};

ostream& operator<<(ostream& out,const Rational& r)
{
    return r.print(out);
}
UncleBens