The reason is a combination of several facts.
-
You want to be able to chain input and output operations as in
in >> x >> y; out << z << std::precision(10) << t << std::endl;
so you must return something that allows
operator<<
again. -
Since you want your operator to work on any
istream
, i.e. any object derived fromstd::istream
, you cannot defineoperator<<(istream_type, object); // take istream by value
since this would only work for the specific istream type
istream_type
, but not for a genericistream
. For that one must use polymorphism, i.e. either take a reference or a pointer (which will be a reference or pointer to a class derived fromstd::istream
). -
Since you only have a reference to the istream, you cannot return the istream object itself (which may be of a type not even defined at the point of the definition of
operator<<
) but only the reference you’ve got.One could get around this restriction by defining
operator<<
atemplate
and take and return theistream_type
by value, but that requires theistream
type to have a copy constructor, which it may well not have for good reasons. -
In order to envoke polymorphism one could, in principle, use pointers (to streams) rather than references. However,
operator<<(stream*,const char*)
is
not allowed in C++ (at least one operand must be of class or enumeration type).Thus, with stream pointers one must use function-call syntax and you’re back with C-style
fprintf(stream*, args...)
.Moreover, pointers can be null or dangling, which in fact is their default state (when declared without initializer), while a reference can be assumed to be valid (it cannot be declared without initializer).