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

📄 chapter16.html

📁 《C++编程思想》中文版。。。。。。。。。。。。。
💻 HTML
📖 第 1 页 / 共 5 页
字号:
inlined:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C16:TStack.h</font>
<font color=#009900>// The Stack as a template</font>
#ifndef TSTACK_H
#define TSTACK_H

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T&gt;
<font color=#0000ff>class</font> Stack {
  <font color=#0000ff>struct</font> Link {
    T* data;
    Link* next;
    Link(T* dat, Link* nxt): 
      data(dat), next(nxt) {}
  }* head;
<font color=#0000ff>public</font>:
  Stack() : head(0) {}
  ~Stack(){ 
    <font color=#0000ff>while</font>(head)
      <font color=#0000ff>delete</font> pop();
  }
  <font color=#0000ff>void</font> push(T* dat) {
    head = <font color=#0000ff>new</font> Link(dat, head);
  }
  T* peek() <font color=#0000ff>const</font> {
    <font color=#0000ff>return</font> head ? head-&gt;data : 0; 
  }
  T* pop(){
    <font color=#0000ff>if</font>(head == 0) <font color=#0000ff>return</font> 0;
    T* result = head-&gt;data;
    Link* oldHead = head;
    head = head-&gt;next;
    <font color=#0000ff>delete</font> oldHead;
    <font color=#0000ff>return</font> result;
  }
};
#endif <font color=#009900>// TSTACK_H ///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you compare this to the
<B>OStack.h</B> example at the end of Chapter 15, you will see that <B>Stack</B>
is virtually identical, except that <B>Object</B> has been replaced with
<B>T</B>. The test program is also nearly identical, except that the necessity
for multiply-inheriting from <B>string</B> and <B>Object</B> (and even the need
for <B>Object </B>itself) has been eliminated. Now there is no <B>MyString</B>
class to announce its destruction, so a small new class is added to show a
<B>Stack </B>container cleaning up its objects:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C16:TStackTest.cpp</font>
<font color=#009900>//{T} TStackTest.cpp</font>
#include <font color=#004488>"TStack.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>class</font> X {
<font color=#0000ff>public</font>:
  <font color=#0000ff>virtual</font> ~X() { cout &lt;&lt; <font color=#004488>"~X "</font> &lt;&lt; endl; }
};

