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

📄 ei42.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<title>Effective C++, 2E | Item 42: Use private inheritance judiciously</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 0; setCurrentMax(0);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "EI42_DIR.HTM";
var dingtext = "Item E42, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E42: Use private inheritance judiciously" -->
<A NAME="21052"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI41_FR.HTM" TARGET="_top">Item 41: Differentiate between inheritance and templates.</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI43_FR.HTM" TARGET="_top">Item 43: Use multiple inheritance judiciously. </A></FONT></DIV>

<P><A NAME="dingp1"></A><FONT ID="eititle">Item 42: &nbsp;Use private inheritance judiciously.</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="21056"></A>
<P><A NAME="dingp2"></A>
<A HREF="./EI35_FR.HTM#6914" TARGET="_top">Item 35</A> demonstrates that C++ treats public inheritance as an isa relationship. It does this by showing that compilers, when given a hierarchy in which a class <CODE>Student</CODE> publicly inherits from a class <CODE>Person</CODE>, implicitly convert <CODE>Student</CODE>s to <CODE>Person</CODE>s when that is necessary for a function call to succeed. It's worth repeating a portion of that example using private inheritance instead of public <NOBR>inheritance:<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>
<A NAME="21057"></A>
<UL><PRE>class Person { ... };
</PRE>
</UL><A NAME="21058"></A>
<UL><PRE>
class Student:                      // this time we use
  private Person { ... };           // private inheritance
</PRE>
</UL><A NAME="21059"></A>
<UL><PRE>
void dance(const Person&amp; p);        // anyone can dance
</PRE>
</UL><A NAME="21060"></A>
<UL><PRE>void study(const Student&amp; s);       // only students study
</PRE>
</UL><A NAME="21061"></A>
<UL><PRE><A NAME="p190"></A>
Person p;                           // p is a Person
Student s;                          // s is a Student
</PRE>
</UL><A NAME="21062"></A>
<UL><PRE>
dance(p);                           // fine, p is a Person
</PRE>
</UL><A NAME="21063"></A>
<UL><PRE>
dance(s);                           // error! a Student isn't
                                    // a Person
</PRE>
</UL><A NAME="21064"></A>
<P><A NAME="dingp3"></A>
Clearly, private inheritance doesn't mean isa. What does it mean <NOBR>then?<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>
<A NAME="21065"></A>
<P><A NAME="dingp4"></A>
"Whoa!" you say. "Before we get to the meaning, let's cover the behavior. How does private inheritance behave?" Well, the first rule governing private inheritance you've just seen in action: in contrast to public inheritance, compilers will generally <I>not</I> convert a derived class object (such as <CODE>Student</CODE>) into a base class object (such as <CODE>Person</CODE>) if the inheritance relationship between the classes is private. That's why the call to <CODE>dance</CODE> fails for the object <CODE>s</CODE>. The second rule is that members inherited from a private base class become private members of the derived class, even if they were protected or public in the base class. So much for <NOBR>behavior.<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>
<A NAME="21068"></A>
<P><A NAME="dingp5"></A>
That brings us to meaning. Private inheritance means is-implemented-in-terms-of. If you make a class <CODE>D</CODE> privately inherit from a class <CODE>B</CODE>, you do so because you are interested in taking advantage of some of the code that has already been written for class <CODE>B</CODE>, not because there is any conceptual relationship between objects of type <CODE>B</CODE> and objects of type <CODE>D</CODE>. As such, private inheritance is purely an implementation technique. Using the terms introduced in <A HREF="./EI36_FR.HTM#7007" TARGET="_top">Item 36</A>, private inheritance means that implementation <I>only</I> should be inherited; interface should be ignored. If <CODE>D</CODE> privately inherits from <CODE>B</CODE>, it means that <CODE>D</CODE> objects are implemented in terms of <CODE>B</CODE> objects, nothing more. Private inheritance means nothing during software <I>design</I>, only during software <I>implementation</I>.<SCRIPT>create_link(5);</SCRIPT>
</P>
<A NAME="21072"></A>
<P><A NAME="dingp6"></A>
The fact that private inheritance means is-implemented-in-terms-of is a
little disturbing, because <A HREF="./EI40_FR.HTM#7424" target="_top">Item
40</A> points out that layering can mean the same thing. How are you supposed
to choose between them? The answer is simple: use layering whenever you can,
use private inheritance whenever you must. When must you? When protected
members and/or virtual functions enter the picture &#151; but more on that in
a <NOBR>moment.<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P> <A
NAME="194702"></A> <P><A NAME="dingp7"></A> <A HREF="./EI41_FR.HTM#7611"
TARGET="_top">Item 41</A> shows a way to write a <CODE>Stack</CODE> template
that generates classes holding objects of different types. You may wish to
familiarize yourself with that Item now. Templates are one of the most useful
features in C++, but once you start using them regularly, you'll discover
that if you instantiate a template a dozen times, you are likely to
instantiate the <i>code</i> for the template a dozen times. In the case of
the <CODE>Stack</CODE> template, the code making up
<CODE>Stack&lt;int&gt;</CODE>'s member functions will be <A
NAME="p191"></A>completely separate from the code making up
<CODE>Stack&lt;double&gt;</CODE>'s member functions. Sometimes this is
unavoidable, but such code replication is likely to exist even if the
template functions could in fact share code. There is a name for the
resultant increase in object code size: template-induced <I>code bloat</I>.
It is not a good <NOBR>thing.<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P> <A
NAME="194705"></A> <P><A NAME="dingp8"></A> For certain kinds of classes, you
can use generic pointers to avoid it. The classes to which this approach is
applicable store <I>pointers</I> instead of objects, and they are implemented
<NOBR>by:<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P> <A NAME="21416"></A> <OL
TYPE="1"><A NAME="dingp9"></A><LI>Creating a single class that stores <CODE>void*</CODE> pointers
to objects.<SCRIPT>create_link(9);</SCRIPT>

 <A NAME="21417"></A><A NAME="dingp10"></A><LI>Creating a set of additional classes
