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

📄 chapter07.html

📁 《C++编程思想》中文版。。。。。。。。。。。。。
💻 HTML
📖 第 1 页 / 共 4 页
字号:
<font color=#0000ff>void</font> SuperVar::print() {
  <font color=#0000ff>switch</font> (vartype) {
    <font color=#0000ff>case</font> character:
      cout &lt;&lt; <font color=#004488>"character: "</font> &lt;&lt; c &lt;&lt; endl;
      <font color=#0000ff>break</font>;
    <font color=#0000ff>case</font> integer:
      cout &lt;&lt; <font color=#004488>"integer: "</font> &lt;&lt; i &lt;&lt; endl;
      <font color=#0000ff>break</font>;
    <font color=#0000ff>case</font> floating_point:
      cout &lt;&lt; <font color=#004488>"float: "</font> &lt;&lt; f &lt;&lt; endl;
      <font color=#0000ff>break</font>;
  }
}

<font color=#0000ff>int</font> main() {
  SuperVar A('c'), B(12), C(1.44F);
  A.print();
  B.print();
  C.print();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In the code above, the
<A NAME="Index1414"></A><B>enum</B> has no type name (it is an
<A NAME="Index1415"></A><A NAME="Index1416"></A>untagged enumeration). This is
acceptable if you are going to immediately define instances of the <B>enum</B>,
as is done here. There is no need to refer to the <B>enum&#8217;s</B> type name
in the future, so the type name is optional.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <A NAME="Index1417"></A><B>union</B>
has no type name and no variable name. This is called an
<A NAME="Index1418"></A><A NAME="Index1419"></A><I>anonymous union</I>, and
creates space for the <B>union</B> but doesn&#8217;t require accessing the
<B>union</B> elements with a variable name and the dot operator. For instance,
if your anonymous <B>union</B> is:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C07:AnonymousUnion.cpp</font>
<font color=#0000ff>int</font> main() {
  <font color=#0000ff>union</font> { 
    <font color=#0000ff>int</font> i; 
    <font color=#0000ff>float</font> f; 
  };
  <font color=#009900>// Access members without using qualifiers:</font>
  i = 12;
  f = 1.22;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that you access members of an
