10.5 Overloading the Binary Stream Insertion and Stream Extraction Operators

You can input and output fundamental-type data using the stream extraction operator >> and the stream insertion operator <<, respectively. The C++ class libraries overload these binary operators for each fundamental type, including pointers and char * strings. You can also overload these operators to perform input and output for your own types. The program of Figs. 10.310.5 overloads these operators to input PhoneNumber objects in the format


(555) 555-5555

and to output them in the format


Area code: 555
Exchange: 555
Line: 5555
(555) 555-5555

The program assumes telephone numbers are input correctly.

Fig. 10.3 PhoneNumber class with overloaded stream insertion and stream extraction operators as friend functions.

Alternate View

 1   // Fig. 10.3: PhoneNumber.h
 2   // PhoneNumber class definition
 3   #ifndef PHONENUMBER_H
 4   #define PHONENUMBER_H
 5
 6   #include <iostream>
 7   #include <string>
 8
 9   class PhoneNumber {
10      friend std::ostream& operator<<(std::ostream&, const PhoneNumber&);
11      friend std::istream& operator>>(std::istream&, PhoneNumber&);      
12   private:
13      std::string areaCode; // 3-digit area code
14      std::string exchange; // 3-digit exchange
15      std::string line; // 4-digit line
16   };
17
18   #endif

Fig. 10.4 Overloaded stream insertion and stream extraction operators for class PhoneNumber.

Alternate View

 1   // Fig. 10.4: PhoneNumber.cpp
 2   // Overloaded stream insertion and stream extraction operators
 3   // for class PhoneNumber.
 4   #include <iomanip>
 5   #include "PhoneNumber.h"
 6   using namespace std;
 7
 8   // overloaded stream insertion operator; cannot be a member function
 9   // if we would like to invoke it with cout << somePhoneNumber;
10   ostream& operator<<(ostream& output, const PhoneNumber& number) {
11      output << "Area code: " << number.areaCode << "
Exchange: "
12         << number.exchange << "
Line: " << number.line << "
"
13         << "(" << number.areaCode << ") " << number.exchange << "-"
14         << number.line << "
";
15      return output; // enables cout << a << b << c;
16   }
17
18   // overloaded stream extraction operator; cannot be a member function
19   // if we would like to invoke it with cin >> somePhoneNumber;
20   istream& operator>>(istream& input, PhoneNumber& number) {
21      input.ignore(); // skip (
22      input >> setw(3) >> number.areaCode; // input area code
23      input.ignore(2); // skip ) and space
24      input >> setw(3) >> number.exchange; // input exchange
25      input.ignore(); // skip dash (-)
26      input >> setw(4) >> number.line; // input line
27      return input; // enables cin >> a >> b >> c;
28   }

Fig. 10.5 Overloaded stream insertion and stream extraction operators.

Alternate View

 1   // Fig. 10.5: fig10_05.cpp
 2   // Demonstrating class PhoneNumber's overloaded stream insertion
 3   // and stream extraction operators.
 4   #include <iostream>
 5   #include "PhoneNumber.h"
 6   using namespace std;
 7
 8   int main() {
 9      PhoneNumber phone; // create object phone
10
11      cout << "Enter phone number in the form (555) 555-5555:" << endl;
12
13      // cin >> phone invokes operator>> by implicitly issuing
14      // the non-member function call operator>>(cin, phone)  
15      cin >> phone;                                           
16
17      cout << "
The phone number entered was:
";
18
19      // cout << phone invokes operator<< by implicitly issuing
20      // the non-member function call operator<<(cout, phone)  
21      cout << phone << endl;                                   
22   }

Enter phone number in the form (555) 555-5555:
(800) 555-1212

The phone number entered was:
Area code: 800
Exchange: 555
Line: 1212
(800) 555-1212

Overloading the Stream Extraction (>>) Operator

The stream extraction operator function operator>> (Fig. 10.4, lines 20–28) takes the istream reference input and the PhoneNumber reference number as arguments and returns an istream reference. The function inputs phone numbers of the form (555) 555-5555 into objects of class PhoneNumber. When the compiler sees the expression


cin >> phone

