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

📄 counting.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 4 页
字号:

<P><A NAME="dingp40"></A><A NAME="AUTO00018"></A>Yes, this is counterintuitive, and don't be surprised if your compilers don't yet support this rule, but the behavior I've described is correct. Let us therefore consider a different way of preventing the deletion of derived class objects via <CODE>Counter*</CODE> pointers.  Let us consider making <CODE>Counter</CODE>'s destructor <CODE>protected</CODE>:<SCRIPT>create_link(40);</SCRIPT>

</P>

<A NAME="AUTO00061"></A><UL><PRE>
template&lt;typename T&gt;
class Counter {
...
protected:
  ~Counter();
  ...
...
};

class Widget: public Counter&lt;Widget&gt; { ... };
Counter&lt;Widget&gt; *pw = new Widget;
...
delete pw;                     // error! Can't call protected
                               // destructor
</PRE>
</UL>

<P><A NAME="dingp41"></A>This offers the behavior we want.  We can still create <CODE>Widget</CODE> objects, and we can still destroy them, as long as we don't do it via <CODE>Counter*</CODE> pointers.  When we destroy a static <CODE>Widget</CODE> or a stack-based <CODE>Widget</CODE>, the implicit call to the <CODE>Counter</CODE> destructor is attributed to the <CODE>Widget</CODE> destructor, and since the <CODE>Widget</CODE> destructor is a member function of a derived class, it has access to <CODE>Counter</CODE>'s protected members.  Similarly, when we delete a <CODE>Widget</CODE> through a <CODE>Widget*</CODE> pointer, the implicit call to the <CODE>Counter</CODE> destructor is attributed to the <CODE>Widget</CODE> <NOBR>destructor.<SCRIPT>create_link(41);</SCRIPT>

</NOBR></P>

<P><A NAME="dingp42"></A><A NAME="AUTO00019"></A>Unfortunately, this design smells a bit of Bait and Switch.  By having <CODE>Widget</CODE> publicly inherit from <CODE>Counter</CODE>, we're saying that every <CODE>Widget</CODE> object <EM>isa</EM> <CODE>Counter</CODE> object (<SCRIPT>sendmetoo(35,6914,'E');</SCRIPT> onMouseOver = "self.status = 'Item E35'; return true" onMouseOut = "self.status = self.defaultStatus">Item E35</A>).  As a result, <CODE>Widget*</CODE> pointers are implicitly and automatically converted to <CODE>Counter*</CODE> pointers whenever it's necessary. <CODE>Widget</CODE> clients can thus be forgiven for expecting that they can delete <CODE>Widget</CODE>s via base class pointers; it's just one of the things public inheritance implies.  Yet the above design disallows it. We get the behavior we want, yes, and that's worth a lot, but it just doesn't <em>feel</em> right.  (The earlier design &#151; the one involving a private <CODE>operator</CODE> <CODE>delete</CODE> &#151; exhibits the same undesireable <NOBR>behavior.)<SCRIPT>create_link(42);</SCRIPT>

</NOBR></P>

<P><A NAME="dingp43"></A><A NAME="AUTO00020"></A>Preventing deletion of derived class objects via public base class pointers looks unsatisfactory no matter how we slice it.  I say we abandon this approach and turn our attention to using a <CODE>Counter</CODE> data member <NOBR>instead.<SCRIPT>create_link(43);</SCRIPT>

</NOBR></p>

<P><A NAME="dingp44"></A><FONT ID="aititle">Using a Data Member</FONT><SCRIPT>create_link(44);</SCRIPT>

</P>

<P><A NAME="dingp45"></A>We've already seen that the design based on a <CODE>Counter</CODE> data member has one drawback: clients must both define a <CODE>Counter</CODE> data member and write an inline version of <CODE>howMany</CODE> that calls the <CODE>Counter</CODE>'s <CODE>howMany</CODE> function. That's marginally more work than we'd like to impose on clients, but it's hardly unmanageable. There is another drawback, however. The addition of a <CODE>Counter</CODE> data member to a class will often increase the size of objects of that class <NOBR>type.<SCRIPT>create_link(45);</SCRIPT>

</NOBR></P>

<P><A NAME="dingp46"></A><A NAME="AUTO00021"></A>At first blush, this is hardly a revelation. After all, how surprising is it that adding a data member to a class makes objects of that type bigger? But blush again. Look at the definition of <CODE>Counter</CODE>:<SCRIPT>create_link(46);</SCRIPT>

</P>

<A NAME="AUTO00062"></A><UL><PRE>
template&lt;typename T&gt;
class Counter {
public:
  Counter();
  Counter(const Counter&amp;);
  ~Counter();

  static size_t howMany();
private:
  static size_t count;
};
</PRE>
</UL>

<P><A NAME="dingp47"></A>Notice how it has no nonstatic data members. That means each object of type <CODE>Counter</CODE> contains <I>nothing</I>. Might we hope that objects of type <CODE>Counter</CODE> have size zero? We might, but it would do us no good. C++ is quite clear on this point. All objects have a size of at least one byte, even objects with no nonstatic data members. By definition, <CODE>sizeof</CODE> will yield some positive number for each class instantiated from the <CODE>Counter</CODE> template. So each client class containing a <CODE>Counter</CODE> object will contain more data than it would if it didn't contain the <CODE>Counter</CODE>.<SCRIPT>create_link(47);</SCRIPT>

</P>

<P><A NAME="dingp48"></A><A NAME="AUTO00022"></A>(Interestingly, this does not imply that the size of a class without a <CODE>Counter</CODE> will necessarily be bigger than the size of the same class containing a <CODE>Counter</CODE>. That's because alignment restrictions can enter into the matter. For example, if <CODE>Widget</CODE> is a class containing two bytes of data but that's required to be four-byte aligned, each object of type <CODE>Widget</CODE> will contain two bytes of padding, and <CODE>sizeof(Widget)</CODE> will return 4. If, as is common, compilers satisfy the requirement that no objects have zero size by inserting a <CODE>char</CODE> into <CODE>Counter&lt;Widget&gt;</CODE>, it's likely that <CODE>sizeof(Widget)</CODE> will still yield 4 even if <CODE>Widget</CODE> contains a <CODE>Counter&lt;Widget&gt;</CODE> object. That object will simply take the place of one of the bytes of padding that <CODE>Widget</CODE> already contained. This is not a terribly common scenario, however, and we certainly can't plan on it when designing a way to package object-counting <NOBR>capabilities.)<SCRIPT>create_link(48);</SCRIPT>

</NOBR></P>

<P><A NAME="dingp49"></A><A NAME="AUTO00023"></A>
I'm writing this at the very beginning of the Christmas season. (It is in fact Thanksgiving Day, 1997, which gives you some idea of how I celebrate major holidays...) Already I'm in a Bah Humbug mood. All I want to do is count objects, and I don't want to haul along any extra baggage to do it. There has <I>got</I> to be a <NOBR>way.<SCRIPT>create_link(49);</SCRIPT>

</NOBR></p>

<P><A NAME="dingp50"></A><FONT ID="aititle">Using Private Inheritance</FONT><SCRIPT>create_link(50);</SCRIPT>

</P>
<P><A NAME="dingp51"></A>Look again at the inheritance-based code that led to the need to consider a virtual destructor in <CODE>Counter</CODE>:<SCRIPT>create_link(51);</SCRIPT>

</P>

<A NAME="AUTO00063"></A>

<UL><PRE>class Widget: public Counter&lt;Widget&gt;
{ ... };

Counter&lt;Widget&gt; *pw = new Widget;
...
delete pw;               // yields undefined results if
			 // Counter lacks a virtual destructor</PRE>
</UL>

<P><A NAME="dingp52"></A>Earlier we tried to prevent this sequence of operations by preventing the <CODE>delete</CODE> expression from compiling, but we discovered that that led to invalid or misleading code.  There is something else we can prohibit. We can prohibit the implicit conversion from a <CODE>Widget*</CODE> pointer (which is what <CODE>new</CODE> returns) to a <CODE>Counter&lt;Widget&gt;*</CODE> pointer. In other words, we can prevent inheritance-based pointer conversions. All we have to do is replace the use of public inheritance with private <NOBR>inheritance:<SCRIPT>create_link(52);</SCRIPT>

</NOBR></P>

<A NAME="AUTO00064"></A><UL><PRE>
class Widget:                                 // inheritance is
  private Counter&lt;Widget&gt; { ... };            // now private

Counter&lt;Widget&gt; *pw =                         // error!  no implicit conversion
  new Widget;                                 // from Widget* to Counter&lt;Widget&gt;*
</PRE>
</UL>
<P><A NAME="dingp53"></A>Furthermore, we're likely to find that the use of <CODE>Counter</CODE> as a base class does not increase the size of <CODE>Widget</CODE> compared to <CODE>Widget</CODE>'s stand-alone size. Yes, I know, I just finished telling you that no class has zero size, but &#151; well, that's not really what I said. What I said was that no <I>objects</I> have zero size. The C++ Standard makes clear that the base-class part of a more derived object <em>may</em> have zero size. In fact many compilers implement what has come to be known as the <I>empty base optimization</I> [<a href="#ref2" onMouseOver = "self.status = 'Reference 2'; return true" onMouseOut = "self.status = self.defaultStatus">Reference 2</A></NOBR>].  Thus, if a <CODE>Widget</CODE> <I>contains</I> a <CODE>Counter</CODE>, the size of the <CODE>Widget</CODE> must increase. The <CODE>Counter</CODE> data member is an object in its own right, hence it must have nonzero size. But if <CODE>Widget</CODE> <I>inherits</I> from <CODE>Counter</CODE>, compilers are allowed to keep <CODE>Widget</CODE> the same size it was before. This suggests an interesting rule of thumb for designs where space is tight and empty classes are involved: prefer private inheritance to containment when both will <NOBR>do.<SCRIPT>create_link(53);</SCRIPT>

