
lafore_robert_objectoriented_programming_in_c
.pdf

Chapter 12
616
2.Type: Scientist Name: Faraday Number: 2222
Number of publications: 99
3.Type: Laborer Name: Smith Number: 3333
Of course you can also exit the program after writing the data to disk. When you start it up again, you can read the file back in and all the data will reappear.
It would be easy to add functions to this program to delete an employee, retrieve data for a single employee from the file, search the file for employees with particular characteristics, and so forth.
Overloading the Extraction and Insertion
Operators
Let’s move on to another stream-related topic: overloading the extraction and insertion operators. This is a powerful feature of C++. It lets you treat I/O for user-defined data types in the same way as basic types like int and double. For example, if you have an object of class crawdad called cd1, you can display it with the statement
cout << “\ncd1=” << cd1;
just as if it were a basic data type.
We can overload the extraction and insertion operators so they work with the display and keyboard (cout and cin) alone. With a little more care, we can also overload them so they work with disk files. We’ll look at examples of both of these situations.
Overloading for cout and cin
Here’s an example, ENGLIO, that overloads the insertion and extraction operators for the Distance class so they work with cout and cin.
//englio.cpp
//overloaded << and >> operators #include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////
class Distance |
//English Distance class |
{ |
|
private: |
|
int feet; |
|
float inches; |
|
public: |
|


Chapter 12
618
Notice how convenient and natural it is to treat Distance objects like any other data type, using statements like
cin >> dist1 >> dist2;
and
cout << “\ndist1=” << dist1 << “\ndist2=” << dist2;
The << and >> operators are overloaded in similar ways. They return, by reference, an object of istream (for >>) or ostream (for <<). These return values permit chaining. The operators take two arguments, both passed by reference. The first argument for >> is an object of istream (such as cin). For << it’s an object of ostream (such as cout). The second argument is an object of the class to be displayed, Distance in this example. The >> operator takes input from the stream specified in the first argument and puts it in the member data of the object specified by the second argument. The << operator removes the data from the object specified by the second argument and sends it into the stream specified by the first argument.
The operator<<() and operator>>() functions must be friends of the Distance class, since the istream and ostream objects appear on the left side of the operator. (See the discussion of friend functions in Chapter 11.)
You can overload the insertion and extraction operators for other classes by following these same steps.
Overloading for Files
Our next example shows how we might overload the << and >> operators in the Distance class so they work with file I/O as well as with cout and cin.
//englio2.cpp
//overloaded << and >> operators can work with files #include <fstream>
#include <iostream> using namespace std;
////////////////////////////////////////////////////////////////
class Distance |
//English Distance class |
{ |
|
private: |
|
int feet; |
|
float inches; |
|
public: |
|
Distance() : feet(0), inches(0.0) //constructor (no args) |
|
{ } |
//constructor (two args) |
Distance(int ft, float in) : feet(ft), inches(in)
{}


Chapter 12
620
We’ve made minimal changes to the overloaded operators themselves. The >> operator no longer prompts for input, since it doesn’t make sense to prompt a file. We assume that the user knows exactly how to enter a feet-and-inches value, including the various punctuation marks. The << operator is unchanged. The program asks for input from the user, writing each Distance value to the file as it’s obtained. When the user is finished with input, the program then reads and displays all the values from the file. Here’s some sample interaction:
Enter Distance: 3’-4.5”
Do another (y/n)? yes
Enter Distance: 7’-11.25”
Do another (y/n)? yes
Enter Distance: 11’-6”
Do another (y/n)? no
Contents of disk file is:
Distance = 3’-4.5”
Distance = 7’-11.25”
Distance = 11’-6”
The distances are stored character by character to the file. In this example the contents of the file would be as follows:
3’-4.5”7’-11.25”11’-6
If the user fails to enter the distances with the correct punctuation, they won’t be written to the file correctly and the file won’t be readable for the << operator. In a real program it’s essential to check the input for errors.
Memory as a Stream Object
You can treat a section of memory as a stream object, inserting data into it just as you would a file. This is useful when you need to format your output in a particular way (such as displaying exactly two digits to the right of the decimal point), but you also need to use a text-output function that requires a string as input. This is common when calling output functions in a GUI environment such as Windows, since these functions often require a string as an argument. (C programmers will remember using the sprintf() function for this purpose.)
A family of stream classes implements such in-memory formatting. For output to memory there is ostrstream, which is derived from (among other classes) ostream. For input from memory there is istrstream, derived from istream; and for memory objects that do both input and output there is strstream, derived from iostream.


Chapter 12
622
d=67890.12
str1=Kafka
str2=Freud
In this example the program displays the contents of the buffer only to show what it looks like. Ordinarily you would have a more sophisticated use for this formatted data.
Command-Line Arguments
If you’ve ever used MS-DOS, you are probably familiar with command-line arguments, used when invoking a program. They are typically used to pass the name of a data file to an application. For example, you can invoke a word processor application and the document it will work on at the same time:
C>wordproc afile.doc
Here afile.doc is a command-line argument. How can we get a C++ program to read the command-line arguments? Here’s an example, COMLINE, that reads and displays as many command-line arguments as you care to type (they’re separated by spaces):
//comline.cpp
//demonstrates command-line arguments #include <iostream>
using namespace std;
int main(int argc, char* argv[] ) |
|
|
||
{ |
|
|
|
|
cout << |
“\nargc = “ << argc << |
endl; |
//number of arguments |
|
for(int |
j=0; j<argc; |
j++) |
|
//display arguments |
cout |
<< “Argument |
“ << j << |
“ = “ |
<< argv[j] << endl; |
return 0;
}
And here’s a sample interaction with the program:
C:\C++BOOK\Chap12>comline uno dos tres
argc = 4
Argument 0 = C:\CPP\CHAP12\COMLINE.EXE Argument 1 = uno
Argument 2 = dos Argument 3 = tres
To read command-line arguments, the main() function (don’t forget it’s a function!) must itself be given two arguments. The first, argc (for argument count), represents the total number of


Chapter 12
624
This program first checks to see whether the user has entered the correct number of commandline arguments. Remember that the pathname of OTYPE.EXE itself is always the first commandline argument. The second argument is the name of the file to be displayed, which the user should have entered when invoking the program:
C>otype ichar.cpp
Thus the total number of command-line arguments should equal 2. If it doesn’t, the user probably doesn’t understand how to use the program, and the program sends an error message via cerr to clarify matters.
If the number of arguments is correct, the program tries to open the file whose name is the second command-line argument (argv[1]). Again, if the file can’t be opened, the program signals an error. Finally, in a while loop, the program reads the file character by character and writes it to the screen.
A value of 0 for the character signals an EOF. This is another way to check for EOF. You can also use the value of the file object itself, as we’ve done before:
while( infile )
{
infile.get(ch); cout << ch;
}
You could also replace this entire while loop with the statement
cout << infile.rdbuf();
as we saw earlier in the ICHAR2 program.
Printer Output
It’s fairly easy to use console-mode programs to send data to the printer. A number of special filenames for hardware devices are defined by the operating system. These make it possible to treat the devices as if they were files. Table 12.11 shows these predefined names.
TABLE 12.11 Hardware Device Names
Name |
Device |
con |
Console (keyboard and screen) |
aux or com1 |
First serial port |
com2 |
Second serial port |
prn or lpt1 |
First parallel printer |