in line 15 of Fig. 10.5, the compiler generates the non-member function call


operator>>(cin, phone);

When this call executes, reference parameter input (Fig. 10.4, line 20) becomes an alias for cin and reference parameter number becomes an alias for phone.

The operator function reads as strings the three parts of the telephone number into the areaCode (line 22), exchange (line 24) and line (line 26) data members of the PhoneNumber object referenced by parameter number—the function is a friend of the class, so it can access a PhoneNumber’s private members. Stream manipulator setw limits the number of characters read into each string. When used with cin and strings, setw restricts the number of characters read to the number of characters specified by its argument (i.e., setw(3) allows three characters to be read). The parentheses, space and dash characters are skipped by calling istream member function ignore (Fig. 10.4, lines 21, 23 and 25), which discards the specified number of characters in the input stream (one character by default).

Function operator>> returns istream reference input (the alias for cin). This enables input operations on PhoneNumber objects to be cascaded with input operations on other PhoneNumber objects or other data types. For example, a program can input two PhoneNumber objects in one statement as follows:


cin >> phone1 >> phone2;

First, the expression cin >> phone1 executes by making the non-member function call


operator>>(cin, phone1);

This call then returns a reference to cin as the value of cin >> phone1, so the remaining portion of the expression is interpreted as cin >> phone2. This executes by making the non-member function call


operator>>(cin, phone2);

Good Programming Practice 10.1

Overloaded operators should mimic the functionality of their built-in counterparts—e.g., the + operator should perform addition, not subtraction. Avoid excessive or inconsistent use of operator overloading, as this can make a program cryptic and difficult to read.

Overloading the Stream Insertion (<<) Operator

The stream insertion operator function (Fig. 10.4, lines 10–16) takes an ostream reference (output) and a const PhoneNumber reference (number) as arguments and returns an ostream reference. Function operator<< displays objects of type PhoneNumber. When the compiler sees the expression


cout << phone

in line 21 of Fig. 10.5, the compiler generates the non-member function call


operator<<(cout, phone);

Function operator<< displays the parts of the telephone number as strings, because they’re stored as string objects. To prove that the stream extraction operator read the individual pieces of a PhoneNumber properly, function operator<< displays each data member separately, then displays a properly formatted phone number.

Overloaded Operators as Non-Member friend Functions

The functions operator>> and operator<< are declared in PhoneNumber as non-member, friend functions (Fig. 10.3, lines 10–11). They’re non-member functions because the object of class PhoneNumber must be the operator’s right operand. If these were to be PhoneNumber member functions, the following awkward statements would have to be used to output and input a PhoneNumber, respectively:


phone << cout;
phone >> cin;

Such statements would be confusing to most C++ programmers, who are familiar with cout and cin appearing as the left operands of these operators. Overloaded operator functions for binary operators can be member functions only when the left operand is an object of the class in which the function is a member.

Overloaded input and output operators are declared as friends if they need to access non-public class members directly for performance or because the class may not offer appropriate get functions. Also, the PhoneNumber reference in function operator<<’s parameter list (Fig. 10.4, line 10) is const, because the function simply outputs a PhoneNumber, and the PhoneNumber reference in function operator>>’s parameter list (line 20) is non-const, because the function must modify the PhoneNumber object to store the telephone number.

Software Engineering Observation 10.2

New input/output capabilities for user-defined types are added to C++ without modifying standard input/output library classes. This is another example of C++’s extensibility.

The overloaded stream insertion operator (<<) is used in an expression in which the left operand has type ostream&, as in cout << classObject. To use the operator in this manner where the right operand is an object of a user-defined class, it must be overloaded as a non-member function. To be a member function, operator << would have to be a member of class ostream. This is not possible for user-defined classes, since we are not allowed to modify C++ Standard Library classes. Similarly, the overloaded stream extraction operator (>>) is used in an expression in which the left operand has the type istream&, as in cin >> classObject, and the right operand is an object of a user-defined class, so it, too, must be a non-member function. Also, each of these overloaded operator functions may require access to the private data members of the class object being output or input, so these overloaded operator functions can be made friend functions of the class for performance reasons.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset