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

📄 chapter06.html

📁 《C++编程思想》中文版。。。。。。。。。。。。。
💻 HTML
📖 第 1 页 / 共 5 页
字号:
<font color=#009900>// With constructors/destructors</font>
#ifndef STACK3_H
#define STACK3_H

<font color=#0000ff>class</font> Stack {
  <font color=#0000ff>struct</font> Link {
    <font color=#0000ff>void</font>* data;
    Link* next;
    Link(<font color=#0000ff>void</font>* dat, Link* nxt);
    ~Link();
  }* head;
<font color=#0000ff>public</font>:
  Stack();
  ~Stack();
  <font color=#0000ff>void</font> push(<font color=#0000ff>void</font>* dat);
  <font color=#0000ff>void</font>* peek();
  <font color=#0000ff>void</font>* pop();
};
#endif <font color=#009900>// STACK3_H ///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Not only does <B>Stack</B> have a
constructor and destructor, but so does the nested <STRIKE>class
</STRIKE><U>struct </U><B>Link</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Stack3.cpp {O}</font>
<font color=#009900>// Constructors/destructors</font>
#include <font color=#004488>"Stack3.h"</font>
#include <font color=#004488>"../require.h"</font>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

Stack::Link::Link(<font color=#0000ff>void</font>* dat, Link* nxt) {
  data = dat;
  next = nxt;
}

Stack::Link::~Link() { }

Stack::Stack() { head = 0; }

<font color=#0000ff>void</font> Stack::push(<font color=#0000ff>void</font>* dat) {
  head = <font color=#0000ff>new</font> Link(dat,head);
}

<font color=#0000ff>void</font>* Stack::peek() { 
  require(head != 0, <font color=#004488>"Stack empty"</font>);
  <font color=#0000ff>return</font> head-&gt;data; 
}

<font color=#0000ff>void</font>* Stack::pop() {
  <font color=#0000ff>if</font>(head == 0) <font color=#0000ff>return</font> 0;
  <font color=#0000ff>void</font>* result = head-&gt;data;
  Link* oldHead = head;
  head = head-&gt;next;
  <font color=#0000ff>delete</font> oldHead;
  <font color=#0000ff>return</font> result;
}

