I have researched and found out that when you want to overload the output stream operator for cout, then the correct way to go about it is to do it this way:
std::ostream& operator<<(std::ostream& os, const T& obj)
This function must be defined outside the class since whats going on here is that the operator<< is actually a friend function defined in ostream and you are making use of that. But, the question is, how exactly is this function being defined in ostream? Since this function takes 2 parameters and the second parameter is user-defined, there is no way that they can guess what is coming there.
Overloading for a class specific should look like this:
std::ostream& operator<<(std::ostream& os, const MyClass& obj)
How does the compiler/library take a generic definition for the second parameter, especially since there is no such thing as a generic class (such as Object in Java) in C++?
you can't overload left shift operator like this in c#. Because in the left shift operator, the first operand must be the containing type and second operand must be an integer. As Mark described, you do can overload operator << in that way.
The left-shift operator causes the bits in shift-expression to be shifted to the left by the number of positions specified by additive-expression . The bit positions that have been vacated by the shift operation are zero-filled.
You can redefine or overload the function of most built-in operators in C++. These operators can be overloaded globally or on a class-by-class basis. Overloaded operators are implemented as functions and can be member functions or global functions. An overloaded operator is called an operator function.
This means C++ has the ability to provide the operators with a special meaning for a data type, this ability is known as operator overloading. For example, we can overload an operator '+' in a class like String so that we can concatenate two strings by just using +.
I think you are confused here:
the operator<< is actually a friend function defined in ostream and you are making use of that.
It’s true that an operator <<
is defined inside class std::ostream
. In fact, there are several versions defined inside it. But those don’t concern us. Furthermore, they are not friend
functions: By definition, a friend
function is defined outside the class it is a friend of.
But this is all unrelated to the function you defined, because your operator <<
function is a separate overload which is being called when you pass an object of your type as the second argument to an invocation of <<
(the first argument being a std::ostream&
).
As TemplateRex has explained, the exact way of finding the appropriate function is via argument-dependent lookup. But more fundamentally, you simply need to know that there are two ways of defining a binary operator for given argument types A
and B
:
A
, and having only one argument, of type B
A
and B
.Both these definitions are candidate functions when you use the operator. (But there are several operators, such as copy assignment which can only be defined inside the class, not outside). So, coming back to your question:
how exactly is this function being defined in ostream? Since this function takes 2 parameters and the second parameter is user-defined, there is no way that they can guess what is coming there
The answer is that it is not defined in ostream
. The only definition is yours, and it’s outside.
C++ functions can be overloaded, i.e. multiple functions with the same name but taking different arguments can co-exist. The compiler goes through a three-step process of Name Lookup, Argument-Deduction and Overload Resolution. At the end of that, only a single function overload can survive as the best match. A gentle introduction to these concepts can be gotten from the first three videos in the series Core C++ by Stephan T. Lavavej.
A common case is a user-defined class S
inside a namespace N
(which could be the global one) with an operator<<(ostream&, S const&)
overload inside that same namespace.
namespace N {
class S
{
// bla
};
std::ostream& operator<<(std::ostream& os, S& const& obj)
{
// print in terms of public interface of S
// (else, deckare this a friend function inside S)
return os;
}
} // N
int main()
{
std::cout << S(); // operator<<(ostream&, S const&) is the best match
}
Name lookup is subtle, in this case it works through so-called argument dependent lookup, which looks in namespaces associated to function arguments. For the above code, these namespace are std
(where all the Standard Library functions live) and N
(where your overload operator<<(ostream&, S const&)
lives). Argument deduction will deduce the correct type, and overload resolution will find that your overload is the best match (in this case, in all likelihood the only match).
Hence, the ability to print your user-defined types using "native" syntax.
NOTE: in this case, it's not called the "left-shift" operator but the "stream insertion" operator, even though the latter has the same lexical form as the former.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With