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
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).
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.
I have a function that takes an ostream reference as an argument, writes some data to the stream, and then returns a reference to that same stream, like so:
#include <iostream>
std::ostream& print( std::ostream& os ) {
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print( std::cout ) << std::endl;
}
The output of this code is:
How are you?
Hello, world!0x601288
However, if I separate the chaining expressions into two statements, like this
int main() {
std::cout << "Hello, world!";
std::cout << print( std::cout ) << std::endl;
}
then I at least get the proper order in the output, but still get a hex value:
Hello, world! How are you?
0x600ec8
I would like to understand what's going on here. Does a normal function take precedence over operator<<, and that's why the output order reverses? What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?
The behavior of your code is unspecified as per the C++ Standard.
Explanation
The following (I removed std::endl for simplicity)
std::cout << "Hello, world!" << print( std::cout );
is equivalent to this:
operator<<(operator<<(std::cout, "Hello, World!"), print(std::cout));
which is a function call, passing two arguments:
First argument is : operator<<(std::cout, "Hello, World!")
Second argument is : print(std::cout)
Now, the Standard doesn't specify the order in which arguments are evaluated. It is unspecified. But your compiler seems to evaluate the second argument first, that is why it prints "How are you?" first, evaluating the second argument to a value of type std::ostream& which then gets passed to the call shown above (that value is the object std::cout itself).
Why hexadecimal output?
You get hexadecimal output because the second argument evaluates to std::cout, which is being printed as hexadecimal number, because std::cout implicitly converts into pointer value of void* type, which is why it is printed as hexadecimal number.
Try this:
void const *pointer = std::cout; //implicitly converts into pointer type!
std::cout << std::cout << std::endl;
std::cout << pointer << std::endl;
It will print the same value for both. For example, this example at ideone prints this:
0x804a044
0x804a044
Also note that I didn't use explicit cast; rather std::cout is implicitly converted into pointer type.
Hope that helps.
What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?
When it depends on what you mean by chaining? Obviously, the following wouldn't work (as explained above):
std::cout << X << print(std::cout) << Y << Z; //unspecified behaviour!
No matter how you write print().
However this is well-defined:
print(std::cout) << X << Y << Z; //well-defined behaviour!
The reason is that your print() function will be evaluated before the rest of the statement and return a reference to cout which is then actually printed as a pointer (cout << cout). This order of evaluation is actually unspecified behavior, but seems to be the case with your compiler.
As for defining a stream aware "function" that actually has defined behavior with the same functionality, this would work;
#include <iostream>
template <class charT, class traits>
std::basic_ostream<charT,traits>& print ( std::basic_ostream<charT,traits>& os )
{
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print << std::endl;
}
See also this answer for a little more detail on what "unspecified" actually means in this case.
Hexadecimal Output
Before C++11, the class std::ostream has a conversion function to void*. Since your print function returns std::ostream&, when evaluating std::cout << print(...), the returned std::ostream lvalue will be implicitly converted to void* and then be outputted as a pointer value. This is why there is a hexadecimal output.
Since C++11, this conversion function is replaced by an explicit conversion function to bool, so trying to output an std::ostream object becomes ill-formed.
Evaluation Order
Before C++17, overloaded operator is considered a function call for analyzing evaluation order, and evaluation order of different arguments of a function call is unspecified. So it is not strange that the print function is evaluated firstly, which causes How are you? is outputted firstly.
Since C++17, the evaluation order of operands of operator << is strictly from left to right, and operands of overloaded operator share the same evaluation order as those of the bulit-in one (see more details here). So your program will always get the output (assume print returns something able to be outputted)
Hello, world! How are you?
something returned by print
LIVE EXAMPLE
In your statement std::cout << "Hello, world!" << print( std::cout ) << std::endl it's undefined whether std::cout << "Hello, world!" happens before or after print( std::cout ). That's why the order may not be what you expect.
The hex value comes from the fact that you're also doing std::cout << std::cout (print returns std::cout which is fed into the << chain). The right hand std::cout is converted to a void * and that's printed to the output.
This would work, to combine print with << and control the order:
print( std::cout << "Hello, world!" ) << std::endl;
Or, if you want a function that's called with <<, see Joachim's answer.
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.
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 <<.