Stack::~Stack() {
  require(head == 0, <font color=#004488>"Stack not empty"</font>);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>Link::Link(&#160;)</B> constructor
simply initializes the <B>data</B> and <B>next</B> pointers, so in
<B>Stack::push(&#160;)</B> the line</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>head = <font color=#0000ff>new</font> Link(dat,head);</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">not only allocates a new link (using
dynamic object creation with the keyword <B>new</B>, introduced in Chapter 4),
but it also neatly initializes the pointers for that link.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You may wonder why the destructor for
<B>Link</B> doesn&#8217;t do anything &#8211; in particular, why doesn&#8217;t
it <B>delete</B> the <B>data</B> pointer? There are two problems. In Chapter 4,
where the <B>Stack</B> was introduced, it was pointed out that you cannot
properly <B>delete</B> a <B>void</B> pointer if it points to an object (an
assertion that will be proven in Chapter 13). But in addition, if the
<B>Link</B> destructor deleted the <B>data</B> pointer, <B>pop(&#160;)</B> would
end up returning a pointer to a deleted object, which would definitely be a bug.
This is sometimes referred to as the issue of
<A NAME="Index1348"></A><I>ownership</I>: the <B>Link</B> and thus the
<B>Stack</B> only holds the pointers, but is not responsible for cleaning them
up. This means that you must be very careful that you know who <I>is</I>
responsible. For example, if you don&#8217;t <B>pop(&#160;)</B> and
<B>delete</B> all the pointers on the <B>Stack</B>, they won&#8217;t get cleaned
up automatically by the <B>Stack</B>&#8217;s destructor. This can be a sticky
issue and leads to <A NAME="Index1349"></A><A NAME="Index1350"></A>memory leaks,
so knowing who is responsible for cleaning up an object can make the difference
between a successful program and a buggy one &#8211; that&#8217;s why
<B>Stack::~Stack(&#160;)</B> prints an error message if the <B>Stack</B> object
isn&#8217;t empty upon destruction.<B> </B></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because the allocation and cleanup of the
<B>Link</B> objects are hidden within <B>Stack</B> &#8211; it&#8217;s part of
the underlying implementation &#8211; you don&#8217;t see it happening in the
test program, although you <I>are</I> responsible for deleting the pointers that
come back from <B>pop(&#160;)</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Stack3Test.cpp</font>
<font color=#009900>//{L} Stack3</font>
<font color=#009900>//{T} Stack3Test.cpp</font>
<font color=#009900>// Constructors/destructors</font>
#include <font color=#004488>"Stack3.h"</font>
#include <font color=#004488>"../require.h"</font>
#include &lt;fstream&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main(<font color=#0000ff>int</font> argc, <font color=#0000ff>char</font>* argv[]) {
  requireArgs(argc, 1); <font color=#009900>// File name is argument</font>
  ifstream in(argv[1]);
  assure(in, argv[1]);
  Stack textlines;
  string line;
  <font color=#009900>// Read file and store lines in the stack:</font>
  <font color=#0000ff>while</font>(getline(in, line))
    textlines.push(<font color=#0000ff>new</font> string(line));
  <font color=#009900>// Pop the lines from the stack and print them:</font>
  string* s;
  <font color=#0000ff>while</font>((s = (string*)textlines.pop()) != 0) {
    cout &lt;&lt; *s &lt;&lt; endl;
    <font color=#0000ff>delete</font> s; 
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In this case, all the lines in
<B>textlines</B> are popped and deleted, but if they weren&#8217;t, you&#8217;d
get a <B>require(&#160;)</B> message that would mean there was a memory
leak.</FONT><A NAME="_Toc312373860"></A><A NAME="_Toc472654860"></A><BR></P></DIV>
<A NAME="Heading232"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Aggregate initialization</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">An <I>aggregate</I> is just what it
sounds like: a bunch of things clumped together. This definition includes
aggregates of mixed types, like <B>struct</B>s and <B>class</B>es. An array is
an aggregate of a single type.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Initializing aggregates can be
error-prone and tedious. C++ <I>aggregate
initialization<A NAME="Index1351"></A><A NAME="Index1352"></A></I> makes it much
safer. When you create an object that&#8217;s an aggregate, all you must do is
make an assignment, and the initialization will be taken care of by the
compiler. This assignment <A NAME="Index1353"></A>comes in several flavors,
depending on the type of aggregate you&#8217;re dealing with, but in all cases
the elements in the assignment must be surrounded by curly braces. For an array
of built-in types this is quite simple:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>int</font> a[5] = { 1, 2, 3, 4, 5 };</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you try to give more initializers
<A NAME="Index1354"></A>than there are array elements, the compiler gives an
error message. But what happens if you give <I>fewer</I> initializers? For
example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>int</font> b[6] = {0};</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here, the compiler will use the first
initializer for the first array element, and then use zero for all the elements
without initializers. Notice this initialization behavior doesn&#8217;t occur if
you define an array without a list of initializers. So the expression above is a
succinct way to initialize <A NAME="Index1355"></A>an array to
zero<A NAME="Index1356"></A>, without using a <B>for</B> loop, and without any
possibility of an off-by-one error
<A NAME="Index1357"></A><A NAME="Index1358"></A><A NAME="Index1359"></A>(Depending
on the compiler, it may also be more efficient than the <B>for</B>
loop.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A second shorthand for arrays is
<I>automatic
counting<A NAME="Index1360"></A><A NAME="Index1361"></A><A NAME="Index1362"></A></I>,
in which you let the compiler determine the size of the array based on the
number of initializers:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>int</font> c[] = { 1, 2, 3, 4 };</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now if you decide to add another element
to the array, you simply add another initializer. If you can set your code up so
it needs to be changed in only one spot, you reduce the chance of errors during
modification. But how do you determine the size of the array? The expression
<A NAME="Index1363"></A><B>sizeof c / sizeof *c</B> (size of the entire array
divided by the size of the first element) does the trick in a way that
doesn&#8217;t need to be changed if the array size
<A NAME="Index1364"></A><A NAME="Index1365"></A>changes</FONT><A NAME="fnB42" HREF="#fn42">[42]</A><FONT FACE="Georgia">:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; <font color=#0000ff>sizeof</font> c / <font color=#0000ff>sizeof</font> *c; i++)
 c[i]++;</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because structures are also aggregates,
they can be initialized in a similar fashion. Because a C-style <B>struct</B>
has all of its members <B>public</B>, they can be assigned
directly:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>struct</font> X {
  <font color=#0000ff>int</font> i;
  <font color=#0000ff>float</font> f;
  <font color=#0000ff>char</font> c;
};

X x1 = { 1, 2.2, 'c' };</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If<A NAME="Index1366"></A><A NAME="Index1367"></A><A NAME="Index1368"></A><A NAME="Index1369"></A>
you have an array of such objects, you can initialize them by using a nested set
of curly braces for each object:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>X x2[3] = { {1, 1.1, 'a'}, {2, 2.2, 'b'} };</PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here, the third object is initialized to
zero.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If any of the data members are
<B>private</B> (which is typically the case for a well-designed class in C++),
or even if everything&#8217;s <B>public</B> but there&#8217;s a constructor,
things are different. In the examples above, the initializers are assigned
directly to the elements of the aggregate, but constructors are a way of forcing
initialization to occur through a formal interface. Here, the constructors must
be called to perform the initialization. So if you have a <B>struct</B> that
looks like this,</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>struct</font> Y {
  <font color=#0000ff>float</font> f;
  <font color=#0000ff>int</font> i;
  Y(<font color=#0000ff>int</font> a);
}; </PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You must indicate constructor calls. The
best approach is the explicit one as follows:</FONT><BR></P></DIV>

⌨️ 快捷键说明

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