I'm trying to understand how to properly overload the "<<" operator so that I can use
std::cout << my_object;
to print useful debug messages. In particular, I need to have an implementation of << for each of my subclasses, so I'm declaring << to be virtual in the superclass.
Right now I'm stuck with the following piece of code
#include <iostream>
using namespace std;
class Shape {
public:
virtual ~Shape() { };
virtual ostream& operator<<(std::ostream &strm) = 0;
};
class Square : public Shape {
int size;
public:
Square() { size = 10; }
~Square() { }
ostream& operator<<(std::ostream &strm) {
return strm << "a square with size " << size;
}
};
int main() {
Square *my_square = new Square();
cout << "my_square is " << my_square << "\n";
}
which (I think) should be working, but doesn't. What I get when using "<<" is that the pointer value of my_square gets printed, rather than the result of the overloaded << .
$ ./a.out
my_square is 0xcacc20
What am I missing here?
operator<<
can't be a member function. This is because of the order of the arguments. The stream has to come first.
When calling an overloaded operator, such as:
os << object;
the compiler will attempt to look up both
os.operator<<(object);
and
operator<<(os, object);
(The rules for this can be rather complex, I won't attempt to describe them here.)
Because the stream always comes on the left, your member function will never be found, since it would have to be called as:
object.operator<<(os);
You need to write a free function like:
ostream& operator<<(std::ostream &strm, Square const& square) {
return strm << "a square with size " << square.size();
}
(where Square::size()
returns the size
member).
Then you need to remember to dereference your pointer too:
std::cout << *my_square << '\n';
Although I see no reason to be dynamically allocating my_square
in this example anyway. Just stick it on the stack as a local variable.
If the aim here is ultimately to be able to print any Shape&
, and have the printed output follow the "real" type, you would need to create:
virtual std::ostream& print(std::ostream&) const = 0;
in the Shape
base class, and override it in each derived class, then have a free function:
std::ostream& operator<<(std::ostream& os, Shape const& shape)
{
return shape.print(os);
}
It is often advised to make all binary operators on your type non-member functions, so that both arguments are treated equally, and the operation remains commutative. See Scott Meyers, Effective C++ (3rd Edition), Item 24, (or find a summary online).
As noted by others, the problem is that operator <<
can't be member function (because of the order of arguments). The canonical way to do this is to have operator <<(const Shape&)
call a virtual function in Shape
class Shape {
friend ostream& operator<<(std::ostream& str, const Shape& shape);
virtual void do_print(ostream& str) = 0;
public:
virtual ~Shape() { };
};
ostream& operator<<(std::ostream& str, const Shape& shape) {
shape.do_print(str);
return str;
}
Note that it is legal to have do_print
be private, even though it is going to be (must be) overridden by derived classes. You could make it protected though if you like.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With