Why operator<< should be friend or global, non-member function.

Discussion in 'C++' started by Eric Lilja, Nov 8, 2006.

  1. Eric Lilja

    Eric Lilja Guest

    >From a book, I know the following is true for the comparison operators:
    An overloaded operator that is a class member is only considered
    when the operator is used with a *left* operand that is an object
    of that class.
    And is that also the reason why if you use class member functions for
    operators << and >> you have to write:
    someclass << cout;
    someclass >> cin;
    ?

    Thus you usually make them friends so you avoid have to use cin and
    cout
    in such a weird manner.

    / E
    Eric Lilja, Nov 8, 2006
    #1
    1. Advertising

  2. Eric Lilja wrote:
    >> From a book, I know the following is true for the comparison
    >> operators:

    > An overloaded operator that is a class member is only considered
    > when the operator is used with a *left* operand that is an object
    > of that class.
    > And is that also the reason why if you use class member functions for
    > operators << and >> you have to write:
    > someclass << cout;
    > someclass >> cin;


    <BTW> Actually, I'd expect the "arrows" to be reversed here, IOW

    someclass >> cout;
    someclass << cin;

    to correctly show the "direction" of the data flow. </BTW>

    > ?


    No, it is not. The actual reason is that if you wanted them as members,
    they would have to be members of 'ostream' or 'istream', to which you
    have no access. That's why they are usually made non-members. Nobody
    in their right mind thinks of making them members of the class to be
    streamed.

    > Thus you usually make them friends so you avoid have to use cin and
    > cout
    > in such a weird manner.


    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Nov 8, 2006
    #2
    1. Advertising

  3. Eric Lilja

    Eric Lilja Guest

    Victor Bazarov skrev:

    > Eric Lilja wrote:
    > >> From a book, I know the following is true for the comparison
    > >> operators:

    > > An overloaded operator that is a class member is only considered
    > > when the operator is used with a *left* operand that is an object
    > > of that class.
    > > And is that also the reason why if you use class member functions for
    > > operators << and >> you have to write:
    > > someclass << cout;
    > > someclass >> cin;

    >
    > <BTW> Actually, I'd expect the "arrows" to be reversed here, IOW


    Oops, sorry about that.

    >
    > someclass >> cout;
    > someclass << cin;
    >
    > to correctly show the "direction" of the data flow. </BTW>
    >
    > > ?

    >
    > No, it is not. The actual reason is that if you wanted them as members,


    Ok, so which operators is the statement true for (An overloaded
    operator that is a class member is only considered when the operator is
    used with a *left* operand that is an object of that class.)? Only for
    comparison operators?

    > they would have to be members of 'ostream' or 'istream', to which you
    > have no access. That's why they are usually made non-members. Nobody
    > in their right mind thinks of making them members of the class to be
    > streamed.
    >
    > > Thus you usually make them friends so you avoid have to use cin and
    > > cout
    > > in such a weird manner.

    >
    > V
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask


    / E
    Eric Lilja, Nov 8, 2006
    #3
  4. Eric Lilja

    Eric Lilja Guest

    Victor Bazarov skrev:

    > Eric Lilja wrote:
    > >> From a book, I know the following is true for the comparison
    > >> operators:

    > > An overloaded operator that is a class member is only considered
    > > when the operator is used with a *left* operand that is an object
    > > of that class.
    > > And is that also the reason why if you use class member functions for
    > > operators << and >> you have to write:
    > > someclass << cout;
    > > someclass >> cin;

    >
    > <BTW> Actually, I'd expect the "arrows" to be reversed here, IOW
    >
    > someclass >> cout;
    > someclass << cin;
    >
    > to correctly show the "direction" of the data flow. </BTW>
    >
    > > ?

    >
    > No, it is not. The actual reason is that if you wanted them as members,
    > they would have to be members of 'ostream' or 'istream', to which you
    > have no access. That's why they are usually made non-members. Nobody
    > in their right mind thinks of making them members of the class to be
    > streamed.


    But wait a minute, it is reason then. You seemed to say that the
    statement "An overloaded operator that is a class member is only
    considered when the operator is used with a *left* operand that is an
    object of that class." is false.
    In the form cout << myclass; cout is the left operand, that's why you
    said I'd have to change ostream or istream. So the statement above is
    true for operator << and >> too.

    >
    > > Thus you usually make them friends so you avoid have to use cin and
    > > cout
    > > in such a weird manner.

    >
    > V
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask


    / E
    Eric Lilja, Nov 8, 2006
    #4
  5. Eric Lilja wrote:
    > Victor Bazarov skrev:
    >
    >> Eric Lilja wrote:
    >>>> From a book, I know the following is true for the comparison
    >>>> operators:
    >>> An overloaded operator that is a class member is only considered
    >>> when the operator is used with a *left* operand that is an object
    >>> of that class.
    >>> And is that also the reason why if you use class member functions
    >>> for operators << and >> you have to write:
    >>> someclass << cout;
    >>> someclass >> cin;

    >>
    >> <BTW> Actually, I'd expect the "arrows" to be reversed here, IOW
    >>
    >> someclass >> cout;
    >> someclass << cin;
    >>
    >> to correctly show the "direction" of the data flow. </BTW>
    >>
    >>> ?

    >>
    >> No, it is not. The actual reason is that if you wanted them as
    >> members, they would have to be members of 'ostream' or 'istream', to
    >> which you have no access. That's why they are usually made
    >> non-members. Nobody in their right mind thinks of making them
    >> members of the class to be streamed.

    >
    > But wait a minute, it is reason then. You seemed to say that the
    > statement "An overloaded operator that is a class member is only
    > considered when the operator is used with a *left* operand that is an
    > object of that class." is false.


    Huh?

    struct A {
    A(int);
    void operator+(A const&) const;
    };

    int main() {
    A a(42);
    a + 73; // compiles OK
    666 + a; // cannot compile
    }

    '666 + a' does not compile because the compilers don't try to convert
    the left operand to 'A' (here). That's why in order for '666 + a' to
    compile, you need the operator+ to be non-member:

    struct A {
    A(int);
    };

    void operator+(A const&, A const&);

    int main() {
    A a(42);
    a + 73; // compiles OK
    666 + a; // compile OK
    }

    > In the form cout << myclass; cout is the left operand, that's why you
    > said I'd have to change ostream or istream. So the statement above is
    > true for operator << and >> too.


    You lost me.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Nov 8, 2006
    #5
  6. Eric Lilja

    Eric Lilja Guest

    Victor Bazarov skrev:

    > Eric Lilja wrote:
    > > Victor Bazarov skrev:
    > >
    > >> Eric Lilja wrote:
    > >>>> From a book, I know the following is true for the comparison
    > >>>> operators:
    > >>> An overloaded operator that is a class member is only considered
    > >>> when the operator is used with a *left* operand that is an object
    > >>> of that class.
    > >>> And is that also the reason why if you use class member functions
    > >>> for operators << and >> you have to write:
    > >>> someclass << cout;
    > >>> someclass >> cin;
    > >>
    > >> <BTW> Actually, I'd expect the "arrows" to be reversed here, IOW
    > >>
    > >> someclass >> cout;
    > >> someclass << cin;
    > >>
    > >> to correctly show the "direction" of the data flow. </BTW>
    > >>
    > >>> ?
    > >>
    > >> No, it is not. The actual reason is that if you wanted them as
    > >> members, they would have to be members of 'ostream' or 'istream', to
    > >> which you have no access. That's why they are usually made
    > >> non-members. Nobody in their right mind thinks of making them
    > >> members of the class to be streamed.

    > >
    > > But wait a minute, it is reason then. You seemed to say that the
    > > statement "An overloaded operator that is a class member is only
    > > considered when the operator is used with a *left* operand that is an
    > > object of that class." is false.

    >
    > Huh?
    >
    > struct A {
    > A(int);
    > void operator+(A const&) const;
    > };
    >
    > int main() {
    > A a(42);
    > a + 73; // compiles OK
    > 666 + a; // cannot compile
    > }
    >
    > '666 + a' does not compile because the compilers don't try to convert
    > the left operand to 'A' (here). That's why in order for '666 + a' to
    > compile, you need the operator+ to be non-member:
    >
    > struct A {
    > A(int);
    > };
    >
    > void operator+(A const&, A const&);
    >
    > int main() {
    > A a(42);
    > a + 73; // compiles OK
    > 666 + a; // compile OK
    > }
    >
    > > In the form cout << myclass; cout is the left operand, that's why you
    > > said I'd have to change ostream or istream. So the statement above is
    > > true for operator << and >> too.

    >
    > You lost me.


    Hehe, ok, I'll try to be a bit more clearer. Just trying to understand
    why operator<< (and >>) "has to be" non-member functions for
    user-introduced classes if you want to be able to use input and output
    streams with objects of those classes in the normal way.
    Say we have a class A and we have an instance of A named "a" and we do:
    cout << a;
    The compiler first check for a global function returning an
    ostream-reference and taking two arguments: reference to an ostream and
    const reference to class A.
    If it finds no such function it translates the call to
    cout.operator<<(a) but that fails because ostream doesn't have a member
    operator<< that takes our class A. Or maybe it checks the other way
    around.
    If we make operator<< a member of A we have to write a.operator<<(cout)
    or a << cout;
    Thus, the solution is to write a global operator<< (usually declared as
    friend for easy access to the class private data members).
    Is this "analysis" correct or at least somewhat correct?

    >
    > V
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask


    / E
    Eric Lilja, Nov 9, 2006
    #6
  7. Eric Lilja

    Noah Roberts Guest

    Eric Lilja wrote:
    > >From a book, I know the following is true for the comparison operators:

    > An overloaded operator that is a class member is only considered
    > when the operator is used with a *left* operand that is an object
    > of that class.
    > And is that also the reason why if you use class member functions for
    > operators << and >> you have to write:
    > someclass << cout;
    > someclass >> cin;
    > ?
    >
    > Thus you usually make them friends so you avoid have to use cin and
    > cout
    > in such a weird manner.


    Avoid making them friends.
    Noah Roberts, Nov 9, 2006
    #7
  8. Eric Lilja wrote:
    > Victor Bazarov skrev:
    >
    >> Eric Lilja wrote:
    >>> Victor Bazarov skrev:
    >>>
    >>>> Eric Lilja wrote:
    >>>>>> From a book, I know the following is true for the comparison
    >>>>>> operators:
    >>>>> An overloaded operator that is a class member is only considered
    >>>>> when the operator is used with a *left* operand that is an object
    >>>>> of that class.
    >>>>> And is that also the reason why if you use class member functions
    >>>>> for operators << and >> you have to write:
    >>>>> someclass << cout;
    >>>>> someclass >> cin;
    >>>>
    >>>> <BTW> Actually, I'd expect the "arrows" to be reversed here, IOW
    >>>>
    >>>> someclass >> cout;
    >>>> someclass << cin;
    >>>>
    >>>> to correctly show the "direction" of the data flow. </BTW>
    >>>>
    >>>>> ?
    >>>>
    >>>> No, it is not. The actual reason is that if you wanted them as
    >>>> members, they would have to be members of 'ostream' or 'istream',
    >>>> to which you have no access. That's why they are usually made
    >>>> non-members. Nobody in their right mind thinks of making them
    >>>> members of the class to be streamed.
    >>>
    >>> But wait a minute, it is reason then. You seemed to say that the
    >>> statement "An overloaded operator that is a class member is only
    >>> considered when the operator is used with a *left* operand that is
    >>> an object of that class." is false.

    >>
    >> Huh?
    >>
    >> struct A {
    >> A(int);
    >> void operator+(A const&) const;
    >> };
    >>
    >> int main() {
    >> A a(42);
    >> a + 73; // compiles OK
    >> 666 + a; // cannot compile
    >> }
    >>
    >> '666 + a' does not compile because the compilers don't try to convert
    >> the left operand to 'A' (here). That's why in order for '666 + a' to
    >> compile, you need the operator+ to be non-member:
    >>
    >> struct A {
    >> A(int);
    >> };
    >>
    >> void operator+(A const&, A const&);
    >>
    >> int main() {
    >> A a(42);
    >> a + 73; // compiles OK
    >> 666 + a; // compile OK
    >> }
    >>
    >>> In the form cout << myclass; cout is the left operand, that's why
    >>> you said I'd have to change ostream or istream. So the statement
    >>> above is true for operator << and >> too.

    >>
    >> You lost me.

    >
    > Hehe, ok, I'll try to be a bit more clearer. Just trying to understand
    > why operator<< (and >>) "has to be" non-member functions for
    > user-introduced classes if you want to be able to use input and output
    > streams with objects of those classes in the normal way.


    Well, actually, no. You can define your own stream class wrapping
    standard stream, then you will be able to add your own operators to
    it and "forward" them in any way you want to the wrapped stream.

    > Say we have a class A and we have an instance of A named "a" and we
    > do: cout << a;


    OK. That's what we do usually.

    > The compiler first check for a global function returning an
    > ostream-reference and taking two arguments: reference to an ostream
    > and const reference to class A.


    It first checks the member, actually.

    > If it finds no such function it translates the call to
    > cout.operator<<(a) but that fails because ostream doesn't have a
    > member operator<< that takes our class A. Or maybe it checks the
    > other way around.


    Right. The other way.

    > If we make operator<< a member of A we have to write
    > a.operator<<(cout) or a << cout;


    Well, yes, but nobody does it that way.

    > Thus, the solution is to write a global operator<< (usually declared
    > as friend for easy access to the class private data members).
    > Is this "analysis" correct or at least somewhat correct?


    Nah, it's fine. You got it.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Nov 9, 2006
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. slide_o_mix
    Replies:
    0
    Views:
    401
    slide_o_mix
    Oct 15, 2003
  2. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,665
    Smokey Grindel
    Dec 2, 2006
  3. Andre  Eisenbach
    Replies:
    6
    Views:
    330
    David White
    Sep 11, 2005
  4. pat270881

    friend und non-member function

    pat270881, Sep 8, 2006, in forum: C++
    Replies:
    5
    Views:
    695
    pat270881
    Sep 9, 2006
  5. Ralph Moritz
    Replies:
    1
    Views:
    313
    Salt_Peter
    Dec 21, 2006
Loading...

Share This Page