11.5.1. Overloading operator<< and operator>>

Programmers frequently overload the inserter (or insertion) and extractor (or extraction) operators because they are the main output and input functions for C++ programs. Each function follows a fixed pattern. While the pattern is rigid and unchanging, some elements are flexible and left to the programmer to name. Specifically, programmers may choose the parameter names, and the class for which the operator is overloaded determines the type-name of the second parameter. Everything else in the pattern is fixed and required. It's easier to see the pattern with a simple example.

friend ostream& operator<<(ostream& out, fraction & f)
{
	// format and print member variables of f
	return out;
}

friend istream& operator>>(istream& in, fraction & f)
{
	// read member variables of f
	return in;
}
Patterns in operator<< and operator>>. The patterns illustrated here assume that the operator definitions are placed inside the class (i.e., not just prototyped in the class). We must keep prototypes in the class, but we can move the function bodies out of the class by dropping the friend keyword.

operator<< And operator>> Examples

We finish off this section with complete implementations of operator<< and operator>> for the fraction class:

class fraction
{
    private:
        int numerator;
        int denominator;

    public:
				.
				.
				.
        friend ostream& operator<<(ostream& out, fraction& f);
        friend istream& operator>>(istream& in, fraction& f);
				.
				.
				.
};
ostream& operator<<(ostream& out, fraction& f)
{
    out << f.denominator << "/" << f.numerator;

    return out;
}

istream& operator>>(istream& in, fraction& f)
{
    cout << "Please enter the numerator part: ";
    in >> f.numerator;
    cout << "Please enter the denominator part: ";
    in >> f.denominator;

    return in;
}
(a)(b)
fraction left;
fraction right;

cin >> left;
cin >> right;
fraction result = left + right;
cout << result << endl;
A picture showing two mappings. First, 'cin >> left' maps to 'operator>>(in,f)'. Second, 'cout << result' maps to 'operator<<(out,f)'. The mapping correspond to the code illustrated in (b) and (c).
(c)(d)
Complete operator<< and operator>> examples. In this example the operator functions are prototyped in the class but are defined outside the class. The friend keyword is always a part of the function declaration (i.e., the prototype).
  1. Prototypes for the inserter and extractor operators; the class specification is typically placed in a header file
  2. The definitions of the inserter and extractor functions; function definitions are often placed in a source code file; the friend keyword does not appear with the definition
  3. Overloaded operators are called using an operator syntax with left and right hand operands
  4. operator>>
    cin is passed into the first parameter, in, and left (referring to the left-hand operand of + in (c)) is passed to f
    operator<<
    cout is passed to the second parameter, out, and result is passed to f
Prompts In operator>>

The example above illustrates "Please enter . . ." prompts in the extractor operator, but is doing so appropriate? Sure, so long as the operator>> is only used to read input from the console, the prompts work well and are appropriate. But by the end of the semester, we will learn that an istream can represent many input sources. For example, it is possible to use istreams and operator>> to read input from files. So what happens if the operator>> is nested inside of some kind of loop that ultimately reads megabytes of data?

Writing output to the console is a relatively slow process. So, even if we don't mind the "clutter" appearing on the console screen for each prompt, the mere fact that a program repeatedly writes a prompt can slow it down. I recommend putting any input prompts in the client code. The client "knows" the data source and whether to prompt or not.