2.6 Basic Input/Output


Stream Operators

Operator overloading is the basis for input and output (I/O) in C++. Overloading is useful for I/O because the same operation (input or output) is being performed, but on different types. This is exactly the situation that operator overloading is meant to address. In C++, there is an overloaded operator that is programmed to handle I/O for each built-in type. Thus, the same operator is used for all types. At compile time the type of the data being input or output determines which of the overloaded operations will be used.

The operator that is overloaded to handle I/O is not an operator with a name like "input" or "output," but is a symbolic operator. The symbolic operator << is used to represent output and the symbolic operator >> is used to represent input. It will be seen later that most of the C++ operators (e.g., +, -, *, /, <, >, =, ==) can be overloaded.

In C++, I/O is based on a stream model. In a stream model the input data is viewed as a continuous stream of data that flows from a source into the the sequence of variables presented to the input stream. The type of the variables determines how the input stream is interpreted to provide values for the variables. On output, the values of variables flow into a (logically) continuous stream to the destination. The source (for input) and the destination (for output) may be the user or a file.

Interactive stream I/O is provided by two classes:

      class istream {...};          // stream input
       class ostream {...};          // stream output

These classes use elements of the C++ language that have not been covered yet. The study of the C++ I/O classes is taken up later. For now, a minimal understanding of how to use these classes is sufficient.

The standard C++ I/O library includes two predefined variables:

       istream cin;            // interactive input
        ostream cout;           // interactive output

These variables are declared in the file "stream.h" that can be included in a program using the include directive:

       #include <stream.h>

Any single built-in type can be output by the << operator as shown in the following example:

       cout << 10;             // output an integer
        cout << 1.234;          // output a float
        cout << 'x';            // output a character
        cout << "Hello World."  // output a string
        cout << '\n';           // output a "newline" character

Because output is viewed as a stream, the five statements above can be reduced to the following single line:

       cout <<  10  << 1.234 << 'x' << "Hello World." << '\n';

The values are entered into the output stream in a left-to-right order. For readability, blanks are often inserted into the output stream as in this example:

       cout << 10 << "  " << 20 << '\n';

which inserts two blanks between the 10 and the 20. The newline character ('\n') can be used to end a line of output. As an alternative to the newline character, the standard I/O library defines a symbol "endl" (for "end line") that will also end the current line of output. The above example can thus be rewritten as:

       cout << 10 << "  " << 20 << endl;

using the endl symbol.

Notice that there is no relationship between the number of lines of code that produce output and the number of lines of text that appear in the output. For example, the following three code fragments each output the same two lines of text:

  (1)  cout << 10;
        cout << endl;
        cout << 20 << endl;

        
   (2)  cout << 10 << endl << 20 << endl;

   (3)  cout 10 << endl << 20;
        cout << endl;

The values of variables can be output using the stream operators as shown in the following example:

       int x, y;               // two integers
        char c;                 // a character
        char *s = "Hello  ";      // a string
        float z = 1.415;        // a floating point value

        x = 100; y = 200;

        cout << x << "  " << y << endl << s << z << endl;

This produces the output string:

       100  200  
        Hello  1.415

The output will appear as two lines because the endl symbol appeared twice in the output stream.

Interactive input uses the predefined variable "cin" and the >> operator in a similar manner. For example, the statements

       int x;

        cin >> x; 

cause an integer value to be read from the standard input and assigned as the value of the variable x. When reading, "whitespace" characters, such as blanks and tabs, are ignored.

A dialogue with the user usually consists of a prompt-response sequence. The program prompts the user to enter data and then reads that data. For example, a program that wants to read two integer values that represent the hour and minute might look like:

       int hour, minute;

        cout << "Enter hour (integer) and minute (integer): " << endl;
        
        cin >> hour >> minute;

