twomers: the first prints the address of the char* pointer, the second the value of the char* pointer, i.e. the address of the string.
In short, all the sites that claim equivalency are quite simply wrong. Using an operator overloading function directly and using the overloaded operator are not equivalent, simply because there are two ways of overloading most operators, and only using the operator automatically chooses between them. Directly calling the function when in reality, the operator is implemented the other way round, leads to compile errors if you're lucky, and to unexpected results in this particular case, because there are so many overloads of <<.
In other words, cout itself contains this member function:
Code:
class basic_ostream {
// ...
self_type &operator <<(const void *); // Prints an address
};
In addition, there is this free function also overloading <<: (omitting template stuff for clarity)
Code:
ostream & operator <<(ostream &s, const char *sz); // Prints the string
Now, let's check it out.
Code:
const char *strlit = "Hello, World!";
cout << strlit; // 1
operator<<(cout, strlit); // 2
cout.operator<<(strlit); // 3
1) Here the overloaded operator is used. The compiler collects all functions that overload << and finds these (among many others which are not relevant):
ostream::operator<<(const void*)
operator<<(ostream&, const char*)
The call signature is
(ostream lvalue) << (const char* lvalue)
It chooses the function that most closely fits the supplied types, which is the free function. So you get the string.
2) Here, you explicitely call a free function called operator<<. So the compiler collects all free functions by that name. It might, for example, find these:
operator<<(ostream&, const char*)
operator<<(ostream&, const string&)
operator<<(ostream&, const complex&)
The call signature is
operator<<(ostream lvalue, const char* lvalue)
Again, the compiler chooses the const char* variant as the best fit.
3) This time, you request a member of ostream by the name of operator<<. The compiler again collects the overload set, which contains among others these:
ostream::operator<<(int)
ostream::operator<<(double)
ostream::operator<<(const void*)
The call signature is
(ostream lvalue) . ostream::operator<<(const char* lvalue)
No direct match this time, so the conversions are considered. The simplest conversion (in fact, in this overload set, the only possible one) turns out to be the const void* one, so it is chosen.
As you can see, they're not at all equivalent.