Tải bản đầy đủ (.pdf) (10 trang)

Absolute C++ (4th Edition) part 53 pdf

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (160.33 KB, 10 trang )

Tools for Stream I/O 527
Display 12.7 Formatting Output
(part 2 of 2)
44 cout << "End of program.\n";
45 return 0;
46 }
47 //Uses <iostream>, <fstream>, and <iomanip>:
48 void makeNeat(ifstream& messyFile, ofstream& neatFile,
49 int numberAfterDecimalpoint, int fieldWidth)
50 {
51 neatFile.setf(ios::fixed);
52 neatFile.setf(ios::showpoint);
53 neatFile.setf(ios::showpos);
54 neatFile.precision(numberAfterDecimalpoint);
55 cout.setf(ios::fixed);
56 cout.setf(ios::showpoint);
57 cout.setf(ios::showpos);
58 cout.precision(numberAfterDecimalpoint);
59 double next;
60 while (messyFile >> next)
61 {
62 cout << setw(fieldWidth) << next << endl;
63 neatFile << setw(fieldWidth) << next << endl;
64 }
65 }
setf and precision
behave the same for a file
output stream as they do
for
cout.
Satisfied if there is a


next number to read
Works the same for file output
streams as it does for
cout
neat.txt
(After program is run)
+10.37000
-9.89897
+2.31300
-8.95000
+15.00000
+7.33333
+92.87650
-123.75684
S
CREEN
O
UTPUT
+10.37000
-9.89897
+2.31300
-8.95000
+15.00000
+7.33333
+92.87650
-123.75684
End of program.
rawdata.txt
(Not changed by program)
10.37 -9.89897

2.313 -8.950 15.0
7.33333 92.8765
-1.237568432e2
528 Streams and File I/O
Example
E
DITING

A
T
EXT
F
ILE
The program discussed here is a very simple example of text editing applied to files. This program
can be used to automatically generate C++ advertising material from existing C advertising mate-
rial (in a rather simplistic way). The program takes its input from a file that contains advertising
copy that says good things about C and writes similar advertising copy about C++ in another file.
The file that contains the C advertising copy is called
cad.txt, and the new file that receives the
C++ advertising copy is called
cppad.txt. The program is shown in Display 12.8. The program
simply reads every character in the file
cad.txt and copies the characters to the file
cppad.txt. Every character is copied unchanged, except that when the uppercase letter ’C’ is
read from the input file, the program writes the string
"C++" to the output file. This program
assumes that whenever the letter
’C’ occurs in the input file, it names the C programming lan-
guage; so this change is exactly what is needed to produce the updated advertising copy.
Notice that the line breaks are preserved when the program reads characters from the input file

and writes the characters to the output file. The newline character
’\n’ is treated just like any
other character. It is read from the input file with the member function
get, and it is written to the
output file using the insertion operator,
<<. We must use the member function get to read the
input (rather than the extraction operator,
>>) because we want to read whitespace.
Stream Hierarchies: A Preview of Inheritance
One very useful way to organize classes is by means of the “derived from” relationship.
When we say that one class is derived from another class we mean that the derived class
was obtained from the other class by adding features. For example, the class of input-
file streams is derived from the class of all input streams by adding additional member
functions such as
open and close. The stream cin belongs to the class of all input
streams, but does not belong to the class of input-file streams because
cin has no mem-
ber functions named
open and close. This section introduces the notion of a derived
class as a way to think about and organize the predefined stream classes. (Chapter 14
shows how to use the idea of a derived class to define classes of your own.)

INHERITANCE AMONG STREAM CLASSES
Both the predefined stream cin and an input-file stream are input streams. So in some
sense they are similar. For example, you can use the extraction operator,
>>, with either
kind of stream. On the other hand, an input-file stream can be connected to a file using
the member function
open, but the stream cin has no member function named open. An
input-file stream is a similar but different kind of stream than

