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

📄 mc5.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 5 页
字号:
  Printer p;                                 // for printing capabilities
  FaxMachine f;                              // for faxing capabilities
  CopyMachine c;                             // for copying capabilities
<A NAME="21074"></A>
  ...
<A NAME="21075"></A>
};
<A NAME="21076"></A>
CPFMachine m1;                               // fine
<A NAME="21077"></A>
CPFMachine m2;                               // throws TooManyObjects exception
</PRE>
</UL>

<P><A NAME="dingp55"></A><A NAME="21072"></A>
The problem is that <CODE>Printer</CODE> objects can exist in three different contexts: on their own, as base class parts of more derived objects, and embedded inside larger objects. The presence of these different contexts significantly muddies the waters regarding what it means to keep track of the "number of objects in existence," because what you consider to be the existence of an object may not jibe with your <NOBR>compilers'.<SCRIPT>create_link(55);</SCRIPT>
</NOBR></P>    <P><A NAME="dingp56"></A><A NAME="21197"></A>
Often you will be interested only in allowing objects to exist on their own, and you will wish to limit the number of <I>those</I> kinds of instantiations. That restriction is easy to satisfy if you adopt the strategy exem<A NAME="p137"></A>plified by our original <CODE>Printer</CODE> class, because the <CODE>Printer</CODE> constructors are private, and (in the absence of <CODE>friend</CODE> declarations) classes with private constructors can't be used as base classes, nor can they be embedded inside other <NOBR>objects.<SCRIPT>create_link(56);</SCRIPT>
</NOBR></P>    <P><A NAME="dingp57"></A><A NAME="21108"></A>
The fact that you can't derive from classes with private constructors leads to a general scheme for preventing derivation, one that doesn't necessarily have to be coupled with limiting object instantiations. Suppose, for example, you have a class, <CODE>FSA</CODE>, for representing finite state automata. (Such state machines are useful in many contexts, among them user interface design.) Further suppose you'd like to allow any number of <CODE>FSA</CODE> objects to be created, but you'd also like to ensure that no class ever inherits from <CODE>FSA</CODE>. (One reason for doing this might be to justify the presence of a nonvirtual destructor in <CODE>FSA</CODE>. <A HREF="../EC/EC3_FR.HTM#223029" TARGET="_top">Item E14</A> explains why base classes generally need virtual destructors, and <A HREF="./MC4_FR.HTM#41284" TARGET="_top">Item 24</A> explains why classes without virtual functions yield smaller objects than do equivalent classes with virtual functions.) Here's how you can design <CODE>FSA</CODE> to satisfy both <NOBR>criteria:<SCRIPT>create_link(57);</SCRIPT>
</NOBR></P>

<A NAME="21137"></A>
<UL><PRE>class FSA {
public:
  // pseudo-constructors
  static FSA * makeFSA();
  static FSA * makeFSA(const FSA&amp; rhs);
  ...
<A NAME="57618"></A>
private:
  FSA();
  FSA(const FSA&amp; rhs);
  ...
};
<A NAME="21147"></A>
FSA * FSA::makeFSA()
{ return new FSA(); }
<A NAME="21496"></A>
FSA * FSA::makeFSA(const FSA&amp; rhs)
{ return new FSA(rhs); }
</PRE>
</UL>

<P><A NAME="dingp58"></A><A NAME="21148"></A>
Unlike the <CODE>thePrinter</CODE> function that always returned a reference to a single object, each <CODE>makeFSA</CODE> pseudo-constructor returns a pointer to a unique object. That's what allows an unlimited number of <CODE>FSA</CODE> objects to be <NOBR>created.<SCRIPT>create_link(58);</SCRIPT>
</NOBR></P>    <P><A NAME="dingp59"></A><A NAME="60915"></A>
This is nice, but the fact that each pseudo-constructor calls <CODE>new</CODE> implies that callers will have to remember to call <CODE>delete.</CODE> Otherwise a resource leak will be introduced. Callers who wish to have <CODE>delete</CODE> called automatically when the current scope is exited can store the pointer returned from <CODE>makeFSA</CODE> in an <CODE>auto_ptr</CODE> object (see <A HREF="./MC2_FR.HTM#5292" TARGET="_top">Item 9</A>); such objects automatically delete what they point to when they themselves go out of <NOBR>scope:<SCRIPT>create_link(59);</SCRIPT>
</NOBR></P>

<A NAME="60729"></A>
<UL><PRE><A NAME="p138"></A>// indirectly call default FSA constructor
auto_ptr&lt;FSA&gt; pfsa1(FSA::makeFSA());
<A NAME="71742"></A>
// indirectly call FSA copy constructor
auto_ptr&lt;FSA&gt; pfsa2(FSA::makeFSA(*pfsa1));
<A NAME="71747"></A>
...                            // use pfsa1 and pfsa2 as normal pointers,
                               // but don't worry about deleting them
</PRE>
</UL>

<P><A NAME="dingp60"></A><font ID="mhtitle">Allowing Objects to Come and Go</font><SCRIPT>create_link(60);</SCRIPT>
</P>

<P><A NAME="dingp61"></A><A NAME="75623"></A>
We now know how to design a class that allows only a single instantiation, we know that keeping track of the number of objects of a particular class is complicated by the fact that object constructors are called in three different contexts, and we know that we can eliminate the confusion surrounding object counts by making constructors private. It is worthwhile to make one final observation. Our use of the <CODE>thePrinter</CODE> function to encapsulate access to a single object limits the number of <CODE>Printer</CODE> objects to one, but it also limits us to a single <CODE>Printer</CODE> object for each run of the program. As a result, it's not possible to write code like <NOBR>this:<SCRIPT>create_link(61);</SCRIPT>
</NOBR></P>

