Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
As the Date extractor illustrated, you must be on
guard for erroneous input. If the input produces an unexpected value, the
process is skewed, and it s difficult to recover. In addition, formatted input
defaults to white space delimiters. Consider what happens when we collect the
code fragments from earlier in this chapter into a single program:
//: C04:Iosexamp.cpp {RunByHand}
// Iostream examples.
#include <iostream>
using namespace std;
int main() {
int i;
cin >> i;
float f;
cin >> f;
char c;
cin >> c;
char buf[100];
cin >> buf;
cout << "i = "
<< i << endl;
cout << "f = " << f <<
endl;
cout << "c = " << c <<
endl;
cout << "buf = " << buf
<< endl;
cout << flush;
cout << hex << "0x" << i
<< endl;
} ///:~
and give it the following input:
We expect the same output as if we gave it
but the output is, somewhat unexpectedly
i = 12
f = 1.4
c = c
buf = this
0xc
Notice that buf got only the first word because the
input routine looked for a space to delimit the input, which it saw after
this. In addition, if the continuous input string is longer than the storage
allocated for buf, we overrun the buffer.
In practice, you ll usually want to get input from
interactive programs a line at a time as a sequence of characters, scan them,
and then perform conversions once they re safely in a buffer. This way you
don t need to worry about the input routine choking on unexpected data.
Another consideration is the whole concept of a command-line
interface. This made sense in the past when the console was little more than a
glass typewriter, but the world is rapidly changing to one where the graphical
user interface (GUI) dominates. What is the meaning of console I/O in such a world? It makes much more sense to ignore cin altogether, other
than for simple examples or tests, and take the following approaches:
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, cout doesn 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 <iostream>
header in Date.h. The standard practice is to only declare classes,
something like this:
This is an age-old
technique for separating interface from implementation and is often called a forward
declaration (and ostream at 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 std namespace.
2. They
are templates.
The proper
declaration would be:
namespace std {
template<class charT, class traits =
char_traits<charT> >
class basic_ostream;
typedef basic_ostream<char> ostream;
}
(As you can see, like the string
class, 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: <iosfwd>. The Date header would then look
something like this:
// Date.h
#include <iosfwd>
class Date {
friend std::ostream&
operator<<(std::ostream&,
const Date&);
friend std::istream&
operator>>(std::istream&, Date&);
// Etc.
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |