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

📄 chap07.htm

📁 This is the second part of that lab manual to teach you how to make real-time programme and how to d
💻 HTM
📖 第 1 页 / 共 5 页
字号:
of <B>string</B> onto any <B>ostream</B>. Notice in <B>write(&#160;) </B>that
you can have a default argument for a reference.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The implementation is quite
simple:</FONT><BR></P></DIV>

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

<font color=#0000ff>void</font> FileEditor::open(<font color=#0000ff>char</font>* filename) {
  ifstream in(filename);
  assure(in, filename);
  string line;
  <font color=#0000ff>while</font>(getline(in, line))
    push_back(line);
}

<font color=#009900>// Could also use copy() here:</font>
<font color=#0000ff>void</font> FileEditor::write(ostream&amp; out) {
  <font color=#0000ff>for</font>(iterator w = begin();  w != end(); w++)
    out &lt;&lt; *w &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The functions from
<B>StringVector.cpp</B> are simply repackaged. Often this is the way classes
evolve &#8211; you start by creating a program to solve a particular
application, then discover some commonly-used functionality within the program
that can be turned into a class.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The line numbering program can now be
rewritten using <B>FileEditor</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C07:FEditTest.cpp</font>
<font color=#009900>//{L} FileEditor ../TestSuite/Test</font>
<font color=#009900>// Test the FileEditor tool</font>
#include <font color=#004488>"FileEditor.h"</font>
#include <font color=#004488>"..</font><font color=#004488>/require.h"</font>
#include &lt;sstream&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[]) {
  FileEditor file;
  <font color=#0000ff>if</font>(argc &gt; 1) {
    file.open(argv[1]);
  } <font color=#0000ff>else</font> {
    file.open(<font color=#004488>"FEditTest.cpp"</font>);
  }
  <font color=#009900>// Do something to the lines...</font>
  <font color=#0000ff>int</font> i = 1;
  FileEditor::iterator w = file.begin();
  <font color=#0000ff>while</font>(w != file.end()) {
    ostringstream ss;
    ss &lt;&lt; i++;
    *w = ss.str() + <font color=#004488>": "</font> + *w;
    w++;
  }
  <font color=#009900>// Now send them to cout:</font>
  file.write();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now the operation of reading
