11.5. operator<< And operator>>

Time: 00:05:05 | Download: Large Small | Streaming | Slides (PDF)
Review

Creating and using the inserter and extractor functions builds on concepts introduced in previous chapters. Please review the following as needed:

Overloaded operators are "overloaded" because they define a new meaning for an operator to which the language has already assigned a meaning. Like overloaded functions, we can overload an operator many times, but we must observe two requirements. First, we may only overload an operator in the context of a new class, and second, at least one operand must be unique to distinguish the operator from the others. While these requirements apply to all overloaded operators, understanding them is especially important for using operator<< and operator>>.

Remember

operator<< and operator>> use two <iostream> classes: istream and ostream. So, when a class overloads either operator, we must also add

#include <iostream>
using namespace std;
to the header file before the class specification.

Revisiting Arguments and Overloaded Functions

Let's take an incremental approach transitioning from "regular" functions to operators to help us understand how operator<< and operator>> work. First, we'll explore two functions overloaded on a single parameter followed by functions overloaded on two parameters.

print(int x)
{
	. . .
}
print(double x)
{
	. . .
}
(a)(b)
print(ostream& out, int x)
{
	. . .
}
print(ostream& out, double x)
{
	. . .
}
(c)(d)
Overloaded functions. When the program calls an overloaded function, the compiler is able to tell which function to bind the call to by match the data type of of the arguments appearing in the function call to the parameters in the function prototype (or declaration). If the overloaded functions have multiple arguments, one unique argument is sufficient to distinguish between any number of functions with the same name.
  1. print(3); - The value 3 is processed as an integer, which matches the first version of the function.
  2. print(3.14); - 3.14 is a double and so matches the second function.
  3. print(cout, 5); - these parameters match the third function. cout, an instance of a class named ostream, sends output to the console.
  4. print(cout, 5.7); - these parameters match the fourth function.

Examples (c) and (d) are are similar to how operator<< is implemented in the ostream class included with the iostream header file. Other classes may also overload the inserter operator and prototype the function in their header file.

The C++ I/O Operators

class ostream
{
    public:
        friend ostream & operator<<(ostream &, char);
        friend ostream & operator<<(ostream &, char *);
        friend ostream & operator<<(ostream &, short);
        friend ostream & operator<<(ostream &, int);
        friend ostream & operator<<(ostream &, long);
        friend ostream & operator<<(ostream &, float);
        friend ostream & operator<<(ostream &, double);
};
class istream
{
    public:
        friend istream & operator>>(istream &, char &);
        friend istream & operator>>(istream &, char *);
        friend istream & operator>>(istream &, short &);
        friend istream & operator>>(istream &, int &);
        friend istream & operator>>(istream &, long &);
        friend istream & operator>>(istream &, float &);
        friend istream & operator>>(istream &, double &);
};
(a)(b)
class string
{
  public:
     friend ostream& operator<<(ostream& out, string& s);
     friend istream& operator>>(istream& in, string& s);
};
class fraction
{
  public:
     friend ostream& operator<<(ostream& out, fraction& f);
     friend istream& operator>>(istream& in, fraction& f);
};
(c)(d)
A picture illustrating a program sending output to the console through an 'ostream' object. The output is the result of evaluating any valid expression. A picture illustrating a program reading data from the console into a variable through an 'istream object.'
(e.i)(e.ii)
The inserter and extractor operator prototypes in <iostram>.
  1. Some of the overloaded inserter operators prototyped in <iostream> (some detail is elided for simplicity). With the exception of C-strings, all primitive data type arguments are passed by value. The function stores or returns the value read from the input stream into the second argument, which requires that the argument be passed by reference
  2. Some of the overloaded extractor operators prototyped in <iostream>
  3. Standard or library classes often overload the inserter and extractor operators as illustrated by the string class. Objects are typically passed by reference
  4. Application programmers can also overload the inserter and extractor operators when doing so is appropriate. Overloaded versions of the inserter and extractor operators for the fraction class are illustrated here
  5. The stream objects are like a garden hose that carries a stream of bytes:
    1. The "faucet" or source end of an ostream attaches to an expression in the program; the "sprayer" or destination end attaches to a console window
    2. The "faucet" or source end of an istream attaches to the keyboard; the "sprayer" or destination end attaches to a variable in the program