📄 chapter14.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<!--
This document was converted from RTF source:
By rtftohtml 4.19
See http://www.sunpack.com/RTF
Filename:TIC2Vone.rtf
Application Directory:C:\TOOLS\RTF2HTML\
Subject:
Author:Bruce Eckel
Operator:Bruce Eckel
Document Comments:
Version Comments:
Comments:
Keywords:
Translation Date:09/27/2001
Translation Time:05:25:53
Translation Platform:Win32
Number of Output files:22
This File:Chapter14.html
SplitDepth=1
SkipNavPanel=1
SkipLeadingToc=1
SkipTrailingToc=1
GenContents=1
GenFrames=1
GenIndex=1
-->
<HEAD lang="en"><META http-equiv="Content-Type" content="text/html">
<TITLE>14: Inheritance & Composition</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF"><DIV ALIGN="CENTER">
<a href="http://www.MindView.net">
<img src="mindview-head.gif" alt="MindView Inc." BORDER = "0"></a>
<CENTER>
<FONT FACE="Verdana" size = "-1">
[ <a href="README-HTML.txt">Viewing Hints</a> ]
[ <a href="http://www.mindview.net/CPPServices/SolutionGuide.html">Exercise Solutions</a> ]
[ <a href="http://www.mindview.net/ThinkingInCPP2e.html">Volume 2</a> ]
[ <a href="http://www.mindview.net/MailingList.html">Free Newsletter</a> ] <br>
[ <a href="http://www.mindview.net/CPPServices/#PublicSeminars">Seminars</a> ]
[ <a href="http://www.mindview.net/CPPServices/#SeminarsOnCD">Seminars on CD ROM</a> ]
[ <a href="http://www.mindview.net/CPPServices/#ConsultingServices">Consulting</a> ]
</FONT>
<H2><FONT FACE="Verdana">
Thinking in C++, 2nd ed. Volume 1</FONT></H2></FONT>
<H3><FONT FACE="Verdana">©2000 by Bruce Eckel</FONT></H3></FONT>
<FONT FACE="Verdana" size = "-1">
[ <a href="Chapter13.html">Previous Chapter</a> ]
[ <a href="Contents.html">Table of Contents</a> ]
[ <a href="DocIndex.html">Index</a> ]
[ <a href="Chapter15.html">Next Chapter</a> ]
</FONT>
</CENTER>
</P></DIV><A NAME="_Toc472654988"></A><A NAME="Heading404"></A><FONT FACE = "Verdana"><H1 ALIGN="LEFT">
14: Inheritance & Composition</H1></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Verdana" SIZE=4>One of the most compelling
features about C++ is </FONT><BR><FONT FACE="Verdana" SIZE=4>code
reuse<A NAME="Index2272"></A><A NAME="Index2273"></A>. But to be revolutionary,
you need to be </FONT><BR><FONT FACE="Verdana" SIZE=4>able to do a lot more than
copy code and change it.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">That’s the C approach, and it
hasn’t worked very well. As with most everything in C++, the solution
revolves around the class. You reuse code by creating new classes, but instead
of creating them from scratch, you use existing classes that someone else has
built and debugged.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The trick is to use the classes without
soiling the existing code. In this chapter you’ll see two ways to
accomplish this. The first is quite straightforward: You simply create objects
of your existing class inside the new class. This is called <I>composition</I>
<A NAME="Index2274"></A>because the new class is composed of objects of existing
classes.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The second approach is subtler. You
create a new class as a <I>type of</I> an existing class. You literally take the
form of the existing class and add code to it, without modifying the existing
class. This magical act is called <I>inheritance<A NAME="Index2275"></A></I>,
and most of the work is done by the compiler. Inheritance is one of the
cornerstones of object-oriented programming and has additional implications that
will be explored in Chapter 15.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It turns out that much of the syntax and
behavior are similar for both composition and inheritance (which makes sense;
they are both ways of making new types from existing types). In this chapter,
you’ll learn about these code reuse
mechanisms.</FONT><A NAME="_Toc305593251"></A><A NAME="_Toc305628723"></A><A NAME="_Toc312374014"></A><A NAME="_Toc472654989"></A><BR></P></DIV>
<A NAME="Heading405"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Composition syntax</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Actually, you’ve been using
composition all along to create classes. You’ve just been composing
classes primarily with built-in types (and sometimes <B>string</B>s). It turns
out to be almost as easy to use composition with user-defined
types.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Consider a class that is valuable for
some reason:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C14:Useful.h</font>
<font color=#009900>// A class to reuse</font>
#ifndef USEFUL_H
#define USEFUL_H
<font color=#0000ff>class</font> X {
<font color=#0000ff>int</font> i;
<font color=#0000ff>public</font>:
X() { i = 0; }
<font color=#0000ff>void</font> set(<font color=#0000ff>int</font> ii) { i = ii; }
<font color=#0000ff>int</font> read() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> i; }
<font color=#0000ff>int</font> permute() { <font color=#0000ff>return</font> i = i * 47; }
};
#endif <font color=#009900>// USEFUL_H ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The data members are <B>private</B> in
this class, so it’s completely safe to embed an object of type <B>X</B> as
a <B>public</B> object in a new class, which makes the interface
straightforward:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C14:Composition.cpp</font>
<font color=#009900>// Reuse code with composition</font>
#include <font color=#004488>"Useful.h"</font>
<font color=#0000ff>class</font> Y {
<font color=#0000ff>int</font> i;
<font color=#0000ff>public</font>:
X x; <font color=#009900>// Embedded object</font>
Y() { i = 0; }
<font color=#0000ff>void</font> f(<font color=#0000ff>int</font> ii) { i = ii; }
<font color=#0000ff>int</font> g() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> i; }
};
<font color=#0000ff>int</font> main() {
Y y;
y.f(47);
y.x.set(37); <font color=#009900>// Access the embedded object</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Accessing the member functions of the
embedded object<A NAME="Index2276"></A> (referred to as a
<I>subobject<A NAME="Index2277"></A></I>) simply requires another member
selection.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It’s more common to make the
embedded objects <B>private</B>, so they become part of the underlying
implementation (which means you can change the implementation if you want). The
<B>public</B> interface functions for your new class then involve the use of the
embedded object, but they don’t necessarily mimic the object’s
interface:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C14:Composition2.cpp</font>
<font color=#009900>// Private embedded objects</font>
#include <font color=#004488>"Useful.h"</font>
<font color=#0000ff>class</font> Y {
<font color=#0000ff>int</font> i;
X x; <font color=#009900>// Embedded object</font>
<font color=#0000ff>public</font>:
Y() { i = 0; }
<font color=#0000ff>void</font> f(<font color=#0000ff>int</font> ii) { i = ii; x.set(ii); }
<font color=#0000ff>int</font> g() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> i * x.read(); }
<font color=#0000ff>void</font> permute() { x.permute(); }
};
<font color=#0000ff>int</font> main() {
Y y;
y.f(47);
y.permute();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here, the <B>permute( )</B> function
is carried through to the new class interface, but the other member functions of
<B>X</B> are used within the members of
<B>Y</B>.</FONT><A NAME="_Toc305593252"></A><A NAME="_Toc305628724"></A><A NAME="_Toc312374015"></A><A NAME="_Toc472654990"></A><BR></P></DIV>
<A NAME="Heading406"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Inheritance syntax</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The syntax for composition is obvious,
but to perform inheritance there’s a new and different
form.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When you inherit, you are saying,
“This new class is like that old class.” You state this in code by
giving the name of the class as usual, but before the opening brace of the class
body, you put a colon and the name of the <I>base class</I> (or base
<I>classes</I>, separated by commas, for
<A NAME="Index2278"></A><A NAME="Index2279"></A>multiple
<A NAME="Index2280"></A>inheritance). When you do this, you automatically get
all the data members and member functions in the base class. Here’s an
example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C14:Inheritance.cpp</font>
<font color=#009900>// Simple inheritance</font>
#include <font color=#004488>"Useful.h"</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> Y : <font color=#0000ff>public</font> X {
<font color=#0000ff>int</font> i; <font color=#009900>// Different from X's i</font>
<font color=#0000ff>public</font>:
Y() { i = 0; }
<font color=#0000ff>int</font> change() {
i = permute(); <font color=#009900>// Different name call</font>
<font color=#0000ff>return</font> i;
}
<font color=#0000ff>void</font> set(<font color=#0000ff>int</font> ii) {
i = ii;
X::set(ii); <font color=#009900>// Same-name function call</font>
}
};
<font color=#0000ff>int</font> main() {
cout << <font color=#004488>"sizeof(X) = "</font> << <font color=#0000ff>sizeof</font>(X) << endl;
cout << <font color=#004488>"sizeof(Y) = "</font>
<< <font color=#0000ff>sizeof</font>(Y) << endl;
Y D;
D.change();
<font color=#009900>// X function interface comes through:</font>
D.read();
D.permute();
<font color=#009900>// Redefined functions hide base versions:</font>
D.set(12);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see <B>Y</B> being inherited from
<B>X</B>, which means that <B>Y</B> will contain all the data elements in
<B>X</B> and all the member functions in <B>X</B>. In fact, <B>Y</B> contains a
subobject of <B>X</B> just as if you had created a member object of <B>X</B>
inside <B>Y</B> instead of inheriting from <B>X</B>. Both member objects and
base class storage are referred to as
subobjects<A NAME="Index2281"></A>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">All the <B>private</B> elements of
<B>X</B> are still <B>private</B> in <B>Y</B>; that is, just because <B>Y</B>
inherits from <B>X</B> doesn’t mean <B>Y</B> can break the protection
mechanism. The <B>private</B> elements of <B>X</B> are still there, they take up
space – you just can’t access them directly.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>main( )</B> you can see that
<B>Y</B>’s<B> </B>data elements are combined with <B>X</B>’s because
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -