Don't let the <<
operator confuse you. Overloaded operators are, at the end of the day, just another way to name functions.
If you have this piece of code:
int i = 1;
std::string s = "x";
double d = 0.5;
std::cout << s << i << d;
Then this is just another way of saying:
int i = 1;
std::string s = "x";
double d = 0.5;
std::operator<<(std::cout, s).operator<<(i).operator<<(d);
Which, by the way, makes it more obvious that the chaining calls work because operator<<
returns a reference to the stream itself. Note that there are two different kinds of operator<<
involved here: the one for std::string
is a free-standing function taking a std::ostream
reference argument, the ones for int
and double
are std::ostream
member functions.
Equipped with this knowledge, it's easy to imagine, for a moment, that we would just be dealing with normally named functions, e.g. "print":
int i = 1;
std::string s = "x";
double d = 0.5;
print(std::cout, s).print(i).print(d);
In fact, you can imagine that there is no overloading but all of them have different names. This makes the whole thing even easier to understand:
int i = 1;
std::string s = "x";
double d = 0.5;
printStringOnStream(std::cout, s).printInt(i).printDouble(d);
If you want to provide std::ostream
printing for your own class, all you have to do is do it like std::string
: provide a free-standing operator<<
which takes a std::ostream
reference and a (const) reference to your object, and which returns a reference to the stream:
std::ostream &operator<<(std::ostream &stream, Employee const &employee)
{
// ...
return stream;
}
Now the // ...
part is where the friend thing comes into play. In order to properly print an Employee
, you'll need access to all its private members. The easiest way to provide this access without exposing it to the whole public is to declare your operator<<
a friend of Employee
:
class Employee
{
// ...
friend std::ostream &operator<<(std::ostream &stream, Employee const &employee);
};
std::ostream &operator<<(std::ostream &stream, Employee const &employee)
{
stream << employee.earnings; // and so on
return stream;
}
There you go, perfect printing for your Employee:
std::cout << "xyz" << my_employee << "abc" << 0.5 << 1;