cin. An input-file stream is
of type
ifstream. The object cin is an object of the class istream (spelled without the
’f’). The classes ifstream and istream are different but closely related types. The class
ifstream is a derived class of the class istream. Let’s see what that means.
12.3
Stream Hierarchies: A Preview of Inheritance 529
Display 12.8 Editing a File of Text
(part 1 of 2)
1 //Program to create a file called cplusad.txt that is identical to the file
2 //cad.txt except that all occurrences of ’C’ are replaced by "C++". Assumes
3 //that the uppercase letter ’C’ does not occur in cad.txt except as the
4 //name of the C programming language.
5 #include <fstream>
6 #include <iostream>
7 #include <cstdlib>
8 using std::ifstream;
9 using std::ofstream;
10 using std::cout;
11 void addPlusPlus(ifstream& inStream, ofstream& outStream);
12 //Precondition: inStream has been connected to an input file with open.
13 //outStream has been connected to an output file with open.
14 //Postcondition: The contents of the file connected to inStream have been
15 //copied into the file connected to outStream, but with each ’C’ replaced
16 //by "C++". (The files are not closed by this function.)
17 int main( )
18 {
19 ifstream fin;
20 ofstream fout;
21 cout << "Begin editing files.\n";

22 fin.open("cad.txt");
23 if (fin.fail( ))
24 {
25 cout << "Input file opening failed.\n";
26 exit(1);
27 }
28 fout.open("cppad.txt");
29 if (fout.fail( ))
30 {
31 cout << "Output file opening failed.\n";
32 exit(1);
33 }
34 addPlusPlus(fin, fout);
530 Streams and File I/O
Display 12.8 Editing a File of Text
(part 2 of 2)
35 fin.close( );
36 fout.close( );
37 cout << "End of editing files.\n";
38 return 0;
39 }
40 void addPlusPlus(ifstream& inStream, ofstream& outStream)
41 {
42 char next;
43 inStream.get(next);
44 while (! inStream.eof( ))
45 {
46 if (next == ’C’)
47 outStream << "C++";
48 else

49 outStream << next;
50 inStream.get(next);
51 }
52 }
C is one of the world’s most modern
programming languages. There is no
language as versatile as C, and C
is fun to use.
C++ is one of the world’s most modern
programming languages. There is no
language as versatile as C++, and C++
is fun to use.
cad.txt
(Not changed by program)
cppad.txt
(After program is run)
Begin editing files.
End of editing files.
S
CREEN
O
UTPUT
Stream Hierarchies: A Preview of Inheritance 531
When we say that some class D is a derived class of some other class B, it means
that class D has all the features of class B but it also has added features. For example,
any stream of type
istream (without the ’f’) can be used with the extraction operator,
>>. The class ifstream (with the ’f’) is a derived class of the class istream, so an object
of type
ifstream can be used with the extraction operator, >>. An object of the class

ifstream has all the properties of an object of type istream. In particular, an object of
the class
ifstream is also an object of type istream.
However,
ifstream has added features so that you can do more with an object of
type
ifstream than you can with an object that is only of type istream. For example,
one added feature is that a stream of type
ifstream can be used with the function open.
The stream
cin is only of type istream and not of type ifstream. You cannot use cin
with the function open. Notice that the relationship between the classes ifstream and
istream is not symmetric. Every object of type ifstream is of type istream (a file input
stream is an input stream), but an object of type
istream need not be of type ifstream
(the object cin is of type istream but not of type ifstream).
The idea of a derived class is really quite common. An example from everyday life
may help to make the idea clearer. The class of all convertibles, for instance, is a derived
class of the class of all automobiles. Every convertible is an automobile, but a convert-
ible is not just an automobile. A convertible is a special kind of automobile with special
properties that other kinds of automobiles do not have. If you have a convertible, you
can lower the top so that the car is open. (You might say that a convertible has an

open” function as an added feature.)
If D is a derived class of the class B, then every object of type D is also of type B. A
convertible is also an automobile. A file input stream (object of the class
ifstream) is
also an input stream (also an object of the class
istream). So, if we use istream as the
type for a function parameter, rather than using

ifstream, then more objects can be
plugged in for the parameter. Consider the following two function definitions, which
differ only in the type of the parameter (and the function name):
void twoSumVersion1(ifstream& sourceFile)//ifstream with an ’f’
{
int n1, n2;
sourceFile >> n1 >> n2;
cout << n1 << " + " << n2 << " = " << (n1 + n2) << endl;
}
and
void twoSumVersion2(istream& sourceFile)//istream without an ’f’
{
int n1, n2;
sourceFile >> n1 >> n2;
cout << n1 << " + " << n2 << " = " << (n1 + n2) << endl;
}
derived
class
532 Streams and File I/O
With twoSumVersion1, the argument must be of type ifstream. So if fileIn is a file
input stream connected to a file, then
twoSumVersion1(fileIn);
is legal, but
twoSumVersion1(cin); //ILLEGAL
is not legal, because cin is not of type ifstream. The object cin is only a stream and
only of type
istream; cin is not a file input stream.
The function
twoSumVersion2 is more versatile. Both of the following are legal:
twoSumVersion2(fileIn);