anonymous union just as if they were ordinary variables. The only difference is
that both variables occupy the same space. If the anonymous <B>union</B> is at
file scope (outside all functions and classes) then it must be declared
<B>static</B> so it has internal
linkage.<A NAME="Index1420"></A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Although <B>SuperVar</B> is now safe, its
usefulness is a bit dubious because the reason for using a <B>union</B> in the
first place is to save space, and the addition of <B>vartype</B> takes up quite
a bit of space relative to the data in the <B>union</B>, so the savings are
effectively eliminated. There are a couple of alternatives to make this scheme
workable. If the <B>vartype</B> controlled more than one <B>union</B> instance
&#8211; if they were all the same type &#8211; then you&#8217;d only need one
for the group and it wouldn&#8217;t take up more space. A more useful approach
is to have <B>#ifdef</B>s around all the <B>vartype</B> code, which can then
guarantee things are being used correctly during development and testing. For
shipping code, the extra space and time overhead can be
eliminated.</FONT><A NAME="_Toc312373869"></A><A NAME="_Toc472654871"></A><BR></P></DIV>
<A NAME="Heading242"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Default arguments</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>Stash3.h</B>, examine the two
constructors for <B>Stash(&#160;)</B>. They don&#8217;t seem all that different,
do they? In fact, the first constructor seems to be a special case of the second
one with the initial <B>size</B> set to zero. It&#8217;s a bit of a waste of
effort to create and maintain two different versions of a similar
function.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">C++ provides a remedy with <I>default
arguments<A NAME="Index1421"></A><A NAME="Index1422"></A></I>. A default
argument is a value given in the declaration that the compiler automatically
inserts if you don&#8217;t provide a value in the function call. In the
<B>Stash</B> example, we can replace the two functions:
<A NAME="Index1423"></A></FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>  Stash(<font color=#0000ff>int</font> size); <font color=#009900>// Zero quantity</font>
 Stash(<font color=#0000ff>int</font> size, <font color=#0000ff>int</font> initQuantity);</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">with the single
function:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>  Stash(<font color=#0000ff>int</font> size, <font color=#0000ff>int</font> initQuantity = 0);</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>Stash(int)</B> definition is
simply removed &#8211; all that is necessary is the single <B>Stash(int,
int)</B> definition.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now, the two object
definitions</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>  Stash A(100), B(100, 0);</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">will produce exactly the same results.
The identical constructor is called in both cases, but for <B>A</B>, the second
argument is automatically substituted by the compiler when it sees the first
argument is an <B>int</B> and that there is no second argument. The compiler has
seen the default argument, so it knows it can still make the function call if it
substitutes this second argument, which is what you&#8217;ve told it to do by
making it a default.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Default arguments are a convenience, as
function overloading is a convenience. Both features allow you to use a single
function name in different situations. The difference is that with default
arguments the compiler is substituting arguments when you don&#8217;t want to
put them in yourself. The preceding example is a good place to use default
arguments instead of function overloading; otherwise you end up with two or more
functions that have similar signatures and similar behaviors. If the functions
have very different behaviors, it doesn&#8217;t usually make sense to use
default arguments (for that matter, you might want to question whether two
functions with very different behaviors should have the same
name).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are two rules you must be aware of
when using default arguments. First, only
<A NAME="Index1424"></A><A NAME="Index1425"></A>trailing arguments may be
defaulted. That is, you can&#8217;t have a default argument followed by a
non-default argument. Second, once you start using default arguments in a
particular function call, all the subsequent arguments in that function&#8217;s
argument list must be defaulted (this follows from the first
rule).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Default arguments are only placed in the
declaration of a function (typically placed in a header
file)<A NAME="Index1426"></A><A NAME="Index1427"></A>. The compiler must see the
default value before it can use it. Sometimes people will place the commented
values of the default arguments in the function definition, for documentation
purposes</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> fn(<font color=#0000ff>int</font> x <font color=#009900>/* = 0 */</font>) { <font color=#009900>// ...</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><A NAME="_Toc472654872"></A><BR></P></DIV>
<A NAME="Heading243"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Placeholder arguments<BR><A NAME="Index1428"></A><A NAME="Index1429"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Arguments in a function declaration can
be declared <A NAME="Index1430"></A>without identifiers. When these are used
with default arguments, it can look a bit funny. You can end up
with</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> f(<font color=#0000ff>int</font> x, <font color=#0000ff>int</font> = 0, <font color=#0000ff>float</font> = 1.1);</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In C++ you don&#8217;t need identifiers
in the function definition, either:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> f(<font color=#0000ff>int</font> x, <font color=#0000ff>int</font>, <font color=#0000ff>float</font> flt) { <font color=#009900>/* ... */</font> }</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In the function body, <B>x</B> and
<B>flt</B> can be referenced, but not the middle argument, because it has no
name. Function calls must still provide a value for the placeholder, though:
<B>f(1)</B> or <B>f(1,2,3.0)</B>. This syntax allows you to put the argument in
as a placeholder without using it. The idea is that you might want to change the
function definition to use the placeholder later, without changing all the code
where the function is called. Of course, you can accomplish the same thing by
using a named argument, but if you define the argument for the function body
without using it, most compilers will give you a warning message, assuming
you&#8217;ve made a logical error. By intentionally leaving the argument name
out, you suppress this warning. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">More important, if you start out using a
function argument and later decide that you don&#8217;t need it, you can
effectively remove it without generating warnings, and yet not disturb any
client code that was calling the previous version of the
function.</FONT><A NAME="_Toc472654873"></A><BR></P></DIV>
<A NAME="Heading244"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Choosing overloading vs. default
arguments<BR><A NAME="Index1431"></A><A NAME="Index1432"></A><A NAME="Index1433"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Both function overloading and default
arguments provide a convenience for calling function names. However, it can seem
confusing at times to know which technique to use. For example, consider the
following tool that is designed to automatically manage blocks of
<A NAME="Index1434"></A>memory for you:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C07:Mem.h</font>
#ifndef MEM_H
#define MEM_H
<font color=#0000ff>typedef</font> <font color=#0000ff>unsigned</font> <font color=#0000ff>char</font> byte;

<font color=#0000ff>class</font> Mem {
  byte* mem;
  <font color=#0000ff>int</font> size;
  <font color=#0000ff>void</font> ensureMinSize(<font color=#0000ff>int</font> minSize);
<font color=#0000ff>public</font>:
  Mem();
  Mem(<font color=#0000ff>int</font> sz);
  ~Mem();
  <font color=#0000ff>int</font> msize();
  byte* pointer();
  byte* pointer(<font color=#0000ff>int</font> minSize);
}; 
#endif <font color=#009900>// MEM_H ///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A <B>Mem</B> object holds a block of
<B>byte</B>s and makes sure that you have enough storage. The default
constructor doesn&#8217;t allocate any storage, and the second constructor
ensures that there is <B>sz</B> storage in the <B>Mem</B> object. The destructor
releases the storage, <B>msize(&#160;)</B> tells you how many bytes there are
currently in the <B>Mem</B> object, and <B>pointer(&#160;)</B> produces a
pointer to the starting address of the storage (<B>Mem</B> is a fairly low-level
tool). There&#8217;s an overloaded version of <B>pointer(&#160;)</B> in which
client programmers can say that they want a pointer to a block of bytes that is
at least <B>minSize</B> large, and the member function ensures
this.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Both the constructor and the
<B>pointer(&#160;)</B> member function use the <B>private</B>
<B>ensureMinSize(&#160;)</B> member function to increase the size of the memory
block (notice that it&#8217;s not safe to hold the result of
<B>pointer(&#160;)</B> if the memory is resized).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#8217;s the implementation of the
class:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C07:Mem.cpp {O}</font>
#include <font color=#004488>"Mem.h"</font>
#include &lt;cstring&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

Mem::Mem() { mem = 0; size = 0; }

Mem::Mem(<font color=#0000ff>int</font> sz) {
  mem = 0;
  size = 0;
  ensureMinSize(sz); 
}

Mem::~Mem() { <font color=#0000ff>delete</font> []mem; }

<font color=#0000ff>int</font> Mem::msize() { <font color=#0000ff>return</font> size; }

<font color=#0000ff>void</font> Mem::ensureMinSize(<font color=#0000ff>int</font> minSize) {
  <font color=#0000ff>if</font>(size &lt; minSize) {
    byte* newmem = <font color=#0000ff>new</font> byte[minSize];
    memset(newmem + size, 0, minSize - size);
    memcpy(newmem, mem, size);
    <font color=#0000ff>delete</font> []mem;
    mem = newmem;
    size = minSize;
  }
}

byte* Mem::pointer() { <font color=#0000ff>return</font> mem; }

byte* Mem::pointer(<font color=#0000ff>int</font> minSize) {
  ensureMinSize(minSize);
  <font color=#0000ff>return</font> mem; 
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that
<B>ensureMinSize(&#160;)</B> is the only function responsible for allocating
memory, and that it is used from the second constructor and the second
overloaded form of <B>pointer(&#160;)</B>. Inside <B>ensureMinSize(&#160;)</B>,
nothing needs to be done if the <B>size</B> is large enough. If new storage must
be allocated in order to make the block bigger (which is also the case when the
block is of size zero after default construction), the new &#8220;extra&#8221;
portion is set to zero using the <A NAME="Index1435"></A>Standard C library
function <B>memset(&#160;)</B>, which was introduced in Chapter 5. The
subsequent function call is to the Standard C library function
<A NAME="Index1436"></A><B>memcpy(&#160;)</B>, which in this case copies the

⌨️ 快捷键说明

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