Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Misunderstanding about ostream class and operator <<

Tags:

c++

iostream

After looking at the ostream::operator << c++ reference,

I noticed the following declarations:

ostream& operator<< (bool val);
ostream& operator<< (short val);
ostream& operator<< (unsigned short val);
ostream& operator<< (int val);
ostream& operator<< (unsigned int val);
ostream& operator<< (long val);
ostream& operator<< (unsigned long val);
ostream& operator<< (float val);
ostream& operator<< (double val);
ostream& operator<< (long double val);
ostream& operator<< (void* val);
ostream& operator<< (streambuf* sb );
ostream& operator<< (ostream& (*pf)(ostream&));
ostream& operator<< (ios& (*pf)(ios&));
ostream& operator<< (ios_base& (*pf)(ios_base&));

But then I found out that there are also the following declarations:

ostream& operator<< (ostream& os, char c);
ostream& operator<< (ostream& os, signed char c);
ostream& operator<< (ostream& os, unsigned char c);
ostream& operator<< (ostream& os, const char* s);
ostream& operator<< (ostream& os, const signed char* s);
ostream& operator<< (ostream& os, const unsigned char* s);

Why are the char/string output operators not member functions?

like image 414
Rouki Avatar asked Apr 15 '13 12:04

Rouki


3 Answers

The first group of operators are members of the stream class.

Most operator overloads, like those in the second group, are not.


As to the why, it is likely just a historical accident. The operators for built in types can be added to the stream classes, and obviously they were (long before C++ was standardized). The standard just documents existing practice here.

Operators for user defined types obviously cannot be added to the stream classes, so they are implemented as free functions.

In retrospect it would have been more consistent to make all the operators free functions, but that would possibly break some old programs.

like image 166
Bo Persson Avatar answered Nov 09 '22 18:11

Bo Persson


The others have described the differences, here's my shot at why they are split.

The non-member versions, which take char variants as parameters are specialized depending on type of the target stream's base character type and handled depending on locale, because standard defines specific behavior (o << '1' has different behavior than oo << 33, it has to be handled properly if o is basic_ostream<wchar_t>, etc).

E.g. char writen to basic_ostream<wchar_t> is widened, while if written to basic_ostream<char> it is not (27.6.2.5.4). So actually there are multiple overloads of operator<<, e.g:

basic_ostream<_Elem, _Traits>& operator<<(basic_ostream<_Elem, _Traits>& _Ostr, char _Ch)
basic_ostream<char, _Traits>& <<(basic_ostream<char, _Traits>& _Ostr, char _Ch)

If they were defined as member functions, you wouldn't be able to specialize them like that as you would have to partially specialize the whole class, not just a single member, since standard doesn't allow partial specialization of member functions.

like image 22
Zdeslav Vojkovic Avatar answered Nov 09 '22 20:11

Zdeslav Vojkovic


There are actually two families of overloader operator<<s, as you have found out.

One family is the overloaded member ostream::operator<< (which gets the ostream reference implicitly as the this pointer) and the other family is the overloaded free function operator<< which gets the ostream reference explicitly as an argument.

When you want to add streaming capability to a class of your own, you add a free function.

like image 1
Jon Avatar answered Nov 09 '22 18:11

Jon