I have an overloaded << operator from my reckful class implemented as follows:
ostream& operator << (ostream& os, const reckful& p)
{
os << p.PrintStuff();
return os;
}
PrintStuff() just being a member function of reckful that returns a string.
The way I understand things, if I were to write something like cout << reckobject << endl; in main(), cout << reckobject would take precedence and my overloaded << (using cout as the left operand and reckobject as the right operand) would return the ostream object os, leaving the expression os << endl; to be evaluated which would output the string and then end the line. So, the first << is the one I declared and the second is the standard << right?
However, my main question is... what is the sequence of events, which are the left and right operands, and which << operators are which when I run a statement like this:
cout << "reckful object = " << reckobject << "!" << endl;
Why does this work if there isn't an ostream object and a reckful object on either side of one << ?
Thanks.
If you notice standard way to implement << it returns the ostream itself. This is the critical piece
So something like
cout << "reckful object = " << reckobject << "!" << endl;
will be called once for
cout << "reckful object = "
This function call will return a ostream with which the second call will be made
namely
cout << reckobject;
so on an so forth.
You can test is out by implementing your << as
void operator << (ostream& os, const reckful& p)
{
os << 1;
}
in which case you can do
std::cout << p;
but not
std::cout << p << std::endl;
The operators make it harder to understand but consider this Point class
struct Point
{
Point& setX( int x) { X = x; return *this;}
Point& setY( int y) { Y = y; return *this;}
int X;
int Y;
};
The way setX and setY are defined, allows
Point p;
p.setX( 2 ).setY( 4 );
This is the same mechanism << is using to chain function calls.
Because each << returns a reference to cout. Because the operator << is left-associative, the calls are done from left to right, so
a << b << c
is equivalent to
(a << b) << c
which is equivalent1 to
operator<<(operator<<(a, b), c);
So in your example, you are doing
operator<<(operator<<(operator<<(operator<<(cout, "reckful object = "), reckobject), "!"), endl);
As you can see, each << depends on the return value of the previous << (or just cout in case there is no further left <<). If you change one of the return types of the <<s to void, you effectively stop any more << calls, because void can't be used as an argument to a function.
1 It's not exactly equivalent because in that example, all operator<< are free functions, whereas in reality, some can be member functions, so you could have a mix of member and non-member calls like
operator<<(a, b).operator<<(c);
or
operator<<(a.operator<<(b), c);
Related
I write a class Fraction, and would like to display Fraction object with std::cout:
Fraction f(3, 5);
std::cout << f << std::endl;
I know overloading operator << can be used for this display purpose. But I can also overload operator type() function, and when only with operator double()(let type be double), I can still std::cout << f << std::endl.
Even more, I can also implement operator std::string(). But, when the mentioned 3 overloaded operator functions all exist, without explicitly type conversion, which one is called when doing std::cout << f << std::endl ? This really makes me curious, is this undefined behavior denpending on compiler implementation, or if there is some rule for scoring the closest/most suitable function to call?
To reproduce, use the following code:
#include <iostream>
#include <string>
class Fraction
{
public:
Fraction(int num, int den=1):
numerator(num), denominator(den) {}
operator double() const {
std::cout << "[operator double()]";
return numerator*1.0 / denominator;
}
operator std::string() const {
std::cout << "[operator std::string()]";
return std::to_string(numerator) + "/" + std::to_string(denominator);
}
private:
int numerator;
int denominator;
#ifdef OVERLOAD_STREAM_OP
friend std::ostream& operator << (std::ostream& os, const Fraction& frac);
#endif
};
#ifdef OVERLOAD_STREAM_OP
std::ostream& operator << (std::ostream& os, const Fraction& frac)
{
std::cout << "[operator <<]";
os << std::to_string(frac.numerator) << "/" << std::to_string(frac.denominator);
return os;
}
#endif
int main()
{
Fraction f(3, 5);
double d = 4 + f;
std::cout << "\n--- now let's print\n";
std::cout << "f: " << f << std::endl;
std::cout << "f: " << std::string(f) << std::endl;
std::cout << d << std::endl;
return 0;
}
The output on my ubuntu 20.04:
(base) zz#home% clang++ fraction.cpp
(base) zz#home% ./a.out
[operator double()]
--- now let's print
f: [operator double()]0.6
f: [operator std::string()]3/5
4.6
I hope this time my question is better formulated and formatted.
Here's the code that produces two separate outputs when I think it should not since I use everytime (I think) the overloaded operator<< for an enum type.
#include <iostream>
using namespace std;
enum Etat { Intact = 5 };
class Ship {
public:
Etat etat_;
Ship ( Etat t = Intact) : etat_(t) {}
~ Ship() {}
ostream& description ( ) const { return cout << "Etat: " << etat_ << " --- ";}
//---------------------------------------ˆˆˆˆ----
};
ostream& operator<< ( ostream& s, const Etat& etat_ )
{
switch ( etat_ )
{
case Intact: s << "intact"; break;
default: s << "unknown state";
}
return s;
}
ostream& operator<< ( ostream& s, Ship n ) { return s << "Etat: " << n.etat_ ; }
int main()
{
Etat etat_ = Intact;
cout << endl << endl << "Etat: "
<< etat_ << " \"cout << etat_\"" << endl << endl;
cout << Ship(etat_)
<< " \"cout << Ship(etat_)\"" << endl << endl;
cout << Ship(etat_).description()
<< " \"cout << Ship(etat_).description()\"" << endl << endl;
return 0;
}
This is what I get in the terminal:
Etat: intact "cout << etat_"
Etat: intact "cout << Ship(etat_)"
Etat: 5 --- 1 "cout << Ship(etat_).description()"
Can anyone explain to me why, in the last case, not only it takes the integer value of the enum attribut, but also adds a "1" after the test string " --- "???
The only thing I can think of is because I used an unorthodox return method in description(), ie 'return cout << ..", but it seems to work since the test string appears.
Is there a way to force the use of the operator<< overload in description()?
Thanks
In the description() function you are returning a reference to std::cout and use it in the std::cout call in main function. There is a reason why operator<< takes an ostream reference as it's first argument. You should modify your function like this and all should work:
ostream& description(ostream& os) const {
return os << "Etat: " << etat_ << " --- ";
}
The random "1" printed out there is caused likely due to the ostream in your example trying to print out reference to itself.
We know that the fascinating class iostream is something too powerful.
it has overloded the insertion operator "<<" to take many datatypes:
ostream& operator(ostream&, int),
ostream& operator(ostream&, char)...
we cannot instantiaate ostream: ostream print;
because ostream because its most CTORSs are "protected-socoped" (cannot be accessed from outside).
the only Constructor we can call is ostream(streambuf*) which takes a pointer to another class object ( class streambuf);
I just wanted to mess up with this class:
#include <ostream>
using namespace std;
int operator << (ostream& out, int* x)
{
out << "invoked!" << endl;
cout << *x; // works well!
cout << x; // normally works well and it prints the address that x points to but instead the program get in infinite loop or crushes!
return *x;
}
int main()
{
system("color 1f");
int* pVal = new int(57);
cout << *pVal << endl;
int* pX = new int(7);
cout << *pX << endl;
cout << *pVal << ", " << *pX << endl;
//cout << pVal << endl; // this doesn't work because my operator returns
//int and not a reference to ostream.
// and it is equal to: 0 << endl; which generates the same error
cout << pVal; // this works
// cout << endl << endl << endl;
return 0;
}
I overloaded the insertion operator to take an lvalue as a reference to an ostream object and a pointer to int as rvalue, I popup a message inside my function to get sure that it is invoked.
Note that I intentionally overloaded it to return int value so that no one can write:
out << pInt << *pInt << endl;
... but just:
out << pInt;
My problem, as you can see in the inline-comments above, is that whilst cout << x normally works well, instead the program get in infinite loop or crushes!
return *x;
Can anyone explain why I am getting the error?
The problem hapens because if you just cout << x, it will call your overloaded function over and over. It never returns.
Here's the solution (cast x to void*)
int operator << (ostream& out, int* x)
{
out << "invoked!" << endl;
cout << *x; // works well!
cout << (void*)x;
return *x;
}
void operator<< (const Integer& left, const Integer& right)
{
cout << "\n: " << right.i;
}
can be accessed like:
Integer obj;
obj << 5 << 3 << 2;
Fine:
But qDebug works like qdebug() << 2;
Which means that the left operand of << operator is a function.
What should be the syntax of a user defined function so that I can write:
myfunc() << 2;
The left operand is not a function, it is the value the function returns. Specifically, qDebug() returns an instance of QDebug, which has some 20 overloads of << defined.
class A
{
public:
ostream& operator<<(int string)
{
cout << "In Overloaded function1\n";
cout << string << endl;
}
};
main()
{
int temp1 = 5;
char str = 'c';
float p= 2.22;
A a;
(a<<temp1);
(a<<str);
(a<<p);
(a<<"value of p=" << 5);
}
I want the output to be: value of p=5
What changes should is do...and the function should accept all data type that is passed
There are 2 solutions.
First solution is to make it a template.
template <typename T>
ostream& operator<<(const T& input) const
{
cout << "In Overloaded function1\n";
return (cout << input << endl);
}
However, this will make the a << str and a << p print c and 2.22, which is different from your original code. that output 99 and 2.
The second solution is simply add an overloaded function for const char*:
ostream& operator<<(int string)
{
cout << "In Overloaded function1\n";
return (cout << string << endl);
}
ostream& operator<<(const char* string)
{
cout << "In Overloaded function1\n";
return (cout << string << endl);
}
This allows C strings and everything convertible to int to be A <<'ed, but that's all — it won't "accept all data type that is passed".
BTW, you have forgotten to return the ostream.