1.If your program requires input, read that input from a file—you’ll soon see that it’s remarkably easy to use files with iostreams. Iostreams for files still works fine with a GUI .
2.Read the input without attempting to convert it, as we just suggested. When the input is some place where it can’t foul things up during conversion, you can safely scan it .
3.Output is different. If you’re using a GUI, coutdoesn’t necessarily work, and you must send it to a file (which is identical to sending it to cout) or use the GUI facilities for data display. Otherwise it often makes sense to send it to cout. In both cases, the output formatting functions of iostreams are highly useful .
Another common practice saves compile time on large projects. Consider, for example, how you would declare the Date stream operators introduced earlier in the chapter in a header file. You only need to include the prototypes for the functions, so it’s not really necessary to include the entire header in Date.h. The standard practice is to only declare classes, something like this: .
class ostream;
This is an age-old technique for separating interface from implementation and is often called a forward declaration(and ostreamat this point would be considered an incomplete type , since the class definition has not yet been seen by the compiler) .
This will not work as is, however, for two reasons:
1. The stream classes are defined in the stdnamespace.
2. They are templates.
The proper declaration would be:
namespace std {
template >
class basic_ostream;
typedef basic_ostream ostream;
}
(As you can see, like the stringclass, the streams classes use the character traits classes mentioned in Chapter 3). Since it would be terribly tedious to type all that for every stream class you want to reference, the standard provides a header that does it for you: . The Dateheader would then look something like this: .
// Date.h
#include
class Date {
friend std::ostream& operator<<(std::ostream&,
const Date&);
friend std::istream& operator>>(std::istream&, Date&);
// etc .
To grab input a line at a time, you have three choices:
The member function get( )
The member function getline( )
The global function getline( )defined in the header
The first two functions take three arguments:
A pointer to a character buffer in which to store the result
The size of that buffer (so it’s not overrun)
The terminating character, to know when to stop reading input
The terminating character has a default value of '\n', which is what you’ll usually use. Both functions store a zero in the result buffer when they encounter the terminating character in the input .
So what’s the difference? Subtle, but important: get( )stops when it sees the delimiter in the input stream, but it doesn’t extract it from the input stream. Thus, if you did another get( )using the same delimiter, it would immediately return with no fetched input. (Presumably, you either use a different delimiter in the next get( )statement or a different input function.) The getline( )function, on the other hand, extracts the delimiter from the input stream, but still doesn’t store it in the result buffer .
The getline( )function defined in is convenient. It is not a member function, but rather a stand-alone function declared in the namespace std. It takes only two non-default arguments, the input stream and the stringobject to populate. Like its namesake, it reads characters until it encounters the first occurrence of the delimiter ( '\n'by default) and consumes and discards the delimiter. The advantage of this function is that it reads into a stringobject, so you don’t have to worry about buffer size .
Generally, when you’re processing a text file that you read a line at a time, you’ll want to use one of the getline( )functions .
Overloaded versions of get( )
The get( )function also comes in three other overloaded versions: one with no arguments that returns the next character, using an intreturn value; one that stuffs a character into its charargument, using a reference ; and one that stores directly into the underlying buffer structure of another iostream object. The latter is explored later in the chapter .
If you know exactly what you’re dealing with and want to move the bytes directly into a variable, an array, or a structure in memory, you can use the unformatted I/O function read( ). The first argument is a pointer to the destination memory, and the second is the number of bytes to read. This is especially useful if you’ve previously stored the information to a file, for example, in binary form using the complementary write( )member function for an output stream (using the same compiler, of course). You’ll see examples of all these functions later .
The Dateextractor shown earlier sets a stream’s fail bit under certain conditions. How does the user know when such a failure occurs? You can detect stream errors by either calling certain stream member functions to see if an error state has occurred, or if you don’t care what the particular error was, you can just evaluate the stream in a Boolean context. Both techniques derive from the state of a stream’s error bits .
The ios_baseclass, from which iosderives, [40] For this reason, we can write ios::failbit instead of ios_base::failbit to save typing.
defines four flags that you can use to test the state of a stream:
Flag |
Meaning |
badbit |
Some fatal (perhaps physical) error occurred. The stream should be considered unusable. |
eofbit |
End-of-input has occurred (either by encountering the physical end of a file stream or by the user terminating a console stream, such as with Ctrl-Z or Ctrl‑D). |
failbit |
An I/O operation failed, most likely because of invalid data (e.g., letters were found when trying to read a number). The stream is still usable. The failbit flag is also set when end-of-input occurs. |
goodbit |
All is well; no errors. End-of-input has not yet occurred. |
You can test whether any of these conditions have occurred by calling corresponding member functions that return a Boolean value indicating whether any of these have been set. The good( )stream member function returns true if none of the other three bits are set. The eof( )function returns true if eofbitis set, which happens with an attempt to read from a stream that has no more data (usually a file). Because end-of-input happens in C++ when trying to read past the end of the physical medium, failbitis also set to indicate that the "expected" data was not successfully read. The fail( )function returns true if either failbitor badbitis set, and bad( )returns true only if the badbitis set .
Читать дальше