Previous Table of Contents Next


The direction of the arrows may seem arbitrary at first. Think about the direction in which data flows, and you’ll remember which way the arrows should go. Refer to Figure 4.1 for an illustration.

The stream operators look suspiciously like the left and right bit shift operators. In fact, that’s exactly what they are! This use of left and right shift is an example of operator overloading, a technique that Chapter 7 discusses in detail. The behavior of the shift operators is redefined for istream and ostream classes (these classes are defined in IOSTREAM.H) so that the shift operators become “put to” operators for these classes.
Programmers who overload operators usually strive to maintain the operator’s general meaning. For example, you’d want the plus sign (+) to indicate some kind of addition operation in any situation (although what it means to add two strings is quite different from what it means to add two numbers). The use of << and >> as stream operators is an exception to this general design principle. Sending data to and from I/O streams has nothing to do with shifting bits. The << and >> operators were overloaded for stream operations because they had syntactic advantages as well as the advantage of being visually appropriate (they suggest data flows).

In the example at the beginning of this section, the last two lines can be rewritten as one. These two lines print two pieces of data—a string and a number:

    cout << “The total is ”;
    cout << a + b;

The two lines can be replaced by the following, more compact statement:

    cout << “The total is ” << a + b;

The associativity of the shift operators is left-to-right, meaning that the following expression is evaluated first:

cout << “The total is ”

As is common in C and C++, this expression does two things: it sends the string to cout (this is its side effect, if you will), and then it evaluates to a value. It so happens that expressions that combine cout with a value always evaluate to cout itself. This is true regardless of the actual output string. Evaluating to cout is, in effect, a syntactic trick that enables you to output or input any number of items using a single statement. You can perform the same trick to input several numbers with one statement, because each subexpression evaluates to cin. For example:

cin >> a >> b >> c >> n;

Figure 4.2 shows how C++ breaks down this statement, each time performing an input operation as the expression’s side effect.


Figure 4.2.  How C++ evaluates multiple input to cin.

The Joy of Formatting

One of the attractions of using cin and cout, especially for beginners, is that you don’t have to use the funny symbols that you use with printf and scanf. Each data type is recognized by the operator, and each data type has a reasonable default behavior. For example, by default the following statement prints the decimal representation of n, which is the most common format.

cout << n;

But what if you want to print in hexadecimal or octal format? For example, you could do the following with the printf statement:

int n = 16;
printf(“n is %x hex, %o octal, and %d decimal.”, n, n,
   n);

This code prints the following text:

n is 10 hex, 20 octal, and 16 decimal.

The following example, using the C++ stream operators, prints the same results:

int n = 16;
cout << “n is ” << hex << n << “ hex, ”;
cout << oct << n << “ octal, and ”;
cout << dec << n << “ decimal. ”;

Just what are hex, oct, and dec? They’re objects (which you’ll learn more about in the next chapter). When sent as “output” to cout or as “input” to cin, they have the effect of changing the integer format of the stream until further notice.

When complex formatting is involved, using the C++ stream objects makes for less readable code than using good old reliable printf and scanf. This is especially true if you have a background in C.

On the side of the stream operators, however, there is a pleasant alternative. Instead of using objects such as hex, oct, and dec, you can use the format function (declared in IOSTREAM.H), which duplicates the behavior of printf format characters and returns a string that can be passed to cout. For example:

int n = 16;
cout << format(“n is %x hex, %o octal, and %d decimal.”,
              n, n, n);

Line-Based Input with STDIO.H

Some C++ programmers prefer to use the I/O library functions declared in STDIO.H and inherited from C. If you have a C programming background and are accustomed to using these functions or if you are maintaining legacy code written in C, it may make sense to continue using them. You’ll probably encounter problems if you attempt to mix different input techniques or different output techniques. Therefore, if you have existing code, it may be best to continue using STDIO.H functions throughout the program.


Previous Table of Contents Next