Any operator is basically a functions.
For instance, an addition operator overloaded operator + for your class Rational might be expressed as Member function:
class Rational
{
private:
...
...
public:
...
//Implicit arg "this" is Left Hand operand.
//Explicitly stated arg objRational is Right Hand operand.
Rational operator+(const Rational& objRational) const {...};
...
};
Please note, that the argument is made const
here to ensure we do not accidentally modify the operand itself, and also the function marks itself const
to make sure we don't modify this
object. Arg is passed by ref because if we are not modifying it for sure, no need to copy and no harm in ref.
The above is technically a function, so you can do something like
Rational r1(3, 4), r2(22, 7);
Rational r3 = r1.operator+(r2); //Really possible! Try it!
It's then just a syntactic sugar added to C++ grammar to allow the same call as
Rational r3 = r1 + r2;
You wrote
cout << *temp ;
Of which, type of (*temp)
is Node, and cout
is an object of ostream
class.
So, the compiler is now looking for an overloaded operator with left hand operand an ostream
object, and right hand operand a Node
object.
So, it is as good as writing, somewhere inside the class ostream itself,
class ostream : ...
{
...
...
//Here, the only one explicit arg is Node,
//which is Right Hand side operand.
//Since it is a member operator,
//implicit arg "this" will be, by default, the LH operand.
public ostream& oprtator<<(const Node& objNode){...}
...
}
But, we do not have that possibility, since we did not write class ostream in the first place. And when it was written, your Node did not exist! Also, it may need to access private members of objNode which will not be allowed for a function which isn't member of Node class.
If we try to put it as a member of class Node, it can access Node's private members. But now the left hand operand of the operator<<
will need to be Node, which ruins the whole purpose.
So, what we do is making it a friend function.
class Node
{
...
...
public:
...
//Since this is NOT a member, bot LH and RH operand need to be stated explicitelty
friend ostream& operator<< (ostream& out, const Node& objNode) { out << node.data; return out; }
...
};
This creates an operator<<
which has left operand an ostream
and right operand a node
, and which can access private members of Node because it's friend. (^_^)
Why accept and return reference of ostream object?
Because, when you try to chain the calls, you need the same object serially getting written into.
Consider a statement: cout << "First: " << objNode1 << ", Second: " << objNode2;
It will be evaluated as
(
(
(
cout << "First: " //Innermost call
) << objNode1
) << ", Second: "
)<< objNode2;
From inside out, for each call, we need the ostream
objects to be passed to the overloaded operator which has all the previous insertions, and therefore the inner calls need to return the reference to modified (after insertion) object of ostream
to be returned.
Hope it helps; Happy Coding :)