<A NAME="23570"></A>
<UL><PRE><I>create Printer object p1;
<A NAME="23571"></A>
use p1;
<A NAME="23572"></A>
destroy p1;
<A NAME="23573"></A>
create Printer object p2;
<A NAME="23574"></A>
use p2;
<A NAME="23575"></A>
destroy p2;
<A NAME="23577"></A>
...</I></PRE>
</UL>

<P><A NAME="dingp62"></A><A NAME="23576"></A>
This design never instantiates more than a single <CODE>Printer</CODE> object at a time, but it does use different <CODE>Printer</CODE> objects in different parts of the program. It somehow seems unreasonable that this isn't allowed. After all, at no point do we violate the constraint that only one printer may exist. Isn't there a way to make this <NOBR>legal?<SCRIPT>create_link(62);</SCRIPT>
</NOBR></P>    <P><A NAME="dingp63"></A><A NAME="23582"></A>
There is. All we have to do is combine the object-counting code we used earlier with the pseudo-constructors we just <NOBR>saw:<SCRIPT>create_link(63);</SCRIPT>
</NOBR></P>

<A NAME="23618"></A>
<UL><PRE>class Printer {
public:
  class TooManyObjects{};
<A NAME="23621"></A>
  // pseudo-constructor
  static Printer * makePrinter();
<A NAME="80108"></A>
~Printer();
<A NAME="23623"></A>
<A NAME="p139"></A>  void submitJob(const PrintJob&amp; job);
  void reset();
  void performSelfTest();
  ...
<A NAME="57627"></A>
private:
  static size_t numObjects;
<A NAME="57628"></A>
  Printer();
<A NAME="80113"></A>
  Printer(const Printer&amp; rhs);           // we don't define this
};                                       // function, because we'll
                                         // never allow copying
                                         // (see <A HREF="../EC/EC4_FR.HTM#6406" TARGET="_top">Item E27</A>)
<A NAME="23625"></A>
// Obligatory definition of class static
size_t Printer::numObjects = 0;
<A NAME="23626"></A>
Printer::Printer()
{
  if (numObjects &gt;= 1) {
    throw TooManyObjects();
  }
<A NAME="23627"></A>
  <I>proceed with normal object construction here;</I>
<A NAME="23628"></A>
  ++numObjects;
}
<A NAME="23632"></A>
Printer * Printer::makePrinter()
{ return new Printer; }
</PRE>
</UL>

<P><A NAME="dingp64"></A><A NAME="23703"></A>
If the notion of throwing an exception when too many objects are requested strikes you as unreasonably harsh, you could have the pseudo-constructor return a null pointer instead. Clients would then have to check for this before doing anything with it, of <NOBR>course.<SCRIPT>create_link(64);</SCRIPT>
</NOBR></P>    <P><A NAME="dingp65"></A><A NAME="23652"></A>
Clients use this <CODE>Printer</CODE> class just as they would any other class, except they must call the pseudo-constructor function instead of the real <NOBR>constructor:<SCRIPT>create_link(65);</SCRIPT>
</NOBR></P>

<A NAME="23653"></A>
<UL><PRE>Printer p1;                                  // error! default ctor is
                                             // private
<A NAME="23654"></A>
Printer *p2 =
  Printer::makePrinter();                    // fine, indirectly calls
                                             // default ctor
<A NAME="23655"></A>
Printer p3 = *p2;                            // error! copy ctor is
                                             // private
<A NAME="23657"></A>
p2-&gt;performSelfTest();                       // all other functions are
p2-&gt;reset();                                 // called as usual
<A NAME="77128"></A>
...
<A NAME="77129"></A>
delete p2;                                   // avoid resource leak; this
                                             // would be unnecessary if
                                             // p2 were an auto_ptr
</PRE>
</UL>

<P><A NAME="dingp66"></A><A NAME="23706"></A>
<A NAME="p140"></A>This technique is easily generalized to any number of objects. All we have to do is replace the hard-wired constant 1 with a class-specific value, then lift the restriction against copying objects. For example, the following revised implementation of our <CODE>Printer</CODE> class allows up to 10 <CODE>Printer</CODE> objects to <NOBR>exist:<SCRIPT>create_link(66);</SCRIPT>
</NOBR></P>

<A NAME="82911"></A>
<UL><PRE>class Printer {
public:
  class TooManyObjects{};
<A NAME="82892"></A>
  // pseudo-constructors
  static Printer * makePrinter();
  static Printer * makePrinter(const Printer&amp; rhs);
<A NAME="82897"></A>
  ...
<A NAME="23648"></A>
private:
  static size_t numObjects;
  static const size_t maxObjects = 10;       // see below
<A NAME="23686"></A>
  Printer();
  Printer(const Printer&amp; rhs);
};
<A NAME="21257"></A>
// Obligatory definitions of class statics
size_t Printer::numObjects = 0;
const size_t Printer::maxObjects;
<A NAME="24009"></A>
Printer::Printer()
{
  if (numObjects &gt;= maxObjects) {
    throw TooManyObjects();
  }
<A NAME="23691"></A>
  ...
<A NAME="23694"></A>
}
<A NAME="21320"></A>
Printer::Printer(const Printer&amp; rhs)
{
  if (numObjects &gt;= maxObjects) {
    throw TooManyObjects();
  }
<A NAME="23696"></A>
  ...
<A NAME="23697"></A>
}
<A NAME="82921"></A>

⌨️ 快捷键说明

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