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

📄 chapter06.html

📁 《C++编程思想》中文版。。。。。。。。。。。。。
💻 HTML
📖 第 1 页 / 共 5 页
字号:
<font color=#0000ff>public</font>:
  ~Y();
}; </PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The destructor is called automatically by
the compiler when the object goes out of
scope<A NAME="Index1305"></A><A NAME="Index1306"></A>. You can see where the
constructor gets called by the point of definition of the object, but the only
evidence for a destructor call is the closing brace of the scope that surrounds
the object. Yet the destructor is still called, even when you use
<A NAME="Index1307"></A><B>goto</B> <A NAME="Index1308"></A>to jump out of a
scope. (<B>goto</B> still exists in C++ for backward compatibility with C and
for the times when it comes in handy.) You should note that a <I>nonlocal
goto<A NAME="Index1309"></A><A NAME="Index1310"></A></I>, implemented by the
Standard C library functions <B>setjmp(&#160;)</B> <A NAME="Index1311"></A>and
<B>longjmp(&#160;)</B>, <A NAME="Index1312"></A>doesn&#8217;t cause destructors
to be called. (This is the specification, even if your compiler doesn&#8217;t
implement it that way. Relying on a feature that isn&#8217;t in the
specification means your code is nonportable.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#8217;s an example demonstrating the
features of constructors and destructors you&#8217;ve seen so
far:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Constructor1.cpp</font>
<font color=#009900>// Constructors &amp; destructors</font>
#include &lt;iostream&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>class</font> Tree {
  <font color=#0000ff>int</font> height;
<font color=#0000ff>public</font>:
  Tree(<font color=#0000ff>int</font> initialHeight);  <font color=#009900>// Constructor</font>
  ~Tree();  <font color=#009900>// Destructor</font>
  <font color=#0000ff>void</font> grow(<font color=#0000ff>int</font> years);
  <font color=#0000ff>void</font> printsize();
};

Tree::Tree(<font color=#0000ff>int</font> initialHeight) {
  height = initialHeight;
}

Tree::~Tree() {
  cout &lt;&lt; <font color=#004488>"inside Tree destructor"</font> &lt;&lt; endl;
  printsize();
}

<font color=#0000ff>void</font> Tree::grow(<font color=#0000ff>int</font> years) {
  height += years;
}

<font color=#0000ff>void</font> Tree::printsize() {
  cout &lt;&lt; <font color=#004488>"Tree height is "</font> &lt;&lt; height &lt;&lt; endl;
}

<font color=#0000ff>int</font> main() {
  cout &lt;&lt; <font color=#004488>"before opening brace"</font> &lt;&lt; endl;
  {
    Tree t(12);
    cout &lt;&lt; <font color=#004488>"after Tree creation"</font> &lt;&lt; endl;
    t.printsize();
    t.grow(4);
    cout &lt;&lt; <font color=#004488>"before closing brace"</font> &lt;&lt; endl;
  }
  cout &lt;&lt; <font color=#004488>"after closing brace"</font> &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#8217;s the output of the above
program:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>before opening brace
after Tree creation
Tree height is 12
before closing brace
inside Tree destructor
Tree height is 16
after closing brace</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that the destructor is
automatically called at the closing brace of the scope that encloses
it.</FONT><A NAME="_Toc312373855"></A><A NAME="_Toc472654855"></A><BR></P></DIV>
<A NAME="Heading227"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Elimination of the definition
block<BR><A NAME="Index1313"></A><A NAME="Index1314"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In C<A NAME="Index1315"></A>, you must
always define all the variables at the beginning of a block, after the opening
brace. This is not an uncommon requirement in programming languages, and the
reason given has often been that it&#8217;s &#8220;good programming
style.&#8221; On this point, I have my suspicions. It has always seemed
inconvenient to me, as a programmer, to pop back to the beginning of a block
every time I need a new variable. I also find code more readable when the
variable definition is close to its point of
use.<A NAME="Index1316"></A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Perhaps these arguments are stylistic. In
C++, however, there&#8217;s a significant problem in being forced to define all
objects at the beginning of a scope. If a constructor exists, it must be called
when the object is created. However, if the constructor takes one or more
initialization arguments, how do you know you will have that initialization
information at the beginning of a scope? In the general programming situation,
you won&#8217;t. Because C has no concept of <B>private</B>, this separation of
definition and initialization is no problem. However, C++ guarantees that when
an object is created, it is simultaneously initialized. This ensures that you
will have no uninitialized objects running around in your system. C
doesn&#8217;t care; in fact, C <I>encourages</I> this practice by requiring you
to define variables at the beginning of a block before you necessarily have the
initialization
information</FONT><A NAME="fnB38" HREF="#fn38">[38]</A><FONT FACE="Georgia">.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In general, C++ will not allow you to
create an object before you have the initialization information for the
constructor. Because of this, the language wouldn&#8217;t be feasible if you had
to define variables at the beginning of a scope. In fact, the style of the
language seems to encourage the definition of an object as close to its point of
use as possible. In C++, any rule that applies to an &#8220;object&#8221;
automatically refers to an object of a built-in type as well. This means that
any class object or variable of a built-in type can also be defined at any point
in a scope. It also means that you can wait until you have the information for a
variable before defining it, so you can always
<A NAME="Index1317"></A><A NAME="Index1318"></A>define and initialize at the
same time:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:DefineInitialize.cpp</font>
<font color=#009900>// Defining variables anywhere</font>
#include <font color=#004488>"../require.h"</font>
#include &lt;iostream&gt;
#include &lt;string&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>class</font> G {
  <font color=#0000ff>int</font> i;
<font color=#0000ff>public</font>:
  G(<font color=#0000ff>int</font> ii);
};

G::G(<font color=#0000ff>int</font> ii) { i = ii; }

<font color=#0000ff>int</font> main() {
  cout &lt;&lt; <font color=#004488>"initialization value? "</font>;
  <font color=#0000ff>int</font> retval = 0;
  cin &gt;&gt; retval;
  require(retval != 0);
  <font color=#0000ff>int</font> y = retval + 3;
  G g(y);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that some code is executed,
then <B>retval</B> is defined, initialized, and used to capture user input, and
then <B>y</B> and <B>g</B> are defined. C, on the other hand, does not allow a
variable to be defined anywhere except at the beginning of the
scope.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In general, you should define variables
as close to their point of use as possible, and always initialize them when they
are defined. (This is a stylistic suggestion for built-in types, where
initialization is optional.) This is a safety issue. By reducing the duration of
the variable&#8217;s availability within the scope, you are reducing the chance
it will be misused in some other part of the scope. In addition, readability is
improved because the reader doesn&#8217;t have to jump back and forth to the
beginning of the scope to know the type of a
variable.</FONT><A NAME="_Toc312373856"></A><A NAME="_Toc472654856"></A><BR></P></DIV>
<A NAME="Heading228"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
for loops</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In C++, you will often see a <B>for</B>
loop <A NAME="Index1319"></A><A NAME="Index1320"></A>counter defined right
inside the <B>for</B> expression:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 0; j &lt; 100; j++) {
    cout &lt;&lt; <font color=#004488>"j = "</font> &lt;&lt; j &lt;&lt; endl;
}
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 100; i++)
 cout &lt;&lt; <font color=#004488>"i = "</font> &lt;&lt; i &lt;&lt; endl;</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The statements above are important
