📄 ei41.htm
字号:
<!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 41: Differentiate between inheritance and templates</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/IMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/NSIMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 2; setCurrentMax(2);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "EI41_DIR.HTM";
var dingtext = "Item E41, P";
if (self == top) {
top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E41: Inheritance vs. templates" -->
<A NAME="7611"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI40_FR.HTM" TARGET="_top">Item 40: Differentiate between inheritance and templates.</A> <BR> Continue to <A HREF="./EI42_FR.HTM" TARGET="_top">Item 42: Use private inheritance judiciously.</A></FONT></DIV>
<P><A NAME="dingp1"></A><FONT ID="eititle">Item 41: Differentiate between inheritance and templates.</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>
<A NAME="7612"></A>
<P><A NAME="dingp2"></A>
Consider the following two design <NOBR>problems:<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>
<UL><A NAME="7613"></A>
<A NAME="dingp3"></A><LI>Being a devoted student of Computer Science, you want to create classes representing stacks of objects. You'll need several different classes, because each stack must be homogeneous, i.e., it must have only a single type of object in it. For example, you might have a class for stacks of <CODE>int</CODE>s, a second class for stacks of <CODE>string</CODE>s, a third for stacks of stacks of <CODE>string</CODE>s, etc. You're interested only in supporting a minimal interface to the class (see <A HREF="./EI18_FR.HTM#17774" TARGET="_top">Item 18</A>), so you'll limit your operations to stack creation, stack destruction, pushing objects onto the stack, popping objects off the stack, and determining whether the stack is empty. For this exercise, you'll ignore the classes in the standard library (including <CODE>stack</CODE> — see <A HREF="./EI49_FR.HTM#8392" TARGET="_top">Item 49</A>), because you crave the experience of writing the code yourself. Reuse is a wonderful thing, but when your goal is a deep understanding of how something works, there's nothing quite like diving in and getting your hands dirty.<SCRIPT>create_link(3);</SCRIPT>
<A NAME="7617"></A>
<A NAME="dingp4"></A><LI>Being a devoted feline aficionado, you want to design classes representing cats. You'll need several different classes, because each breed of cat is a little different. Like all objects, cats can be created and destroyed, but, as any cat-lover knows, the only other things cats do are eat and sleep. However, each breed of cat eats and sleeps in its own endearing way.<SCRIPT>create_link(4);</SCRIPT>
</UL></P>
<A NAME="7618"></A>
<P><A NAME="dingp5"></A>
These two problem specifications sound similar, yet they result in utterly different software designs. <NOBR>Why?<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="7619"></A>
<P><A NAME="dingp6"></A>
<A NAME="p186"></A>The answer has to do with the relationship between each class's behavior and the <I>type</I> of object being manipulated. With both stacks and cats, you're dealing with a variety of different types (stacks containing objects of type <CODE>T</CODE>, cats of breed <CODE>T</CODE>), but the question you must ask yourself is this: does the type <CODE>T</CODE> affect the <I>behavior</I> of the class? If <CODE>T</CODE> does <I>not</I> affect the behavior, you can use a template. If <CODE>T</CODE> <i>does</i> affect the behavior, you'll need virtual functions, and you'll therefore use <NOBR>inheritance.<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>
<A NAME="7622"></A>
<P><A NAME="dingp7"></A>
Here's how you might define a linked-list implementation of a <CODE>Stack</CODE> class, assuming that the objects to be stacked are of type <CODE>T</CODE>:<SCRIPT>create_link(7);</SCRIPT>
</P>
<A NAME="7625"></A>
<UL><PRE>class Stack {
public:
Stack();
~Stack();
</PRE>
</UL><A NAME="7630"></A>
<UL><PRE> void push(const T& object);
T pop();
</PRE>
</UL><A NAME="21253"></A>
<UL><PRE>
bool empty() const; // is stack empty?
</PRE>
</UL><A NAME="21258"></A>
<UL><PRE>private:
struct StackNode { // linked list node
T data; // data at this node
StackNode *next; // next node in list
</PRE>
</UL><A NAME="222939"></A>
<UL><PRE> // StackNode constructor initializes both fields
StackNode(const T& newData, StackNode *nextNode)
: data(newData), next(nextNode) {}
};
</PRE>
</UL><A NAME="222988"></A>
<UL><PRE>
StackNode *top; // top of stack
</PRE>
</UL><A NAME="222989"></A>
<UL><PRE>
Stack(const Stack& rhs); // prevent copying and
Stack& operator=(const Stack& rhs); // assignment (see <A HREF="./EI27_FR.HTM#6406" TARGET="_top">Item 27</A>)
};
</PRE>
</UL><A NAME="222983"></A>
<P><A NAME="dingp8"></A>
<CODE>Stack</CODE> objects would thus build data structures that look like <NOBR>this:<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>
<SPAN ID="Image1of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_186A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_186A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_186A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_186A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_186A5.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_186A5.GIF" BORDER=0></SPAN>
<P><A NAME="dingp9"></A><A NAME="222984"></A>
The linked list itself is made up of <CODE>StackNode</CODE> objects, but that's an implementation detail of the <CODE>Stack</CODE> class, so <CODE>StackNode</CODE> has been declared a private type of <CODE>Stack</CODE>. Notice that <CODE>StackNode</CODE> has a constructor to make sure all its fields are initialized properly. Just because you can write linked lists in your sleep is no reason to omit technological advances such as <NOBR>constructors.<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<A NAME="7644"></A>
<P><A NAME="dingp10"></A>
<A NAME="p187"></A>Here's a reasonable first cut at how you might implement the <CODE>Stack</CODE> member functions. As with many prototype implementations (and far too much production software), there's no checking for errors, because in a prototypical world, nothing ever goes <NOBR>wrong.<SCRIPT>create_link(10);</SCRIPT>
</NOBR></P>
<A NAME="7646"></A>
<UL><PRE>
Stack::Stack(): top(0) {} // initialize top to null
</PRE>
</UL><A NAME="7648"></A>
<UL><PRE>void Stack::push(const T& object)
{
top = new StackNode(object, top); // put new node at
} // front of list
</PRE>
</UL><A NAME="7654"></A>
<UL><PRE>T Stack::pop()
{
StackNode *topOfStack = top; // remember top node
top = top->next;
</PRE>
</UL><A NAME="7657"></A>
<UL><PRE>
T data = topOfStack->data; // remember node data
delete topOfStack;
</PRE>
</UL><A NAME="7658"></A>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -