Streams provide a way to read and write potentially unlimited information and working with them is very different than data types representing a single variable.

I’ve described streams so far with an example of a stream of water flowing by and it’s time to go a little deeper into that understanding. Why are they useful and how do you use them?

You’ll likely work with streams when dealing with files but there are other places where a stream makes sense. Anytime you have a series or a string of data where one byte comes after another, then a stream might help. It doesn’t matter if the stream has a fixed beginning and end or if it can go on forever.

When dealing with this type of data which is more of a flow of data, it helps to have a common and accepted way to read, write, and manipulate the data. Streams have been around for a long time even before object-oriented programming. In the C language you open a file on disk with the fopen method and it returns to you a pointer to a FILE struct. What’s inside this FILE struct is not for your program to use in any way. All you do is pass the pointer to other methods to read or write information and later to close the file when you’re done. The other methods use the information in the FILE struct to know which file on disk is being worked on and where in the file the data should be read from or written to.

This is a stream because as you read or write information, the FILE struct is updated with the new position. What I mean is that if you read 5 bytes, then the current position within the file is advanced by 5 bytes. That way, when you read another 5 bytes, you get the next 5 bytes instead of reading the same bytes again. It’s as if the water in the stream has flowed past you a bit. It’s different than a real stream because it waits for you to read again before advancing. A real stream just keeps on flowing.

As you can see, this concept makes it easy to read and write information to and from files because you don’t have to worry about where you are in the file. The stream keeps track of that for you.

The C++ language takes streams to a whole new level and makes them object-oriented. You might wonder why object-oriented streams are so special if streams have been around for so long. Well, you can work with them much easier and extend them in ways not possible with the older streams. They use operator overloading instead of methods with parameters to make sure that you don’t get anything mixed up. And they’re extensible and make it easy for your custom classes to blend right into the code just like the built-in types. The compiler knows all about the types of your variables and makes sure to call the correct overloaded operator.

When you want to extend this to work with your own types, just provide your own overloaded shift operators, either for input or for output, that work with your new type. And the compiler will call your versions when needed.