special cases, which cause confusion to new C++ programmers.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The variables <B>i</B> and <B>j</B> are
defined directly inside the <B>for</B> expression (which you cannot do in C).
They are then available for use in the <B>for</B> loop. It&#8217;s a very
convenient syntax because the context removes all question about the purpose of
<B>i</B> and <B>j</B>, so you don&#8217;t need to use such ungainly names as
<B>i_loop_counter</B> for clarity.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">However, some confusion may result if you
expect the lifetimes of the variables <B>i </B>and <B>j </B>to extend beyond the
scope of the for loop &#8211; they do
not</FONT><A NAME="fnB39" HREF="#fn39">[39]</A><A NAME="Index1321"></A><A NAME="Index1322"></A><A NAME="Index1323"></A><A NAME="Index1324"></A><FONT FACE="Georgia">.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Chapter 3 points out that <B>while</B>
and <B>switch</B> statements also allow the definition of objects in their
control expressions, although this usage seems far less important than with the
<B>for</B> loop.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Watch out for local variables that
<A NAME="Index1325"></A><A NAME="Index1326"></A><A NAME="Index1327"></A>hide
variables from the enclosing scope. In general, using the same name for a nested
variable and a variable that is global to that scope is confusing and error
prone</FONT><A NAME="fnB40" HREF="#fn40">[40]</A><FONT FACE="Georgia">.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">I find small scopes an indicator of good
design. If you have several pages for a single function, perhaps you&#8217;re
trying to do too much with that function. More granular functions are not only
more useful, but it&#8217;s also easier to find
bugs<A NAME="Index1328"></A>.</FONT><A NAME="_Toc312373857"></A><A NAME="_Toc472654857"></A><BR></P></DIV>
<A NAME="Heading229"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Storage allocation</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A variable can now be defined at any
point in a scope, so it might seem that the storage for a variable may not be
defined until its point of definition. It&#8217;s actually more likely that the
compiler will follow the practice in C of allocating all the storage for a scope
at the opening brace of that scope. It doesn&#8217;t matter because, as a
programmer, you can&#8217;t access the storage (a.k.a. the object) until it has
been defined</FONT><A NAME="fnB41" HREF="#fn41">[41]</A><FONT FACE="Georgia">.
Although the storage is
allocated<A NAME="Index1329"></A><A NAME="Index1330"></A> at the beginning of
the <A NAME="Index1331"></A>block, the constructor call doesn&#8217;t happen
until the sequence point where the object is defined because the identifier
isn&#8217;t available until then. The compiler even checks to make sure that you
don&#8217;t put the object definition (and thus the constructor call) where the
sequence point <A NAME="Index1332"></A><A NAME="Index1333"></A>only
conditionally passes through it, such as in a
<A NAME="Index1334"></A><B>switch</B> <A NAME="Index1335"></A>statement or
somewhere a <A NAME="Index1336"></A><B>goto</B> <A NAME="Index1337"></A>can jump
past it. Uncommenting the statements in the following code will generate a
warning or an error:</FONT><BR></P></DIV>

⌨️ 快捷键说明

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