whose only purpose is to enforce strong typing. These classes all use the
generic class of step 1 for the actual
work.<SCRIPT>create_link(10);</SCRIPT>

</OL></P> <A NAME="21418"></A> <P><A NAME="dingp11"></A> Here's an example using the non-template
<CODE>Stack</CODE> class of <A HREF="./EI41_FR.HTM#7611" target="_top">Item
41</A>, except here it stores generic pointers instead of <NOBR>objects:<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P>
<A NAME="21420"></A>
<UL><PRE>class GenericStack {
public:
  GenericStack();
  ~GenericStack();
</PRE>
</UL><A NAME="21424"></A>
<UL><PRE>  void push(void *object);
  void * pop();
</PRE>
</UL><A NAME="21637"></A>
<UL><PRE>  bool empty() const;
</PRE>
</UL><A NAME="21632"></A>
<UL><PRE>private:
  struct StackNode {
    void *data;                    // data at this node
    StackNode *next;               // next node in list
</PRE>
</UL><A NAME="21633"></A>
<UL><PRE>    StackNode(void *newData, StackNode *nextNode)
    : data(newData), next(nextNode) {}
  };
</PRE>
</UL><A NAME="222995"></A>
<UL><PRE>
  StackNode *top;                          // top of stack
</PRE>
</UL><A NAME="222996"></A>
<UL><PRE>
  GenericStack(const GenericStack&amp; rhs);   // prevent copying and
  GenericStack&amp;                            // assignment (see
    operator=(const GenericStack&amp; rhs);    // <A HREF="./EI27_FR.HTM#6406" TARGET="_top">Item 27</A>)
};
</PRE>
</UL><A NAME="21426"></A>
<P><A NAME="dingp12"></A>
Because this class stores pointers instead of objects, it is possible that an
object is pointed to by more than one stack (i.e., has been pushed onto
multiple stacks). It is thus of critical importance that <CODE>pop</CODE> and
the class destructor <I>not</I> delete the <CODE>data</CODE> pointer of any
<CODE>StackNode</CODE> object they destroy, although they must continue to
delete the <CODE>StackNode</CODE> object itself. After all, the
<CODE>StackNode</CODE> objects are allocated inside the

⌨️ 快捷键说明

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