the file is in the constructor:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>FileEditor file(argv[1]);</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">(or in the <B>open( ) </B>method) and
writing happens in the single line (which defaults to sending the output to
<B>cout</B>):</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>file.write();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The bulk of the program is involved with
actually modifying the file in
memory.</FONT><A NAME="_Toc519042016"></A><BR></P></DIV>
<A NAME="Heading195"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
A plethora of iterators</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As mentioned earlier, the iterator is the
abstraction that allows a piece of code to be <I>generic</I>, and to work with
different types of containers without knowing the underlying structure of those
containers.<I> </I>Every container produces iterators. You must always be able
to say:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>ContainerType::iterator
ContainerType::const_iterator</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">to produce the types of the iterators
produced by that container. Every container has a <B>begin(&#160;)</B> method
that produces an iterator indicating the beginning of the elements in the
container, and an <B>end(&#160;)</B> method that produces an iterator which is
the as the <I>past-the-end value</I> of the container. If the container is
<B>const</B>&#184; <B>begin(&#160;)</B> and <B>end(&#160;)</B> produce
<B>const</B> iterators.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Every iterator can be moved forward to
the next element using the <B>operator++</B> (an iterator may be able to do more
than this, as you shall see, but it must at least support forward movement with
<B>operator++</B>).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The basic iterator is only guaranteed to
be able to perform <B>==</B> and <B>!=</B> comparisons. Thus, to move an
iterator <B>it</B> forward without running it off the end you say something
like:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>while</font>(it != pastEnd) {
  <font color=#009900>// Do something</font>
  it++;
}</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Where <B>pastEnd</B> is the past-the-end
value produced by the container&#8217;s <B>end(&#160;)</B> member
function.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">An iterator can be used to produce the
element that it is currently selecting within a container by dereferencing the
iterator. This can take two forms. If <B>it </B>is an iterator and <B>f(&#160;)
</B>is a member function of the objects held in the container that the iterator
is pointing within, then you can say either:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>(*it).f();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">or </FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>it-&gt;f();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Knowing this, you can create a template
that works with any container. Here, the <B>apply(&#160;)</B> function template
calls a member function for every object in the container, using a pointer to
member that is passed as an argument:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C07:Apply.cpp</font>
<font color=#009900>// Using basic iterators</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-g++3}</font>
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;iterator&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> Cont, <font color=#0000ff>class</font> PtrMemFun&gt;
<font color=#0000ff>void</font> apply(Cont&amp; c, PtrMemFun f) {
  <font color=#0000ff>typename</font> Cont::iterator it = c.begin();
  <font color=#0000ff>while</font>(it != c.end()) {
    (it-&gt;*f)(); <font color=#009900>// Compact form</font>
    ((*it).*f)(); <font color=#009900>// Alternate form</font>
    it++;
  }
}

<font color=#0000ff>class</font> Z {
  <font color=#0000ff>int</font> i;
<font color=#0000ff>public</font>:
  Z(<font color=#0000ff>int</font> ii) : i(ii) {}
  <font color=#0000ff>void</font> g() { i++; }
  <font color=#0000ff>friend</font> ostream&amp; 
  <font color=#0000ff>operator</font>&lt;&lt;(ostream&amp; os, <font color=#0000ff>const</font> Z&amp; z) {
    <font color=#0000ff>return</font> os &lt;&lt; z.i;
  }
};

<font color=#0000ff>int</font> main() {
  ostream_iterator&lt;Z&gt; out(cout, <font color=#004488>" "</font>);
  vector&lt;Z&gt; vz;
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 10; i++)
    vz.push_back(Z(i));
  copy(vz.begin(), vz.end(), out);
  cout &lt;&lt; endl;
  apply(vz, &amp;Z::g);
  copy(vz.begin(), vz.end(), out);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because <B>operator-&gt;</B> is defined
for STL iterators, it can be used for pointer-to-member dereferencing (in the
following chapter you&#8217;ll learn a more elegant way to handle the problem of
applying a member function or ordinary function to every object in a
container).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Much of the time, this is all you need to
know about iterators &#8211; that they are produced by <B>begin(&#160;)</B> and
<B>end(&#160;)</B>, and that you can use them to move through a container and
select elements. Many of the problems that you solve, and the STL algorithms
(covered in the next chapter) will allow you to just flail away with the basics
of iterators. However, things can at times become more subtle, and in those
cases you need to know more about iterators. The rest of this section gives you
the details.</FONT><A NAME="_Toc519042017"></A><BR></P></DIV>
<A NAME="Heading196"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Iterators in reversible containers</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">All containers must produce the basic
<B>iterator</B>. A container may also be <I>reversible</I>, which means that it
can produce iterators that move backwards from the end, as well as the iterators
that move forward from the beginning.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A reversible container has the methods
<B>rbegin(&#160;)</B> (to produce a <B>reverse_iterator</B> selecting the end)
and <B>rend(&#160;)</B> (to produce a <B>reverse_iterator</B> indicating
&#8220;one past the beginning&#8221;). If the container is <B>const</B> then
<B>rbegin(&#160;)</B> and <B>rend(&#160;)</B> will produce
<B>const_reverse_iterator</B>s.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">All the basic sequence containers
<B>vector</B>, <B>deque</B> and <B>list</B> are reversible containers. The
following example uses <B>vector</B>, but will work with <B>deque</B> and
<B>list</B> as well:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C07:Reversible.cpp</font>
<font color=#009900>// Using reversible containers</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <font color=#004488>"..</font><font color=#004488>/require.h"</font>
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;string&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main() {
  ifstream in(<font color=#004488>"Reversible.cpp"</font>);
  assure(in, <font color=#004488>"Reversible.cpp"</font>);
  string line;
  vector&lt;string&gt; lines;
  <font color=#0000ff>while</font>(getline(in, line))
    lines.push_back(line);
  vector&lt;string&gt;::reverse_iterator r;
  <font color=#0000ff>for</font>(r = lines.rbegin(); r != lines.rend(); r++)
    cout &lt;&lt; *r &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You move backward through the container
using the same syntax as moving forward through a container with an ordinary
iterator.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The associative containers <B>set</B>,
<B>multiset</B>, <B>map</B> and <B>multimap</B> are also reversible. Using

⌨️ 快捷键说明

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