I wrote a simple binary tree class in C++ and want to add an output operator to it. My first attempt was:
ostream& operator<<(ostream& out, const Tree& tree) {
out << tree.myData;
if (tree.myLeft)
out << "(" << (*tree.myLeft) << ")";
if (tree.myRight)
out << "[" << (*tree.myRight) << "]";
return out;
}
(where myLeft and myRight are pointers to left and right child of the current tree, respectively). This works correctly, however, it is not sufficiently cool, since it spans several lines and requires to write "out << " several times.
As an attempt to create a one-line operator, I wrote this:
ostream& operator<<(ostream& out, const Tree& tree) {
return (out << tree.myData
<< "(" << (tree.myLeft? *tree.myLeft: "") << ")"
<< "[" << (tree.myRight? *tree.myRight: "") << "]");
}
But, this generates an error:
incompatible operand types ('Tree' and 'const char [1]')
So I tried this:
ostream& operator<<(ostream& out, const Tree& tree) {
return (&tree?
out << tree.myData
<< "(" << *(tree.myLeft) << ")"
<< "[" << *(tree.myRight) << "]":
out);
}
This works on my computer, but generates a warning implying that this is undefined behavior:
Reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to always convert to true [-Wundefined-bool-conversion]
QUESTION: Is there a way to write this output operator in a simple single statement?
A simple and elegant solution is to redesign your tree to work without null pointers. Instead, replace current uses of null pointers with pointers to a sentinel tree node which has behaviour consistent with an empty tree.
Then you can rewrite your output stream operator as follows:
ostream& operator<<(ostream& out, const Tree& tree) {
if (&tree == &Tree::NULL_TREE_SENTINEL) return out;
return out << tree.myData
<< "(" << *tree.myLeft << ")"
<< "[" << *tree.myRight << "]";
}
(This assumes a corresponding static member inside Tree, to which the sentinels are pointers, like singletons.)
Alternatively, the sentinel tree node could be an instance of a subclass of Tree with this behaviour. This is sometimes known as the null object pattern. However, it requires dynamic dispatch (i.e. runtime polymorphism via virtual member functions) to work.
Apart from this you don’t quite diagnose the problem with your second code correctly:
This works on my computer
It appears to work but doesn’t actually. I don’t know under what exact circumstances that code will actually do something nasty. But just to be clear, your code is illegal due to the sub-expressions *(tree.myLeft) and *(tree.myRight): these expressions are dereferencing null pointers, and this is never legal. The warning message you’re receiving about the &tree test is merely a symptom of that prior error.
Related
We had a class where professor asked us to overload ostream to print object this way (saying we have object t)
cout << t << endl;
Then we were asked to cout the same object this way
t << cout << endl;
How does this work and why?
ostream& operator<<(ostream& o, T& t)
{
return o << t.member;
}
// This is usual way and "normal" that I know about but won't work on both ways
Expected output is the same, but second way is confusing. Why would anyone want to use it?
As any good book or tutorial should tell you, for any operator X the expression a X b will (if a suitable overload is found) be equal to operatorX(a, b).
Or if a (in a X b) have overloaded the operator as a member function, then it's equal to a.operatorX(b).
If we now take cout << t, that will call either operator<<(cout, t) or cout.operator<<(t) depending on the type of t.
As should be easy to guess, reversing the order to t << cout would then be operator<<(t, cout) or t.operator<<(cout).
This question already has answers here:
Why we need to return reference to istream/ostream while overloading >> and << operators?
(4 answers)
Closed 5 years ago.
//using namespace std;
Here's the following piece of code
ostream& write(ostream& os) const {
os << getRe() << "j " << getIm();
return os;
}
This is a member function in a class representing complex numbers ("PComplex), which is derived from an abstract class ("Serializable"). (Implementation of pure virtual function).
My main question is why do we need to return a reference to an ostream object? Why not void?
Returning an ostream& object allows us to chain a bunch of operators togeather.
Consider this statement
cout << "Hello " << "World";
This is actually two calls to ostream& operator<<(ostream& os, const char* c). If we consider the order of execution, we get:
(cout << "Hello ") << "World";
This function accepts cout on the left and "Hello " on the right. It prints the contents of the right hand-side to the console, then it returns cout. We we consider what's left after the first step we get this:
(cout) << "World";
Now we take the brackets away and get:
cout << "World;
This one is much easier to deal with. Now we call the function again to print `"World" and return the cout again, which we will simply not do anything with.
If we returned void instead of ostream&, then (cout << "Hello ") would reduce to (void). That would leave us with:
(void) << "World";
This doesn't match any overloads and so we would then get an error. While the (cout << "Hello ") would still work, we wouldn't be able to chain << "World" on the same line.
so I am coding my c++ homework assignment and there is a final part where he wants us to Replace the formatted output method (toString) with an overloaded output/insertion operator. TO be 100% honest I have no idea what he means by this. I've searched around a bit and found example codes using an overloaded insertion operator, but can't seem to find how to incorporate it into my code. Though I think I may be looking in the wrong place. My toString is as follows:
string Movie::toString() const {
ostringstream oS;
oS << "\n\n====================== Movie Information\n"
<< "\n Movie Title:\t" << title << " (" << releaseYear << ")"
<< "\n US Rank & Box Office:\t" << usRank << "\t$" << usBoxOffice
<< "\nNon-US Rank & Box Office:\t" << nonUSRank << "\t$" << nonUSBoxOffice
<< "\n World Rank & Box Office:\t" << worldRank << "\t$" << worldBoxOffice
<< "\n";
return oS.str();
}
Like I mentioned I'm not sure what "overloaded" means, so If for some reason this isn't enough information for you to help me with the problem directly, then can you give me a brief description of what he may mean by replacing the current output with an overloaded output operator. Thank You
edit: This is the next question I have. https://stackoverflow.com/questions/14924621/c-overloaded-output-operator-cont
To overload a function means to provide other functions with the same name but different parameter types. Operators can also be overloaded. Many operators have a corresponding function that can be overloaded called operator??, where ?? is the operator itself. For example if you have two objects x and y of class type T, you could overload operator+. Overloading an operator allows you to give some meaning to using that operator with the type. So now you could do x + y.
The stream insertion operator is <<. It's what you use when you do std::cin << "hello"; - it inserts into the stream. This operator can also be overloaded, just as + was overloaded above. The function you need to overload is called operator<<.
There are two ways to overload a binary operator like << (binary because it takes two operands, one on the left side and one on the right, left << right). One is to make it a member of the type of left and give it a single parameter of the type of right. The other is to make it a non-member function with two parameters, one the type of left and the other the type of right. Since the type of your left will be std::ostream, you can't modify the class (because it's provided by the standard), so you'll have to go with option two.
So your free function needs to look something like this:
std::ostream& operator<<(std::ostream& os, const Movie& movie) {
// Insert everything you want into `os`
return os;
}
Now this function will be called whenever you do << with an std::ostream on the left and a Movie on the right.
I think your task is meant to be writing an overloaded operator << which allows you to write the string representation of your object to an output stream:
std::ostream& operator <<(std::ostream& os, const Movie& movie) {
os << "\n\n====================== Movie Information\n"
<< "\n Movie Title:\t" << movie.title << " (" << movie.releaseYear << ")"
<< "\n US Rank & Box Office:\t" << movie.usRank << "\t$" << movie.usBoxOffice
<< "\nNon-US Rank & Box Office:\t" << movie.nonUSRank << "\t$" << movie.nonUSBoxOffice
<< "\n World Rank & Box Office:\t" << movie.worldRank << "\t$" << movie.worldBoxOffice
<< "\n";
return os;
}
And you use this operator as you could do with built-in types:
Movie m;
// Do something with m
cout << m; // Write m to the standard output
I am trying to revive some old software but the problem is that the software was written in 2003 with MC and windows Iostream Header files have changed from that times iostream.h to iostream.
So this software had a 3D matrix Library which had function something like this
friend ostream& operator<< (ostream&, const CMatrix3D<T>&);
this function was no more compatable with iostream so I changed it to:
friend bool operator<< (std::ostream&, const CMatrix3D<T>&);
but now at one place where this function was previously called as:
friend ostream& operator << (ostream& os, block* bl)
{
vec_3d p1 = bl->points[0]->value();
vec_3d p2 = bl->points[6]->value();
os << "Diagonal points: " << p1 << " " << p2;
return os;
}
and then I changed it to:
friend bool operator << (std::ostream& os, block* bl)
{
vec_3d p1 = bl->points[0]->value();
vec_3d p2 = bl->points[6]->value();
os << "Diagonal points: " << p1 << " " << p2;
return os;
}
giving me these errors:
error C2297: '<<' : illegal, right operand has type 'const char [2]'
error C2678: binary '<<' : no operator found which takes a left-hand
operand of type 'int' (or there is no acceptable conversion)
Can someone suggest me a way out?
The reason that that the operator<< on ostreams has a return type of ostream& is so that it can be chained, to call as shown in your example implementations:
os << "Diagonal points: " << p1 << " " << p2;
This is the standard behavior of that operator, and a lot of code will rely on it, so it's a bad idea to have it return something else such as the bool that you changed it to. It should always return std::ostream&.
That should fix at least some of your problems. It is not clear without seeing the rest of your code, and knowing exactly which line the compiler is complaining about, whether that is all of the problem or not.
To remove whitespace from an input stream these days, you use the std::ws input manipulator.
i.e.
fp >> ws;
MSDN Reference for std::ws.
I want to overload << operator in a Line class so I can print an object using cout like this:
cout << myLineObject << endl;
but this is not working:
class Line{
public:
float m;
float b;
string operator << (Line &line){return ("y = " + line.m + "x + " + line.b);};
};
I get:
Invalid operands of types 'const char [5]' and 'float' to binary 'operator+'
I also tried with stringstream but I get even more errors. What is the correct way of doing this?
Thanks ;)
The correct way is listed everywhere overloading << is discussed, and you've managed to miss pretty much all of it.
The standard declaration is ostream & operator<<(ostream & s, const & Line l); It cannot be a member function, and it needs to return a reference to the ostream so that you can chain << as normal.
The definition, in your case, would be something like
ostream & operator<<(ostream & s, const & Line l)
{
return s << "y = " << l.m << "x + " << l.b;
}
Note that you return the incoming ostream, and print what you like using the << operator rather than using the + operator. It's pretty simple if you follow this
form.
In this case, the data members are public (which is not a good idea in general),
so there's no access problems. If you need to get inaccessible values (because
they're private and not exposed in the public interface), you'll need to declare
the operator to be a friend in the class definition.
operator<< has to be a non-member function, since the stream is the left-hand argument. In your case, since the data members are public, it can be implemented outside the class:
std::ostream& operator<<(std::ostream& stream, const Line& line)
{
return stream << "y = " << line.m << " x = " << line.b;
}
Googled this one, looks fine:
Overloading <<
Basically, when overloading << operator for IO, your function should look like this:
friend ostream& operator<<(ostream& output, const YourClassHere& p);
Notice, that operator<< is not a class member, but a external function (which can be friend if you need it to be). Such function should use output to write to it and then return it, so you can chain it.
The error here is nothing to do with the operator overloading, though once resolved you may have more questions on that. This error happens because there is no operator+ defined that takes arguments of const char[5] and float. Since you are trying to concatenate the string forms of those four args
"y = " + line.m + "x + " + line.b
you have to do this in a way the compiler can understand e.g.
ostringstream concat;
concat << string("y = ") << line.m << string("x + ") << line.b;
return concat.str();
Once you get past this, you can work on your << overloading logic.
You can do this way:
class Line{
public:
float m;
float b;
friend ostream& operator<< (ostream& out, Line& object) {
out << object.m << endl;
out << object.b << endl;
return out;
}
};
Then you can do:
cout << your_Line_object << endl;
Other have explained the correct way. I figured I'd mention what you are doing wrong.
You define an operator which takes two Line objects:
Line a;
Line b;
string c = a << b;
// c would have the string values for line b
// the values of line a would be ignored.
Of course, that's not the error you are seeing. That's caused by the line "y = " + line.m. "y = " is a char[5]. amd line.m is a float, and there is no operator+ which takes those two (This ain't Basic -- or C#).
The problem is that C++ has no easy way to "add" non-string values to a string. Which is why we use the convention of cout <<.