<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&lt;string&gt; 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 some lines from the stack:</font>
  string* s;
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 10; i++) {
    <font color=#0000ff>if</font>((s = (string*)textlines.pop())==0) <font color=#0000ff>break</font>;
    cout &lt;&lt; *s &lt;&lt; endl;
    <font color=#0000ff>delete</font> s; 
  } <font color=#009900>// The destructor deletes the other strings.</font>
  <font color=#009900>// Show that correct destruction happens:</font>
  Stack&lt;X&gt; xx;
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 0; j &lt; 10; j++)
    xx.push(<font color=#0000ff>new</font> X);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The
<A NAME="Index2655"></A><A NAME="Index2656"></A>destructor for <B>X</B> is
virtual, not because it&#8217;s necessary here, but because <B>xx</B> could
later be used to hold objects derived from <B>X</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice how easy it is to create different
kinds of <B>Stack</B>s for <B>string</B> and for <B>X</B>.<B> </B>Because of the
template, you get the best of both worlds: the ease of use of the <B>Stack</B>
class along with proper cleanup.</FONT><A NAME="_Toc472655056"></A><BR></P></DIV>
<A NAME="Heading475"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Templatized pointer Stash<BR><A NAME="Index2657"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Reorganizing the <B>PStash</B> code into
a template isn&#8217;t quite so simple because there are a number of member
functions that should not be
<A NAME="Index2658"></A><A NAME="Index2659"></A>inlined. However, as a template
those function definitions still belong in the
<A NAME="Index2660"></A><A NAME="Index2661"></A>header file (the compiler and
linker take care of any multiple definition problems). The code looks quite
similar to the ordinary <B>PStash</B> except that you&#8217;ll notice the size
of the increment (used by <B>inflate(&#160;)</B>) has been templatized as a
non-class parameter with a default value, so that the increment size can be
modified at the point of instantiation (notice that this means that the
increment size is fixed; you may also argue that the increment size should be
changeable throughout the lifetime of the object):</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C16:TPStash.h</font>
#ifndef TPSTASH_H
#define TPSTASH_H

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr = 10&gt;
<font color=#0000ff>class</font> PStash {
  <font color=#0000ff>int</font> quantity; <font color=#009900>// Number of storage spaces</font>
  <font color=#0000ff>int</font> next; <font color=#009900>// Next empty space</font>
  T** storage;
  <font color=#0000ff>void</font> inflate(<font color=#0000ff>int</font> increase = incr);
<font color=#0000ff>public</font>:
  PStash() : quantity(0), next(0), storage(0) {}
  ~PStash();
  <font color=#0000ff>int</font> add(T* element);
  T* <font color=#0000ff>operator</font>[](<font color=#0000ff>int</font> index) <font color=#0000ff>const</font>; <font color=#009900>// Fetch</font>
  <font color=#009900>// Remove the reference from this PStash:</font>
  T* remove(<font color=#0000ff>int</font> index);
  <font color=#009900>// Number of elements in Stash:</font>
  <font color=#0000ff>int</font> count() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> next; }
};

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr&gt;
<font color=#0000ff>int</font> PStash&lt;T, incr&gt;::add(T* element) {
  <font color=#0000ff>if</font>(next &gt;= quantity)
    inflate(incr);
  storage[next++] = element;
  <font color=#0000ff>return</font>(next - 1); <font color=#009900>// Index number</font>
}

<font color=#009900>// Ownership of remaining pointers:</font>
<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr&gt;
PStash&lt;T, incr&gt;::~PStash() {
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; next; i++) {
    <font color=#0000ff>delete</font> storage[i]; <font color=#009900>// Null pointers OK</font>
    storage[i] = 0; <font color=#009900>// Just to be safe</font>
  }
  <font color=#0000ff>delete</font> []storage;
}

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr&gt;
T* PStash&lt;T, incr&gt;::<font color=#0000ff>operator</font>[](<font color=#0000ff>int</font> index) <font color=#0000ff>const</font> {
  require(index &gt;= 0,
    <font color=#004488>"PStash::operator[] index negative"</font>);
  <font color=#0000ff>if</font>(index &gt;= next)
    <font color=#0000ff>return</font> 0; <font color=#009900>// To indicate the end</font>
  require(storage[index] != 0, 
    <font color=#004488>"PStash::operator[] returned null pointer"</font>);
  <font color=#009900>// Produce pointer to desired element:</font>
  <font color=#0000ff>return</font> storage[index];
}

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr&gt;
T* PStash&lt;T, incr&gt;::remove(<font color=#0000ff>int</font> index) {
  <font color=#009900>// operator[] performs validity checks:</font>
  T* v = <font color=#0000ff>operator</font>[](index);
  <font color=#009900>// "Remove" the pointer:</font>
  <font color=#0000ff>if</font>(v != 0) storage[index] = 0;
  <font color=#0000ff>return</font> v;
}

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr&gt;
<font color=#0000ff>void</font> PStash&lt;T, incr&gt;::inflate(<font color=#0000ff>int</font> increase) {
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> psz = <font color=#0000ff>sizeof</font>(T*);
  T** st = <font color=#0000ff>new</font> T*[quantity + increase];
  memset(st, 0, (quantity + increase) * psz);
  memcpy(st, storage, quantity * psz);
  quantity += increase;
  <font color=#0000ff>delete</font> []storage; <font color=#009900>// Old storage</font>
  storage = st; <font color=#009900>// Point to new memory</font>
}
#endif <font color=#009900>// TPSTASH_H ///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The default increment size used here is
small to guarantee that calls to <B>inflate(&#160;) </B>occur. This way we can
make sure it works correctly.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To test the
<A NAME="Index2662"></A>ownership control of the templatized <B>PStash</B>, the
following class will report
<A NAME="Index2663"></A><A NAME="Index2664"></A>creations and destructions of
itself, and also guarantee that all objects that have been created were also
destroyed. <B>AutoCounter</B> will allow only objects of its type to be created
on the
stack<A NAME="Index2665"></A><A NAME="Index2666"></A><A NAME="Index2667"></A><A NAME="Index2668"></A>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C16:AutoCounter.h</font>
#ifndef AUTOCOUNTER_H
#define AUTOCOUNTER_H
#include <font color=#004488>"../require.h"</font>
#include &lt;iostream&gt;
#include &lt;set&gt; <font color=#009900>// Standard C++ Library container</font>
#include &lt;string&gt;

<font color=#0000ff>class</font> AutoCounter {
  <font color=#0000ff>static</font> <font color=#0000ff>int</font> count;
  <font color=#0000ff>int</font> id;
  <font color=#0000ff>class</font> CleanupCheck {
    std::set&lt;AutoCounter*&gt; trace;
  <font color=#0000ff>public</font>:
    <font color=#0000ff>void</font> add(AutoCounter* ap) {
      trace.insert(ap);
    }
    <font color=#0000ff>void</font> remove(AutoCounter* ap) {
      require(trace.erase(ap) == 1,
        <font color=#004488>"Attempt to delete AutoCounter twice"</font>);
    }
    ~CleanupCheck() {
      std::cout &lt;&lt; <font color=#004488>"~CleanupCheck()"</font>&lt;&lt; std::endl;
      require(trace.size() == 0,
       <font color=#004488>"All AutoCounter objects not cleaned up"</font>);
    }
  };
  <font color=#0000ff>static</font> CleanupCheck verifier;
  AutoCounter() : id(count++) {
    verifier.add(<font color=#0000ff>this</font>); <font color=#009900>// Register itself</font>
    std::cout &lt;&lt; <font color=#004488>"created["</font> &lt;&lt; id &lt;&lt; <font color=#004488>"]"</font> 
              &lt;&lt; std::endl;
  }

⌨️ 快捷键说明

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