Extending the iostream library
Cay S. Horstmann
Thanks to James K. Lowden for the conversion to HTML.
This article appeared originally in C++ Report, Volume 6, Number 4, May 1994.
With the first release of C++ came two libraries, complex.h and stream.h. The complex library makes
perfect sense, at least to that mandarin minority of programmers dealing with complex numbers. After all,
overloading of the arithmetic operators is just what is needed to handle complex numbers as easily as real
numbers. But did the streams really answer a pressing need? Most C programmers are perfectly happy with
stdio.h. In fact, I must confess that my original attraction to C was not caused by its charming syntax but
because stdio.h file handling was far easier than in Pascal. Many C++ programmers embrace classes and
virtual functions but stick with stdio.h for input and output.
Why don't streams get more respect? In a nutshell, formatting. With printf, formatting is phenomenally
printf("(%8.2f,%8.2f)\n", x, y);
For a long time, it was a well-kept secret that you can do formatting with streams at all. The first
description of stream formatting that I came across is [1 , appendix A]. I eventually figured out that the
stream equivalent of the printf statement above is
cout << "(" << setprecision(2) << setiosflags(ios::fixed)
<< setw(8) << x << "," << setw(8) << y << ")" << endl;
This revelation did nothing to increase my enthusiasm for streams.
Of course streams do have two advantages. They are typesafe. You can't do dumb mistakes like
scanf("%f", &x); // double* requires %lf
And they are extensible. To provide input and output for complex numbers, one merely needs to implement
istream& operator>>(istream&, Complex&);
Now complex numbers can be extracted from, and inserted to, any kind of stream, such as file and string
streams, and not just cin and cout.
In fact, streams are extensible in another way. Not only can input and output be defined for new data types,
but new stream classes that interact with new devices can be derived from the basic stream classes. In this
regard, the stream library functions as a framework for new stream classes. Until very recently, deriving
new stream classes was a very black art that required reading through the source code for the stream library
for guidance. A brand new book , devoted entirely to the stream library, removes much of that challenge.
In this article, I present an overview over the formatting and buffering architecture of streams and give two
practical applications. I describe a manipulator that makes formatting much easier. For example, the print
statement above becomes
cout << "(" << setformat("%8.2f") << x << ","
<< setformat("8.2f") << y << ")" << endl;
which is almost tolerable. And I derive a new stream class for Microsoft Windows programming that routes
diagnostic messages into a special debug window. You use it just like any other ostream.