Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

lafore_robert_objectoriented_programming_in_c

.pdf
Скачиваний:
51
Добавлен:
27.03.2023
Размер:
8.94 Mб
Скачать

Streams and Files

625

TABLE 12.11

Continued

Name

Device

 

 

lpt2

Second parallel printer

lpt3

Third parallel printer

nul

Dummy (nonexistent) device

 

 

In most systems the printer is connected to the first parallel port, so the filename for the printer should be prn or lpt1. (You can substitute the appropriate name if your system is configured differently.)

The following program, EZPRINT, sends a string and a number to the printer, using formatted output with the insertion operator.

//ezprint.cpp

//demonstrates simple output to printer

#include <fstream>

//for file streams

using namespace std;

 

int main()

 

{

 

 

char*

s1 = “\nToday’s winning number is “;

int

n1 = 17982;

 

ofstream outfile;

//make a file

outfile.open(“PRN”);

//open it for printer

outfile << s1 << n1 << endl;

//send data to printer

outfile << ‘\x0C’;

//formfeed to eject page

return 0;

 

}

 

 

You can send any amount of formatted output to the printer this way. The ‘\x0C’ character causes the page to eject from the printer.

The next example, OPRINT, prints the contents of a disk file, specified on the command line, to the printer. It uses the character-by-character approach to this data transfer.

//oprint.cpp

//imitates print command

#include <fstream>

//for

file functions

#include

<iostream>

 

 

using namespace std;

 

 

#include

<process.h>

//for

exit()

12

AND S

F TREAMS

ILES

626

Chapter 12

 

int main(int argc, char* argv[] )

{

if(argc != 2)

{

cerr << “\nFormat: oprint filename”;

exit(-1);

 

}

 

char ch;

//character to read

ifstream infile;

//create file for input

infile.open( argv[1] );

//open file

if( !infile )

//check for errors

{

 

cerr << “\nCan’t open “ << argv[1];

exit(-1);

 

}

 

ofstream outfile;

//make file

outfile.open(“PRN”);

//open it for printer

while( infile.get(ch) != 0 )

//read a character

outfile.put(ch);

//write character to printer

outfile.put(‘\x0C’);

//formfeed to eject page

return 0;

 

}

 

You can use this program to print any text file, such as any of your .CPP source files. It acts much the same as the DOS PRINT command. Like the OTYPE example, this program checks for the correct number of command-line arguments, and for a successful opening of the specified file.

Summary

In this chapter we briefly examined the hierarchy of stream classes and showed how to handle various kinds of I/O errors. Then we saw how to perform file I/O in a variety of ways. Files in C++ are associated with objects of various classes, typically ofstream for output, ifstream for input, and fstream for both input and output. Member functions of these or base classes are used to perform I/O operations. Such operators and functions as <<, put(), and write() are used for output, while >>, get(), and read() are used for input.

The read() and write() functions work in binary mode, so entire objects can be saved to disk no matter what sort of data they contain. Single objects can be stored, as can arrays or other data structures of many objects. File I/O can be handled by member functions. This can be the responsibility of individual objects, or the class itself can handle I/O using static member functions.

A check for error conditions should be made after each file operation. The file object itself takes on a value of 0 if an error occurred. Also, several member functions can be used to determine specific kinds of errors. The extraction operator >> and the insertion operator << can be overloaded so that they work with programmer-defined data types. Memory can be considered a stream, and data sent to it as if it were a file.

Streams and Files

627

Questions

Answers to these questions can be found in Appendix G.

1.A C++ stream is

a.the flow of control through a function.

b.a flow of data from one place to another.

c.associated with a particular class.

d.a file.

2.The base class for most stream classes is the ________ class.

3.Name three stream classes commonly used for disk I/O.

4.Write a statement that will create an object called salefile of the ofstream class and associate it with a file called SALES.JUN.

5.True or false: Some streams work with input, and some with output.

6.Write an if statement that checks whether an ifstream object called foobar has reached the end of file or has encountered an error.

7.We can output text to an object of class ofstream using the insertion operator << because

a.the ofstream class is a stream.

b.the insertion operator works with all classes.

c.we are actually outputting to cout.

d.the insertion operator is overloaded in ofstream.

8.Write a statement that writes a single character to an object called fileOut, which is of class ofstream.

9.To write data that contains variables of type float to an object of type ofstream, you should use

a.the insertion operator.

b.seekg().

c.write().

d.put().

10.Write a statement that will read the contents of an ifstream object called ifile into an array called buff.

12

AND S

F TREAMS

ILES

Chapter 12

628

11.Mode bits such as app and ate

a.are defined in the ios class.

b.can specify if a file is open for reading or writing.

c.work with the put() and get() functions.

