### Defining an Output Operator for a Class Type

An output operator is predefined for all built-in C++ types. If you create a class type and want to write output of that class type to a file or to any of the predefined output streams, you need to define an output operator for that class's type. You define an ostream output operator that has the class type as its second argument. For example:

    myclass.h

    #include <iostream.h>

    class PhoneNumber {
       public:
          int AreaCode;
          int Exchange;
          int Local;
    // Copy Constructor:
          PhoneNumber(int ac, int ex, int lc) :
          AreaCode(ac), Exchange(ex), Local(lc) {}
    //... Other member functions
    };

    ostream& operator<< (ostream& aStream, PhoneNumber aPhoneNum) {
       aStream << "(" << aPhoneNum.AreaCode << ") "
               << aPhoneNum.Exchange << "-"
               << aPhoneNum.Local << '\n';
       return aStream;
       }

The output operator must have the following characteristics:

- Its return type should be a reference to an ostream.
- Its first argument must be a reference to an ostream. This argument must be used as the function's return value.
- Its second argument must be of the class type for which the operator is being defined.

You can define the code performing the actual output any way you like. In the above example, output is accomplished for the class type by placing in the output stream all data members of the class, along with parentheses around the area code, a space before the exchange, and a hyphen between the exchange and the local.

#### Class Output Operators and the Format State

You should consider checking the state of applicable format flags for any stream you perform output to in a class output operator. At the very least, if you change the format state in your class output operator, before your operator returns it should reset the format state to what it was on entry to the operator. For example, if you design an output operator to always write floating-point numbers at a given precision, you should save the precision in a temporary on entry to your operator, then change the precision and do your output, and reset the precision before returning.

The ios::x_width setting determines the field width for output. Because ios::x_width is reset after each insertion into an output stream (including insertions within class output operators you define), you may want to check the setting of ios::x_width and duplicate it for each output your operator performs. Consider the following example, in which class Coord_3D defines a three-dimensional co-ordinate system. If the function requesting output sets the stream's width to a given value before the output operator for Coord_3D is invoked, the output operator applies that width to each of the three co-ordinates being output. (Note that it lets the width reset after the third output so that, from the client code's perspective, ios::x_width is reset by the output operation, as it would be for built-in types such as float).

    //Setting the output width in a class output operator

    #include <iostream.h>
    #include <iomanip.h>

    class Coord_3D {
       public:
          double X,Y,Z;
          Coord_3D(double x, double y, double z) : X(x), Y(y), Z(z) {}
          };

    ostream& operator << (ostream& aStream, Coord_3D coord) {
       int startingWidth=aStream.width();
       aStream << coord.X
    #ifndef NOSETW
             << setw(startingWidth)    // set width again
    #endif
             << coord.Y
    #ifndef NOSETW
             << setw(startingWidth)    // set width again
    #endif
             << coord.Z;
       return aStream;
       }

    void main() {
       Coord_3D MyCoord(38.162168,1773.59,17293.12);
       cout << setw(17) << MyCoord << '\n'
            << setw(11) << MyCoord << endl;
       }

If you add #define NOSETW to prevent the two lines containing setw() in the output operator definition from being compiled, the program produces the output shown below. Notice that only the first data member of class Coord_3D is formatted to the desired width.

          38.16221773.5917293.1
    38.16221773.5917293.1

If you do not comment out the lines containing setw(), all three data members are formatted to the desired width, as shown below:

          38.1622          1773.59        17293.1
    38.1622    1773.59    17293.1

Changing the Formatting of Stream Output