Input from and output to disk files use a similar strategy. Two additional classes are defined in the standard C++ library:

       class ifstream {
          private:
            ...
          public:
            ifstream(char* filename);   // name of file to use for input
            ...
        };


        class ofstream {
          private:
            ...
          public:
            ofstream(char* filename);   //name of file to use for output
            ...
        };

The following example shows how data in files is manipulated using the stream I/O operators:

       ifstream is("file.dat");
        ofstream os("out.dat");
  
        int x, y;

        is >> x >> y;                   // reads two integers from file.dat

        os << "The sum is:  ";          // output heading to out.dat
        os << (x + y) << '\n';          // output sum and end line

        

Stream Output to a Window

A variation of the Frame class, named TextFrame, allows stream output to a window. This class presents a very simplified version of the stream I/O model; it is restricted so that only output is possible and that only for the most basic built-in types (int, long, float, double, char, and char*).

A partial definition of the TextFrame class is shown below. The constructors for a TextFrame are similar to those for a Frame object, as are the MoveTo and Resize methods. Keep in mind that the TextFrame class is not part of the standard C++ library - like the Frame class, it is only part of the materials used here for learning about C++.


The TextFrame Class
class TextFrame {
 private:
                // encapsulated, hidden data
 public:

   TextFrame(char *name, int x, int y, int w, int h);
   TextFrame(char* name, int x, int y);
   TextFrame(char* name);
   TextFrame();

  ~TextFrame(); 

   void     MoveTo( Location newLocation);      // change position
   void     Resize( Shape newShape);            // change shape
   void     Resize( float factor);              //
   int      IsNamed(char* n);                   // is this your name?
   
   ...

};

The TextFrame class can be used as shown in the code below. This code creates two Frame objects and a TextFrame object. The code outputs to the TextFrame the name of the Frame object in which each mouse event occurs.

 Frame window1("Window1", 100,100, 200, 200);
  Frame window2("Window2", 400,400, 200, 200);
  TextFrame out("Display", 400, 20, 200, 200);

  OnStart() {
    window1.DrawText("Click in this window", 20,20);
    window2.DrawText("Click in this window", 20,20);
    out << "Name of window clicked in will appear below" << '\n';
  }

  OnPaint() {
    window1.DrawText("Click in this window", 20,20);
    window2.DrawText("Click in this window", 20,20);
    out << "Name of window clicked in will appear below" << '\n';
  }
 
  OnMouseEvent(char* frameName, int x, int y, int buttonState) {
    out << name ;
    out << '\';
  }

  OnTimerEvent() {}

The TextFrame class is useful for displaying textual information to a user and is also convenient for displaying status information during development, testing, and debugging.

 

String Streams

The stream I/O facilities may be used to transfer formatted data to a character array, or to read formatted data from a character array. Although the stream I/O operators are used, the stream operators in this case only cause the transfer of information between the character array and other variables in memory. The string stream operations do not involve an input or output device or file.

Stream processing using a character array is useful when formatted data (e.g., several integer values) are being passed to an interface that accepts only a single string (a char*) parameter. This occurs, for example, in the Frame class's DrawText method. To display one or more integer values in a Frame using DrawText, the integer data must first be converted to a single string. Using the stream output operators on a string stream, the integer data is written into the string stream. The string stream places the data in a character array. The stream output operations maintain an end-of-string character ('\0') after the last character added to the character array. Thus, the character array can then be handled as a normal character array or string. It is also possible to use the stream input operators to read formatted data from a character array.

String stream processing involves two classes that are defined in the standard C++ library:

  class istrstream {...};
   class ostrstream {...};