d.specify ways of opening a file.

12.Define what current position means when applied to files.

13.True or false: A file pointer always contains the address of the file.

14.Write a statement that moves the current position 13 bytes backward in a stream object called f1.

15.The statement

f1.write( (char*)&obj1, sizeof(obj1) );

a.writes the member functions of obj1 to f1.

b.writes the data in obj1 to f1.

c.writes the member functions and the data of obj1 to f1.

d.writes the address of obj1 to f1.

16.Command-line arguments are

a.disagreements in the military.

b.typed following a program name at the command prompt.

c.accessed through arguments to main().

d.accessible only from disk files.

17.Used with cin, what does the skipws flag accomplish?

18.Write a declarator for main() that will enable command-line arguments.

19.In console mode programs, the printer can be accessed using the predefined filename

________.

20.Write the declarator for the overloaded >> operator that takes output from an object of class istream and displays it as the contents of an object of class Sample.

Exercises

Answers to starred exercises can be found in Appendix G.

*1. Start with the Distance class from the ENGLCON example in Chapter 6, “Objects and Classes.” Using a loop similar to that in the DISKFUN example in this chapter, get a number of Distance values from the user, and write them to a disk file. Append them to existing values in the file, if any. When the user signals that no more values will be input, read the file and display all the values.

Streams and Files

*2. Write a program that emulates the DOS COPY command. That is, it should copy the contents of a text file (such as any .CPP file) to another file. Invoke the program with two command-line arguments—the source file and the destination file—like this:

C>ocopy srcfile.cpp destfile.cpp

In the program, check that the user has typed the correct number of command-line arguments, and that the files specified can be opened.

*3. Write a program that returns the size in bytes of a program entered on the command line:

C>filesize program.ext

4.In a loop, prompt the user to enter name data consisting of a first name, middle initial, last name, and employee number (type unsigned long). Then, using formatted I/O with the insertion (<<) operator, write these four data items to an ofstream object. Don’t forget that strings must be terminated with a space or other whitespace character. When the user indicates that no more name data will be entered, close the ofstream object, open an ifstream object, read and display all the data in the file, and terminate the program.

5.Create a time class that includes integer member values for hours, minutes, and seconds. Make a member function get_time() that gets a time value from the user, and a function put_time() that displays a time in 12:59:59 format. Add error checking to the get_time()

function to minimize user mistakes. This function should request hours, minutes, and seconds separately, and check each one for ios error status flags and the correct range. Hours should be between 0 and 23, and minutes and seconds between 0 and 59. Don’t input these values as strings and then convert them; read them directly as integers. This implies that you won’t be able to screen out entries with superfluous decimal points, as does the ENGL_IO program in this chapter, but we’ll assume that’s not important.

In main(), use a loop to repeatedly get a time value from the user with get_time() and then display it with put_time(), like this:

Enter hours: 11 Enter minutes: 59 Enter seconds: 59 time = 11:59:59

Do another (y/n)? y Enter hours: 25

Hours must be between 0 and 23 Enter hours: 1

Enter minutes: 10 Enter seconds: five

Incorrect seconds input Enter seconds: 5

time = 1:10:05

629

12

AND S

F TREAMS

ILES

Chapter 12

630

6.Make a class called name from the data in Exercise 4 (first name, middle initial, last name, employee number). Create member functions for this class that read and write an object’s data to a disk file, using ofstream, and read it back using ifstream. Use formatted data with the << and >> operators. The read and write member functions should be self-contained: they should include statements to open the appropriate stream and read or write a record.

The write function can simply append its data to the end of the file. The read function will need a way to select which record it’s going to read. One way to do this is to call it with a parameter representing the record number. Once it knows which record it should

read, how does the read function find the record? You might think you could use the seekg() function, but that isn’t much help because in formatted I/O the records are all different lengths (depending on the number of characters in the strings and the number of digits in the integer). So you’ll need to actually read records until you’ve skipped forward to the one you want.

In main(), call these member functions to allow the user to enter data for a number of objects that are written to a file as they are entered. The program then displays all this data by reading it from the file.

7.Another approach to adding file stream I/O to an object is to make the file stream itself a static member of the object. Why do that? Well, it’s often conceptually easier to think of the stream as being related to the class as a whole than to the individual objects of the class. Also, it’s more efficient to open a stream only once, then read and write objects to it as needed. For example, once the file is opened, each time the read function is called it can return the data for the next object in the file. The file pointer will progress automatically through the file because the file is not closed between reads. Rewrite the program in Exercises 4 and 6 to use an fstream object as a static data item of the name class. Keep the same functionality that is in those exercises. Write a static function to open this stream, and another static function to reset the file pointer to the beginning of the file. You can use this reset function when you’re done writing and want to read all the records back from the file.