twoSumVersion2(cin);
The moral is clear: Use istream, not ifstream, as a parameter type whenever you
can. When choosing a parameter type, use the most general type you can. (To draw a
real-life analogy: You might prefer to own a convertible, but you would not want a
garage that could only hold a convertible. What if you borrowed a sedan from a friend?
You’d still want to be able to park the sedan in your garage.)
You cannot always use the parameter type
istream instead of the parameter type
ifstream. If you define a function with a parameter of type istream, then that param-
eter can only use
istream member functions. In particular, it cannot use the functions
open and close. If you cannot keep all calls to the member functions open and close
outside the function definition, then you must use a parameter of type ifstream.
So far we have discussed two classes for input streams:
istream and its derived class
ifstream. The situation with output streams is similar. Chapter 1 introduced the out-
put streams
cout and cerr, which are in the class ostream. This chapter introduced the
file output streams, which are in the class
ofstream (with an ’f’). The class ostream is
the class of all output streams. The streams
cout and cerr are of type ostream, but not
of type
ofstream. In contrast to cout or cerr, an output-file stream is declared to be of
type
ofstream. The class ofstream of output-file streams is a derived class of the class
ostream. For example, the following function writes the word "Hello" to the output
stream given as its argument.
void sayHello(ostream& anyOutStream)
{

anyOutStream << "Hello";
}
The first of the following calls writes "Hello" to the screen; the second writes "Hello"
to the file with the external file name afile.txt.
ofstream fout;
fout.open("afile.txt");
sayHello(cout);
sayHello(fout);
ostream and
ofstream
Stream Hierarchies: A Preview of Inheritance 533
Example
Note that an output-file stream is of type ofstream and of type ostream.
Derived classes are often discussed using the metaphor of inheritance and family
relationships. If class D is a derived class of class B, then class D is called a child of class
B and class B is called a parent of class D. The derived class is said to inherit the mem-
ber functions of its parent class. For example, every convertible inherits the fact that it
has four wheels from the class of all automobiles, and every input-file stream inherits
the extraction operator,
>>, from the class of all input streams. This is why the topic of
derived classes is often called inheritance.
A
NOTHER

newLine
F
UNCTION
As an example of how you can make a stream function more versatile, consider the function new-
Line
that we defined in Display 9.2. That function works only for input from the keyboard, which

is input from the predefined stream
cin. The function newLine in Display 9.2 has no arguments.
Below we have rewritten the function
newLine so that it has a formal parameter of type istream
for the input stream:
//Uses <iostream>:
void newLine(istream&
inStream)
{
char symbol;
do

{
M
AKING
S
TREAM
P
ARAMETERS
V
ERSATILE
If you want to define a function that takes an input stream as an argument and you want that
argument to be
cin in some cases and an input-file stream in other cases, then use a formal
parameter of type
istream (without an ’f’). However, an input-file stream, even if used as an
argument of type
istream, must still be declared to be of type ifstream (with an ’f’).
Similarly, if you want to define a function that takes an output stream as an argument and you
want that argument to be cout in some cases and an output-file stream in other cases, then use a

formal parameter of type
ostream. However, an output-file stream, even if used as an argument
of type
ostream, must still be declared to be of type ofstream (with an ’f’). You cannot open
or close a stream parameter of type
istream or ostream. Open these objects before passing
them to your function and close them after the function call.
The stream classes istream and ostream are defined in the iostream library and placed in the
std namespace. One way to make them available to your code is the following:
#include <iostream>
using std::istream;
using std::ostream;
inheritance
child
parent
534 Streams and File I/O
inStream.get(symbol);
} while (symbol != ’\n’);
}
Now, suppose your program contains this new version of the function newLine. If your program
is taking input from an input stream called
fin (which is connected to an input file), the follow-
ing will discard all the input left on the line currently being read from the input file:
newLine(fin);
If your program is also reading some input from the keyboard, the following will discard the
remainder of the input line that was typed in at the keyboard:
newLine(cin);
If your program has only the above rewritten version of newLine, which takes a stream argument
such as
fin or cin, you must always give the stream name, even if the stream name is cin. But