</NOBR></P>

<P><A NAME="dingp54"></A><A NAME="AUTO00024"></A>This last design is nearly perfect. It fulfills the efficiency criterion, provided your compilers implement the empty base optimization, because inheriting from <CODE>Counter</CODE> adds no per-object data to the inheriting class, and all <CODE>Counter</CODE> member functions are inline. It fulfills the foolproof criterion, because count manipulations are handled automatically by <CODE>Counter</CODE> member functions, those functions are automatically called by C++, and the use of private inheritance prevents implicit conversions that would allow derived-class objects to be manipulated as if they were base-class objects. (Okay, it's not totally foolproof: <CODE>Widget</CODE>'s author might foolishly instantiate <CODE>Counter</CODE> with a type other than <CODE>Widget</CODE>, i.e., <CODE>Widget</CODE> could be made to inherit from <CODE>Counter&lt;Gidget&gt;</CODE>. I choose to ignore this <NOBR>possibility.)<SCRIPT>create_link(54);</SCRIPT>

</NOBR></P>

<P><A NAME="dingp55"></A><A NAME="AUTO00025"></A>The design is certainly easy for clients to use, but some may grumble that it could be easier. The use of private inheritance means that <CODE>howMany</CODE> will become private in inheriting classes, so such classes must include a <CODE>using</CODE> declaration to make <CODE>howMany</CODE> public to their <NOBR>clients:<SCRIPT>create_link(55);</SCRIPT>

</NOBR></P>

<!-- when adding special characters in <A NAME="AUTO00065"></A><UL><PRE> tags (like &gt;) make sure to add extra spaces to
compensate -->

<A NAME="AUTO00026"></A>
<A NAME="AUTO00066"></A><UL><PRE>
class Widget: private Counter&lt;Widget&gt; {
public:
  using Counter&lt;Widget&gt;::howMany;           // make howMany public

  ...                                       // rest of Widget
};                                          // is unchanged

class ABCD: private Counter&lt;ABCD&gt; {
public:
  using Counter&lt;ABCD&gt;::howMany;             // make howMany public

  ...                                       // rest of Widget
};                                          // is unchanged

</PRE>
</UL>
<P><A NAME="dingp56"></A>For compilers not supporting name spaces, the same thing is accomplished by replacing the <CODE>using</CODE> declaration with the older (now deprecated) access <NOBR>declaration:<SCRIPT>create_link(56);</SCRIPT>

</NOBR></P>

<A NAME="AUTO00067"></A><UL><PRE>
class Widget: private Counter&lt;Widget&gt; {
public:
  Counter&lt;Widget&gt;::howMany;                 // make howMany public

  ...                                       // rest of Widget
};                                          // is unchanged

class ABCD: private Counter&lt;ABCD&gt; {
public:
  Counter&lt;ABCD&gt;::howMany;                   // make howMany public

  ...                                       // rest of ABCD
};                                          // is unchanged
</PRE>
</UL>
<P><A NAME="dingp57"></A>Hence, clients who want to count objects and who want to make that count available (as part of their class's interface) to their clients must do two things: declare <CODE>Counter</CODE> as a base class and make <CODE>howMany</CODE> accessible.  (Simple variations on this design make it possible for <CODE>Widget</CODE> to use <CODE>Counter&lt;Widget&gt;</CODE> to count objects without making the count available to <CODE>Widget</CODE> clients, not even by calling <CODE>Counter&lt;Widget&gt;::howMany</CODE> directly. It is an interesting exercise to come up with one or more such <NOBR>variations.)<SCRIPT>create_link(57);</SCRIPT>

</NOBR></P>

<P><A NAME="dingp58"></A><A NAME="AUTO00027"></A>The use of inheritance does, however, lead to two conditions that are worth noting. The first is ambiguity. Suppose we want to count <CODE>Widget</CODE>s, and we want to make the count available for general use. As shown above, we have <CODE>Widget</CODE> inherit from <CODE>Counter&lt;Widget&gt;</CODE> and we make <CODE>howMany</CODE> public in <CODE>Widget</CODE>. Now suppose we have a class <CODE>SpecialWidget</CODE> publicly inherit from <CODE>Widget</CODE> and we want to offer <CODE>SpecialWidget</CODE> clients the same functionality <CODE>Widget</CODE> clients enjoy. No problem, we just have <CODE>SpecialWidget</CODE> inherit from <CODE>Counter&lt;SpecialWidget&gt;</CODE>.<SCRIPT>create_link(58);</SCRIPT>

</P>

⌨️ 快捷键说明

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