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 it is being performed on different types. This is exactly the situation that operator overloading is meant to address. In C++, each type has an overloaded operator that is programmed to handle I/O for that specific 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 steam 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 outputThese 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 the use these classes is sufficient.
The standard C++ I/O library includes two predefined variables:
istream cin; // interactive input ostream cout; // interactive outputThese 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" characterBecause 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';that 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 be re-written 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;Produces the output string:
100 200 Hello 1.415The output will appear as two line 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 (blanks, tabs) are ignored.
A dialog 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
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++.
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 n the code below. This code creates two Frame objects and a TextFrame object. The code output 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 in displaying textual information to a user and is also convenient for displaying status information during development, testing and debugging.
Stream processing using a character array is useful when formatted data (e.g., several integer values) is 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 and 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 define 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. This example 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 a input stream 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 = 20Notice 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.
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 ona stream 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 failedAn operation may fail, for example, if the stream was unable to parse the contents input stream 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 ot 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:
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.
|
Exercises |