thanks to overloading, you can have both versions of the function
newLine in the same program:
the version with no arguments that is given in Display 9.2 and the version with one argument of
type
istream that we just defined. In a program with both definitions of newLine, the following
two calls are equivalent:
newLine(cin);
and
newLine( );
You do not really need two versions of the function newLine. The version with one argument of
type
istream can serve all your needs. However, many programmers find it convenient to have a
version with no arguments for keyboard input, since keyboard input is used so frequently.
An alternative to having two overloaded versions of the newLine function is to use a default
argument (as discussed in Chapter 4). In the following code, we have rewritten the
newLine
function a third time:
//Uses <iostream>:
void newLine(istream& inStream = cin)
{
char symbol;
do
{
inStream.get(symbol);
} while (symbol != '\n');
}
If we call this function as
newLine( );
using both
versions

of
newLine
Stream Hierarchies: A Preview of Inheritance 535
Self-Test Exercises
the formal parameter takes the default argument cin. If we call this as
newLine(fin);
the formal parameter takes the argument fin.
An alternative to using this
newLine function is to use the function ignore, which we discussed
in Chapter 9. The function
ignore is a member of every input-file stream as well as a member of
cin.
13. What is the type of the stream cin? What is the type of the stream cout?
14. Define a function called
copyChar that takes one argument that is an input stream. When
called,
copyChar will read one character of input from the input stream given as its argu-
ment and will write that character to the screen. You should be able to call your function
using either
cin or an input-file stream as the argument to your function copyChar. (If the
argument is an input-file stream, then the stream is connected to a file before the function
is called, so
copyChar will not open or close any files.) For example, the first of the follow-
ing two calls to
copyChar will copy a character from the file stuff.txt to the screen, and
the second will copy a character from the keyboard to the screen:
ifstream fin;
fin.open("stuff.txt");
copyChar(fin);
copyChar(cin);

15. Define a function called copyLine that takes one argument that is an input stream. When
called,
copyLine reads one line of input from the input stream given as its argument and
writes that line to the screen. You should be able to call your function using either
cin or
an input-file stream as the argument to your function
copyLine. (If the argument is an
input-file stream, then the stream is connected to a file before the function is called, so
copyLine will not open or close any files.) For example, the first of the following two calls
to
copyLine will copy a line from the file stuff.txt to the screen, and the second will
copy a line from the keyboard to the screen:
ifstream fin;
fin.open("stuff.txt");
copyLine(fin);
copyLine(cin);
16. Define a function called sendLine that takes one argument that is an output stream.
When called,
sendLine reads one line of input from the keyboard and outputs the line to
the output stream given as its argument. You should be able to call your function using
either
cout or an output-file stream as the argument to your function sendLine. (If the
ignore
536 Streams and File I/O
argument is an output-file stream, then the stream is connected to a file before the function
is called, so
sendLine will not open or close any files.) For example, the first of the follow-
ing calls to
sendLine will copy a line from the keyboard to the file morestuf.txt, and
the second will copy a line from the keyboard to the screen:

ofstream fout;
fout.open("morestuf.txt");
cout << "Enter 2 lines of input:\n";
sendLine(fout);
sendLine(cout);
17. Is the following statement true or false? If it is false, correct it. In either event, explain it
carefully.
A function written using a parameter of class
ifstream or ofstream can be called with
istream or ostream arguments, respectively.
Random Access to Files
Any time, any where.
Common response to a challenge for a confrontation
The streams for sequential access to files, which we discussed in the previous sections of
this chapter, are the ones most often used for file access in C++. However, some appli-
cations that require very rapid access to records in very large databases require some sort
of random access to particular parts of a file. Such applications might best be done with
specialized database software. But perhaps you are given the job of writing such a pack-
age in C++, or perhaps you are just curious about how such things are done in C++.
C++ does provide for random access to files so that your program can both read from
and write to random locations in a file. This section gives a brief glimpse of this ran-
dom access to files. This is not a complete tutorial on random access to files, but will let
you know the name of the main stream class used and the important issues you will
encounter.
If you want to be able to both read and write to a file in C++, you use the stream
class
fstream that is defined in the <fstream> library. The definition of fstream is
placed in the
std namespace.
Details about opening a file and connecting it to a stream in the class

fstream are
basically the same as discussed for the classes
ifstream and ofstream, except that
fstream has a second argument to open. This second argument specifies whether the
stream is used for input, output, or both input and output. For example, a program
that does both input and output to a file named
"stuff" might start as follows:
12.4

×