8.Starting with the LINKLIST program in Chapter 10, “Pointers,” create a program that gives the user four options, which can be selected by pressing a key.

Add a link to the list in memory (the user supplies the data, which is one integer)

Display the data from all the links in memory

Write the data for all the links to a disk file (creating or truncating the file as necessary)

Read all the data back from the file, and construct a new linked list in which to store it

Streams and Files

631

The first two options can use the member functions already implemented in LINKLIST. You’ll need to write functions to read to, and write from, the disk file. You can use the same file for all reads and writes. The file should store only the data; there’s no sense in its storing the contents of pointers, which will probably not be relevant when the list is read back in.

9.Start with Exercise 7 in Chapter 8, “Operator Overloading,” and overload the insertion (<<) and extraction (>>) operators for the frac class in the four-function calculator. Note that you can chain the operators, so asking for a fraction, an operator, and a fraction

should require only one statement:

cin >> frac1 >> op >> frac2;

10.Add error checking to the extraction (>>) operator of the frac class in Exercise 9. With error checking it’s probably better to prompt for the first fraction, then for the operator, and then for the second fraction, rather than using a single statement as shown in Exercise 9. This makes the format more comprehensible when it is interspersed with error messages.

Enter first fraction: 5/0

Denominator cannot be 0

Enter fraction again: 5/1

Enter operator (+, -, *, /): +

Enter second fraction: one third

Input error

Enter fraction again: 1/3

Answer is --------------------- 16/3

Do another (y/n)?

As implied in this sample interaction, you should check for ios error flags and also for a denominator of 0. If there’s an error, prompt the user to enter the fraction again.

11.Start with the bMoney class, last seen in Exercise 5 in Chapter 11. Overload the insertion (<<) and extraction (>>) operators to perform I/O on bMoney quantities. Perform some sample I/O in main().

12.To the EMPL_IO program in this chapter add the ability to search through all the employee objects in a disk file, looking for one with a specified employee number. If it finds a match, it should display the data for the employee. The user can invoke this find() function by typing the ‘f’ character. The function should then prompt for the employee number. Ask yourself whether the function should be static, virtual, or something else. This search and display operation should not interfere with the data in memory.

12

AND S

F TREAMS

ILES

Chapter 12

632

NOTE

Note: Don’t try to read a file generated with the EMPL_IO program. The classes are not the same because of the find() member function in the new program, and disaster will result if their data is mixed, as discussed in this chapter. You may need to turn on an Enable RTTI option in your compiler. Consult Appendix C, “Microsoft Visual C++,” or Appendix D, “Borland C++Builder,” as appropriate.

Multifile Programs

CHAPT E R

13

IN THIS CHAPTER

Reasons for Multifile Programs

634

Creating a Multifile Program

637

Inter-File Communication 638

 

• A Very Long Number Class

651

 

A High-Rise Elevator Simulation

658

Chapter 13

634

In previous chapters we’ve seen how the various parts of a C++ program—such as class declarations, member functions, and a main() function—are combined. However, the programs in those chapters all consisted of a single file. Now let’s look at program organization from a wider perspective, involving multiple files. We’ll see how communication is carried out among files, and how header files fit into the picture.

Besides discussing multifile programs in general, this chapter will introduce some longer and more ambitious applications. Our aim in these programs is not that you necessarily understand every detail of their operation, but that you acquire a general understanding of how the elements of larger programs relate to one another. These programs also show how classes can be used in more realistic applications than the short examples we’ve seen so far. On the other hand, they are not so long that it takes all spring to wade through them.

Reasons for Multifile Programs

There are several reasons for using multifile programs. These include the use of class libraries, the organization of programmers working on a project, and the conceptual design of a program. Let’s reflect briefly on these issues.

Class Libraries

In traditional procedure-oriented languages it has long been customary for software vendors to furnish libraries of functions. Other programmers then combine these libraries with their own custom-written routines to create an application for the end user.

Libraries provide ready-made functions for a wide variety of fields. For instance, a vendor might supply a library of functions for handling statistics calculations, or one for advanced memory management.

Since C++ is organized around classes rather than functions, it’s not surprising that libraries for C++ programs consist of classes. What may be surprising is how much better a class library is than an old-fashioned function library. Because classes encapsulate both data and functions, and because they more closely model objects in real life, the interface between a class library and the application that makes use of it can be much cleaner than that provided by a function library.

For these reasons class libraries assume a more important role in C++ programming than function libraries do in traditional programming. A class library can take over a greater portion of the programming burden. An applications programmer, if the right class library is available, may find that only a minimal amount of programming is necessary to create a final product. Also, as more and more class libraries are created, the chances of finding one that solves your particular programming problem continues to increase.