472,143 Members | 1,292 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,143 software developers and data experts.

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

>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

Nov 8 '06 #1
7 2607
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;
<BTWActually, 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
Nov 8 '06 #2

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;

<BTWActually, 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

Nov 8 '06 #3

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;

<BTWActually, 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

Nov 8 '06 #4
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;

<BTWActually, 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
Nov 8 '06 #5

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;

<BTWActually, 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

Nov 9 '06 #6

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.

Nov 9 '06 #7
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;

<BTWActually, 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
Nov 9 '06 #8

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by Dan | last post: by
5 posts views Thread by Gianni Mariani | last post: by
5 posts views Thread by Eric Lilja | last post: by
2 posts views Thread by Harry | last post: by
3 posts views Thread by Yudan Yi \(OSU\) | last post: by
2 posts views Thread by ryan_melville | last post: by
reply views Thread by leo001 | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.