A stream is an object that represents a sequence of characters. Streams can be read for input, or written for output. Input streams are instances of "subclasses" of istream, and output streams are instances of "subclasses" of ostream.
(Don't think too hard about subclasses now, we'll cover them soon. For now, an instance of a subclass of a class C can be treated just like an instance of C.)
By encapsulating notion of an output or input sequence in a stream, we achieve several goals at once; among them:
- Unlike use of printf or scanf, use of a stream object does not always require that you provide format specifiers:
fprintf(stdout, "%d %s\n", 5, "foo"); /* C way */ cout << 5 << ' ' << "foo" << endl; // C++ way - Output using C++ streams is type safe---there is no possibility of attempting to output a character as an integer, or vice versa, without explicit casting.
- The idea of a stream is abstracted from any particular kind of stream. All streams share a common interface and can be used uniformly. The user can even define custom streams, e.g. an output stream that compresses its data and sends it over the network.
Unfortunately, to fully understand C++ streams, you need to know virtually everything there is to know about C++. Fortunately, you don't have to fully understand how the streams work in order to use them.
Standard streams
You are already familiar with at least two of the three standard stream objects. The streams cout, cerr, and cin are objects that are created and initialized exactly once by the runtime system. The way this happens is deep magic that we need not go into here.
You might ask, "Well, if these streams are objects, they must be instances of a class." Yes, in fact they are instances of a class. However, that class is system-dependent, and the only guarantee is that they will implement the ostream and istream interfaces.