⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap05.htm

📁 C++编程思想第二版第二卷
💻 HTM
📖 第 1 页 / 共 5 页
字号:
#endif <font color=#009900>// FULLWRAP_H ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This class contains almost all the file
I/O functions from <B>cstdio</B>. <B>vfprintf(&#160;)</B> is missing; it is used
to implement the <B>printf(&#160;)</B> <A NAME="Index174"></A>member
function.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>File</B> has the same constructor as
in the previous example, and it also has a default constructor. The default
constructor is important if you want to create an array of <B>File</B> objects
or use a <B>File</B> object as a member of another class where the
initialization doesn&#8217;t happen in the constructor (but sometime after the
enclosing object is created).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The default constructor sets the private
<B>FILE</B> pointer <B>f</B> to zero. But now, before any reference to <B>f</B>,
its value must be checked to ensure it isn&#8217;t zero. This is accomplished
with the last member function in the class, <B>F(&#160;)</B>, which is
<B>private</B> because it is intended to be used only by other member functions.
(We don&#8217;t want to give the user direct access to the <B>FILE</B> structure
in this class.)</FONT><A NAME="fnB10" HREF="#fn10">[10]</A><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This is not a terrible solution by any
means. It&#8217;s quite functional, and you could imagine making similar classes
for standard (console) I/O and for in-core formatting (reading/writing a piece
of memory rather than a file or the console).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The big stumbling block is the runtime
interpreter<A NAME="Index175"></A>
<A NAME="Index176"></A><A NAME="Index177"></A>used for the variable-argument
list functions. This is the code that parses through your format string at
runtime and grabs and interprets arguments from the variable argument list.
It&#8217;s a problem for four reasons.</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">Even if you use only a
fraction of the functionality of the interpreter, the whole thing gets loaded.
So if you say:</FONT><BR><TT><FONT FACE="Courier New">printf("%c",
'x');</FONT></TT><BR><FONT FACE="Georgia">you&#8217;ll get the whole package,
including the parts that print out floating-point numbers and strings.
There&#8217;s no option for reducing the amount of space used by the
program.</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">Because the
interpretation happens at runtime there&#8217;s a performance overhead you
can&#8217;t get rid of. It&#8217;s frustrating because all the information is
<I>there</I> in the format string at compile time, but it&#8217;s not evaluated
until runtime. However, if you could parse the arguments in the format string at
compile time you could make hard function calls that have the potential to be
much faster than a runtime interpreter (although the <B>printf(&#160;)</B>
family of functions is usually quite well
optimized).</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">A worse
problem occurs because the evaluation of the format string doesn&#8217;t happen
until runtime: there can be no compile-time error
checkin</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">g<A NAME="Index178"></A><A NAME="Index179"></A>.
You&#8217;re probably very familiar with this problem if you&#8217;ve tried to
find bugs that came from using the wrong number or type of arguments in a
<B>printf(&#160;)</B> statement. C++ makes a big deal out of compile-time error
checking to find errors early and make your life easier. It seems a shame to
throw it away for an I/O library, especially because I/O is used a
lot.</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">For C++, the most
important problem is that the <B>printf(&#160;)</B> family of functions is not
particularly
extensibl</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">e<A NAME="Index180"></A>.
They&#8217;re really designed to handle the four basic data types
<A NAME="Index181"></A>in C <A NAME="Index182"></A>(<B>char</B>, <B>int</B>,
<B>float</B>, <B>double</B> and their variations). You might think that every
time you add a new class, you could add an overloaded <B>printf(&#160;)</B> and
<B>scanf(&#160;)</B> function (and their variants for files and strings) but
remember, overloaded functions must have different types in their argument lists
and the <B>printf(&#160;)</B> family hides its type information in the format
string and in the variable argument
list<A NAME="Index183"></A><A NAME="Index184"></A>. For a language like C++,
whose goal is to be able to easily add new data types, this is an ungainly
restriction.</FONT><A NAME="_Toc305628664"></A><A NAME="_Toc312373876"></A><A NAME="_Toc519041944"></A><BR></P></DIV>
<A NAME="Heading108"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Iostreams to the rescue</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">All these issues make it clear that one
of the first standard class libraries for C++ should handle I/O. Because
&#8220;hello, world&#8221; is the first program just about everyone writes in a
new language, and because I/O is part of virtually every program, the I/O
library in C++ must be particularly easy to use. It also has the much greater
challenge that it can never know all the classes it must accommodate, but it
must nevertheless be adaptable to use any new class. Thus its constraints
required that this first class be a truly inspired design.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This chapter won&#8217;t look at the
details of the design and how to add iostream functionality to your own classes
(you&#8217;ll learn that in a later chapter). First, you need to learn to use
iostreams. In addition to gaining a great deal of leverage and clarity in your
dealings with I/O and formatting, you&#8217;ll also see how a really powerful
C++ library can
work.</FONT><A NAME="_Toc312373877"></A><A NAME="_Toc519041945"></A><BR></P></DIV>
<A NAME="Heading109"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Sneak preview of operator overloading<BR><A NAME="Index185"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Before you can use the iostreams library,
you must understand one new feature of the language that won&#8217;t be covered
in detail until a later chapter. To use iostreams, you need to know that in C++
all the operators can take on different meanings. In this chapter, we&#8217;re
particularly interested in <B>&lt;&lt;</B> and <B>&gt;&gt;</B>. The statement
&#8220;operators can take on different meanings&#8221; deserves some extra
insight.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In Chapter XX, you learned how function
overloading allows you to use the same function name with different argument
lists. Now imagine that when the compiler sees an expression consisting of an
argument followed by an operator followed by an argument, it simply calls a
function. That is, an operator is simply a function call with a different
syntax.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course, this is C++, which is very
particular about data types. So there must be a previously declared function to
match that operator and those particular argument types, or the compiler will
not accept the expression.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">What most people find immediately
disturbing about operator overloading is the thought that maybe everything they
know about operators in C is suddenly wrong. This is absolutely false. Here are
two of the sacred design goals of
C++<A NAME="Index186"></A><A NAME="Index187"></A>:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">A program that compiles in
C will compile in C++. The only compilation errors and warnings from the C++
compiler will result from the &#8220;holes&#8221; in the C language, and fixing
these will require only local editing. (Indeed, the complaints by the C++
compiler usually lead you directly to undiscovered bugs in the C
program.)</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">The C++
compiler will not secretly change the behavior of a C program by recompiling it
under C++.</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Keeping these goals
in mind will help answer a lot of questions; knowing there are no capricious
changes to C when moving to C++ helps make the transition easy. In particular,
operators for built-in types won&#8217;t suddenly start working differently
&#8211; you cannot change their meaning. Overloaded operators can be created
only where new data types are involved. So you can create a new overloaded
operator for a new class, but the expression</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>1 &lt;&lt; 4;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">won&#8217;t suddenly change its meaning,
and the illegal code</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>1.414 &lt;&lt; 1;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">won&#8217;t suddenly start
working.</FONT><A NAME="_Toc312373878"></A><A NAME="_Toc519041946"></A><BR></P></DIV>
<A NAME="Heading110"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Inserters and extractors</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In the iostreams library, two operators
have been overloaded to make the use of iostreams easy. The operator
<B>&lt;&lt;</B> <A NAME="Index188"></A>is often referred to as an
<I>inserter</I> <A NAME="Index189"></A>for iostreams, and the operator
<B>&gt;&gt;</B> <A NAME="Index190"></A>is often referred to as an
<I>extractor<A NAME="Index191"></A></I>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A <I>stream</I> <A NAME="Index192"></A>is
an object that formats and holds bytes. You can have an input stream
(<I>istream<A NAME="Index193"></A></I>) or an output stream
(<I>ostream<A NAME="Index194"></A></I>). There are different types of istreams
and ostreams: <I>ifstreams <A NAME="Index195"></A></I>and <I>ofstreams</I>
<A NAME="Index196"></A>for files<A NAME="Index197"></A>, <I>istrstreams
<A NAME="Index198"></A></I>, and <I>ostrstreams</I> <A NAME="Index199"></A>for
<B>char*</B> <A NAME="Index200"></A>memory (in-core formatting), and
<I>istringstreams</I> <A NAME="Index201"></A>&amp; <I>ostringstreams</I>
<A NAME="Index202"></A>for interfacing with the Standard C++ <B>string</B>
class<A NAME="Index203"></A><A NAME="Index204"></A><A NAME="Index205"></A><A NAME="Index206"></A>.
All these stream objects have the same interface, regardless of whether
you&#8217;re working with a file, standard I/O, a piece of memory or a
<B>string</B> object. The single interface you learn also works for extensions
added to support new classes.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If a stream is capable of producing bytes
(an istream), you can get information from the stream using an extractor. The
extractor produces and formats the type of information that&#8217;s expected by
the destination object. To see an example of this, you can use the <B>cin</B>
object, which is the iostream equivalent of <B>stdin</B> in C, that is,
redirectable standard input. This object is pre-defined whenever you include the
<B>iostream.h </B>header file. (Thus, the iostream library is automatically
linked with most compilers.)</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>  <font color=#0000ff>int</font> i;
  cin &gt;&gt; i;

  <font color=#0000ff>float</font> f;
  cin &gt;&gt; f;

  <font color=#0000ff>char</font> c;
  cin &gt;&gt; c;

  <font color=#0000ff>char</font> buf[100];
  cin &gt;&gt; buf;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There&#8217;s an overloaded <B>operator
&gt;&gt;</B> for every data type you can use as the right-hand argument of
<B>&gt;&gt;</B> in an iostream statement. (You can also overload your own, which
you&#8217;ll see in a later chapter.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To find out what you have in the various
variables, you can use the <B>cout</B> object (corresponding to standard output;
there&#8217;s also a <B>cerr</B> object corresponding to standard error) with
the inserter <B>&lt;&lt;</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>  cout &lt;&lt; <font color=#004488>"i = "</font>;
  cout &lt;&lt; i;
  cout &lt;&lt; <font color=#004488>"\n"</font>;
  cout &lt;&lt; <font color=#004488>"f = "</font>;
  cout &lt;&lt; f;
  cout &lt;&lt; <font color=#004488>"\n"</font>;
  cout &lt;&lt; <font color=#004488>"c = "</font>;
  cout &lt;&lt; c;
  cout &lt;&lt; <font color=#004488>"\n"</font>;
  cout &lt;&lt; <font color=#004488>"buf = "</font>;
  cout &lt;&lt; buf;
  cout &lt;&lt; <font color=#004488>"\n"</font>;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This is notably tedious, and
doesn&#8217;t seem like much of an improvement over <B>printf(&#160;)</B>, type
checking or no. Fortunately, the overloaded inserters and extractors in
iostreams are designed to be chained <A NAME="Index207"></A>together into a
complex expression that is much easier to write:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>  cout &lt;&lt; <font color=#004488>"i = "</font> &lt;&lt; i &lt;&lt; endl;
  cout &lt;&lt; <font color=#004488>"f = "</font> &lt;&lt; f &lt;&lt; endl;
  cout &lt;&lt; <font color=#004488>"c = "</font> &lt;&lt; c &lt;&lt; endl;
  cout &lt;&lt; <font color=#004488>"buf = "</font> &lt;&lt; buf &lt;&lt; endl;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You&#8217;ll understand how this can
happen in a later chapter, but for now it&#8217;s sufficient to take the
attitude of a class user and just know it works that way.</FONT><BR></P></DIV>
<A NAME="Heading111"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H4 ALIGN="LEFT">
Manipulators</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">One new element has been added here: a
<I>manipulator</I> <A NAME="Index208"></A>called
<B>endl<A NAME="Index209"></A></B>. A manipulator acts on the stream itself; in
this case it inserts a newline and <I>flushes</I> the stream (puts out all
pending characters that have been stored in the internal stream buffer but not
yet output). You can also just flush
<A NAME="Index210"></A><A NAME="Index211"></A>the stream:</FONT><BR></P></DIV>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -