By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,953 Members | 1,123 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,953 IT Pros & Developers. It's quick & easy.

Just learning C++ - a question

P: n/a
I have created a class and used it to further overload ostream:

class drum
{
...
friend ostream& operator<< ( ostream&, drum const& );
}

ostream& operator<< ( ostream& out, drum const& od )
{
....
return out;
}

and this works great. Now I also realize that by passing the class
reference as a const, the called subroutine is prevented from writing
to 'drum' via compile time checking.

But just for giggles, I changed the declaration and definition by
omitting the 'const'. I received many compile errors and could not
quite follow what they meant.

So my question is, why does the reference to drum HAVE TO BE 'const' ??
Is that a quirk of my (gnu cygwin) compiler or ...

Thanks a million
Wick

Jul 31 '06 #1
Share this Question
Share on Google+
12 Replies


P: n/a

wickwire wrote:
So my question is, why does the reference to drum HAVE TO BE 'const' ??
Is that a quirk of my (gnu cygwin) compiler or ...
Maybe you are attempting to print a const drum? No way of knowing
without calling code.

Jul 31 '06 #2

P: n/a
wickwire wrote:
I have created a class and used it to further overload ostream:

class drum
{
...
friend ostream& operator<< ( ostream&, drum const& );
}

ostream& operator<< ( ostream& out, drum const& od )
{
....
return out;
}

and this works great. Now I also realize that by passing the class
reference as a const, the called subroutine is prevented from writing
to 'drum' via compile time checking.

But just for giggles, I changed the declaration and definition by
omitting the 'const'. I received many compile errors and could not
quite follow what they meant.

So my question is, why does the reference to drum HAVE TO BE 'const'
?? Is that a quirk of my (gnu cygwin) compiler or ...
It doesn't have to be const. The error messages you received were most
like due to the way you used your operator -- the object which you wanted
to output _was_ in fact a const object, probably. But as you see, I am
guessing here -- you didn't follow the recommendations of FAQ 5.8.

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

P: n/a

Victor Bazarov wrote:
It doesn't have to be const. The error messages you received were most
like due to the way you used your operator -- the object which you wanted
to output _was_ in fact a const object, probably. But as you see, I am
guessing here -- you didn't follow the recommendations of FAQ 5.8.

OK, here is the code and error message:

************************************************** ***********************

#include <iostream>
#include <iomanip>

using namespace std;

class Base
{
public:
~Base(){}
Base(int val, int num) { }

friend ostream& operator<< ( ostream&, Base& );
};
ostream& operator<< ( ostream &os, Base& obj )
{
return os << "hi";
}
int main()
{
int u5 = 100;
cout << setw(0) << Base(u5,0) << endl;
return 0;
}