The constructor for a string stream object requires a pointer to the beginning of the character array (or memory buffer) and an integer argument giving the length of the array (or buffer). Once constructed, the stream output operator (<<) can be applied to an ostrstream object and the stream input operator (>>) can be applied to an istrstream object. An example of using string stream processing is shown in the example below, which writes to a character array a simple arithmetic expression to add two integer values. The simple expression is formatted using the output string stream object named "expression" and parsed using an input string stream object named parser.

  char text[100];

   ostrstream expression(text, 100);    // create string stream

   expression << 10 << " + " << 20 << endl;

   ...

   istrstream parser(text, 100);

   int value1, value2;
   char operator;

   parser >> value1             // value1   = 10
          >> operator           // operator = '+'
          >> value2;            // value2   = 20

Notice that the two string streams are constructed using the "text" character array. It is into this character array that "expression" places its formatted data and from which "parser" reads characters to produce the formatted data requested of it.

 

Other Methods on Streams

In addition to the stream I/O operators, stream objects also provide methods that may be invoked using the dot operator (.). These methods provide ways to query the status of the stream and to perform operations that are not readily described by an operator notation.

Examples of operators that query the state of the stream are those that test whether the end of an input stream has been reached or whether the last operation performed on a stream has succeeded or failed. These two methods are used in the following code fragment:

       if (cin.eof()) ...      // at end of standard input stream
        if (cin.fail()) ...     // last input operation failed

An operation may fail, for example, if the stream was unable to parse the contents of an input stream adequately to produce a value of the required type. For example, if an integer is to be read next from the input stream and the next text in the input stream is "abcd," that cannot be read as an integer value.

Reading an entire string or an entire line of input is also done through methods that use the dot operator, because this operation does not fit the stream operator model (i.e., there is no data type that corresponds to a line of input in C++). The method for reading a string or line of input is named "get" and it has three parameters:

  1. a character array into which the data is read
  2. the maximum number of characters to be placed in the character array from the input stream (not to exceed one less than the length of the character array)
  3. a character which, if encountered in the stream, will terminate the reading

Several details about the get method that help to understand its operation are these:

  • An end-of-string character ('\0') is placed in the character array after the last character read from the input stream. This allows the character buffer to be used wherever a null terminated string is needed. Because the end-of-string character takes one space in the character array, the maximum number of characters that can be read from the input stream is one less than the length of the character array.
  • The get method will stop reading characters from the stream when either the maximum length is reached or when the special terminating character is encountered, whichever comes first
  • The special terminating character is not removed from the stream nor is it placed in the character array.

An example of using the get method to read a line of input is shown in the following example:

  char line[100];

   ...

   cin.get(line, 100, '\n');

Notice that the dot operator has been used to apply the get method to the standard input stream object.

Tasks

  1. Write a program that creates a Frame object with all default values. The program should then read location and shape information and a character string from a file named "window.dat." The Frame object should then be moved and resized using the location and shape information read from the file and the character string read from the file written into the Frame object.
  2. Mouse Tracker: Write a program that displays in a Frame the current mouse coordinates. The coordinates should be written in the form (x,y) - including the parentheses and comma - at the current mouse location. A string stream must be used to format the string to be written in the Frame
  3. Simplest Timer: Write a program to output to a TextFrame the current value of an integer variable that is incremented and output on each timer event. The TextFrame shoud initially display a zero.
  4. Mouse Reporter: Write a program to output to a TextFrame a line each time the left mouse button is clecked in a Frame object. The line of output should be of the form (x,y) - including the parentheses and comma - where x and y are the coordinates of the mouse event.
  5. Mouse Reporter 2: Write a program that extends the Mouse Reporter program by having two Frame objects and the line of output in the TextFrame is of the form name:(x,y) where name is the name of the Frame in which the mouse click occurred and x and y are the coordinates of the mouse event.
  6. File Viewer: Write a program that reads a disk file named "viewer.dat" a line at a time and writes each line to a TextFrame.
  7. File Scanner: Revise the FileViewer program so that a single line of text from the file is read and written to the TextFrame on each timer event.



©1998 Prentice-Hall, Inc.
A Simon & Schuster Company
Upper Saddle River, New Jersey 07458

Legal Statement

 

 

 

ÿ