************************************************** ***********************
g++ o.cpp -o o
o.cpp: In function `int main()':
o.cpp:22: error: no match for 'operator<<' in 'std::operator<< [with
_CharT = char, _Traits =
std::char_traits<char>](((std::basic_ostream<char,
std::char_traits<char&)(&std::cout)), std::setw(0)) << Base(u5, 0)'

/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:63:
note: candidates are: std::basic_ostream<_CharT, _Traits>&
std::basic_ostream<_CharT,
_Traits>::operator<<(std::basic_ostream<_CharT,
_Traits>&(*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT =
char, _Traits = std::char_traits<char>]

/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:74:
note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(std::basic_ios<_CharT,
_Traits>&(*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char,
_Traits = std::char_traits<char>]

<<< The list of candidates is quite long >>>

Thanks
Wick

Jul 31 '06 #4

P: n/a

wickwire wrote:
cout << setw(0) << Base(u5,0) << endl;
You can't pass a temporary as a non-const parameter. Change to:

Base b(u5, 0);
cout << setw(0) << b << endl;

Jul 31 '06 #5

P: n/a

Noah Roberts wrote:
wickwire wrote:
cout << setw(0) << Base(u5,0) << endl;

You can't pass a temporary as a non-const parameter. Change to:

Base b(u5, 0);
cout << setw(0) << b << endl;
Thank you. A rule I was unfamiliar with. Do you mind one more question
?

Using the original code I supplied:
If I change the declaration and definition such that the passed
parameter IS a const (and this works ok as I stated before), is the
copy-constructor ever used ? I assume the constructor Base(int, int) is
all that is called (and the reference to the temporary object is passed
to ostream:: cout.

But if I add a copy-constructor to the Base object - and make it
private, I get an error message telling me that the constructor IS
private - if I add a copy-constructor to the object and make it public,
it never gets called.

Thanks again
Wick

Jul 31 '06 #6

P: n/a
In article <11**********************@i3g2000cwc.googlegroups. com>,
wi******@bigfoot.com says...

[ ... ]
ostream& operator<< ( ostream &os, Base& obj )
This takes a Base by reference, which means the parameter you pass
must be a non-const variable. To receive a temporary object, it must
receive a reference to a _const_ object:

ostream &operator<<(ostream &os, Base const &obj) { /* ... */ }

A reference parameter should normally be a reference to a const
object unless the function really needs to modify the original object
-- and you probably do NOT want an operator<< to modify the original
object.

[ ... ]
cout << setw(0) << Base(u5,0) << endl;
Here, instead of passing a non-const variable, you're passing a
temporary object. Since that can only bind to a reference to const,
and you don't have an operator<< that takes a reference to a const
Base, the compiler complains that it can't find a suitable function
to use (and, in this case, lists what it looked at that wouldn't
work).

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jul 31 '06 #7

P: n/a

Jerry Coffin wrote:
In article <11**********************@i3g2000cwc.googlegroups. com>,
wi******@bigfoot.com says...

[ ... ]
ostream& operator<< ( ostream &os, Base& obj )

This takes a Base by reference, which means the parameter you pass
must be a non-const variable. To receive a temporary object, it must
receive a reference to a _const_ object:

ostream &operator<<(ostream &os, Base const &obj) { /* ... */ }

A reference parameter should normally be a reference to a const
object unless the function really needs to modify the original object
-- and you probably do NOT want an operator<< to modify the original
object.
Thanks for a simple answer. This all makes sense now - from a rules
perspective, although I am not sure I understand WHY the limitations
are there yet. And actually, I did want the operator<< to modify the
original object, which is why I got into this issue in the first place
(no profound reason, just playing around).

Wick

Jul 31 '06 #8

P: n/a
In article <11**********************@i3g2000cwc.googlegroups. com>,
wi******@bigfoot.com says...

[ A non-const reference can't bind to a temporary ... ]
Thanks for a simple answer. This all makes sense now - from a rules
perspective, although I am not sure I understand WHY the limitations
are there yet.
A couple of reasons. One is that it gives the compiler some leeway in
how it does things. For example, rather than creating each temporary
object on the fly, the compiler could pre-build all the temporary
objects, and then just use them when needed. If you allowed them to
be modified, the next time you re-used that temporary object, you
wouldn't get what you expected.
And actually, I did want the operator<< to modify the
original object, which is why I got into this issue in the first place
(no profound reason, just playing around).
While it's perfectly reasonable when you're just playing around, for
real code, careful judgement is important. Overloading operators to
do things a lot different from what people expect is generally a poor
idea. You could overload operator+ to do multiplication and operator*
to do subtraction, but it would usually be a really _bad_ idea.

Likewise with overloading operator<< to modify its argument. This
would surprise people enough that it's almost certain to be a bad
idea.

As an aside, what does it accomplish for it to modify its argument,
if that argument is a temporary? The new value you've created will be
discarded at the end of the expression anyway...

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jul 31 '06 #9

P: n/a

Jerry Coffin wrote:
In article <11**********************@i3g2000cwc.googlegroups. com>,
wi******@bigfoot.com says...

As an aside, what does it accomplish for it to modify its argument,
if that argument is a temporary? The new value you've created will be
discarded at the end of the expression anyway...
In this case, I was building a binary number operator for ostream and
as I was peeling the bits off of the passed value, I was shifting the
number <in a variable in the object>. So in effect I was simply using a
variable in the object when an automatic variable in the function would
have been a better choice.

Enjoy,
Wick

Jul 31 '06 #10

P: n/a

wickwire wrote:
Noah Roberts wrote:
wickwire wrote:
cout << setw(0) << Base(u5,0) << endl;
You can't pass a temporary as a non-const parameter. Change to:

Base b(u5, 0);
cout << setw(0) << b << endl;

Thank you. A rule I was unfamiliar with. Do you mind one more question
?

Using the original code I supplied:
If I change the declaration and definition such that the passed
parameter IS a const (and this works ok as I stated before), is the
copy-constructor ever used ? I assume the constructor Base(int, int) is
all that is called (and the reference to the temporary object is passed
to ostream:: cout.

But if I add a copy-constructor to the Base object - and make it
private, I get an error message telling me that the constructor IS
private - if I add a copy-constructor to the object and make it public,
it never gets called.
I don't know why the copy-ctr is wanted. If the standard says a copy
takes place then the copy ctr must be available. However, the standard
does say that an implementation is free not to copy in some cases as an
optimization technique so then maybe the ctr has to be there but
doesn't have to be called.

I don't know the actual answer to your question. That's just a guess
about what might be going on.

Jul 31 '06 #11

P: n/a

Noah Roberts wrote:
wickwire wrote:
Noah Roberts wrote:
wickwire wrote:
I don't know why the copy-ctr is wanted. If the standard says a copy
takes place then the copy ctr must be available. However, the standard
does say that an implementation is free not to copy in some cases as an
optimization technique so then maybe the ctr has to be there but
doesn't have to be called.

I don't know the actual answer to your question. That's just a guess
about what might be going on.
Thanks for trying to answer this one. I did find another post that
asked a similar question and the answer was that the compiler needed
the ctor (so it had to be public) and then optimised it away (so it
never got called). That seems to describe the bahavior I see although
why a copy-ctor would be needed in the first place is still a mystery.

See, I'm learning a lot from this group. I'm already using 'ctor'
instead of 'constructor' !

Wick

Jul 31 '06 #12

P: n/a

wickwire wrote:
Noah Roberts wrote:
wickwire wrote:
Noah Roberts wrote:
wickwire wrote:
I don't know why the copy-ctr is wanted. If the standard says a copy
takes place then the copy ctr must be available. However, the standard
does say that an implementation is free not to copy in some cases as an
optimization technique so then maybe the ctr has to be there but
doesn't have to be called.

I don't know the actual answer to your question. That's just a guess
about what might be going on.

Thanks for trying to answer this one. I did find another post that
asked a similar question and the answer was that the compiler needed
the ctor (so it had to be public) and then optimised it away (so it
never got called). That seems to describe the bahavior I see although
why a copy-ctor would be needed in the first place is still a mystery.
It has to do with the assignment of the temporary to a reference. The
reference has to be const (as the return of a function/constructor is
not an lvalue) and a copy occurs.

The implementation is free to optimize out the copy but all semantic
requirements must be met. In other words the constructor must exist.

I just looked it up in the std...many references, I couldn't quote it
all here but that is the gist of the matter. The standard is really a
must have for anyone serious about really knowing what they are doing
in C++.

Jul 31 '06 #13

This discussion thread is closed

Replies have been disabled for this discussion.