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

📄 chap10.htm

📁 This is the second part of that lab manual to teach you how to make real-time programme and how to d
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<!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:C:\TEMP\TicV2\html\TicV2.rtf
Application Directory:C:\TOOLS\RTF2HTML\
Subject:
Author:Bruce Eckel
Operator:Bruce Eckel
Document Comments:
Version Comments:
Comments:
Keywords:
Translation Date:09/26/2001
Translation Time:08:32:35
Translation Platform:Win32
Number of Output files:19
This File:C:\TEMP\TicV2\html\Chap10.htm
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>10: Multiple inheritance</TITLE>
</HEAD>

<BODY  BGCOLOR="#FFFFFF"><DIV ALIGN="CENTER">
  <a href="http://www.MindView.net">
  <img src="mindview.gif" alt="MindView Inc." BORDER = "0"></a>
  <CENTER>
    <FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans" size = "-1">
    [ <a href="README.txt">Viewing Hints</a> ]
    [ <a href="RevisionHistory.htm">Revision History</a> ]
    [ <a href="http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html">Book Home Page</a> ]
    [ <a href="http://www.mindview.net/Etc/MailingList.html">Free Newsletter</a> ] <br>
    [ <a href="http://www.mindview.net/Seminars">Seminars</a> ]
    [ <a href="http://www.mindview.net/CDs">Seminars on CD ROM</a> ]
    [ <a href="http://www.mindview.net/Services">Consulting</a> ]
    </FONT>
  <H2><FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans">
  Thinking in C++, 2nd edition, Volume 2<br>
  <small>Revision 4.0</small></FONT></H2>
  <H3><FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans">
  by Bruce Eckel &amp; Chuck Allison<br>&copy;2001 MindView, Inc.</FONT></H3>
  
    <FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans" size = "-1">
     [ <a href="Chap09.htm">Previous Chapter</a> ] 
    
    [ <a href="SimpCont.htm">Short TOC</a> ] 
    [ <a href="Contents.htm">Table of Contents</a> ] 
  
        [ <a href="DocIdx.htm">Index</a> ]
        
     [ <a href="Chap11.htm">Next Chapter</a> ] 
    </FONT>
    
  </CENTER>
  </P></DIV><A NAME="_Toc519042101"></A><A NAME="Heading308"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H1 ALIGN="LEFT">
10: Multiple inheritance</H1></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Verdana" SIZE=4>The basic concept of multiple
inheritance (MI) sounds simple enough. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">[[[Notes: </FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">Demo of use of MI, using
Greenhouse example and different company&#8217;s greenhouse controller
equipment.</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">Introduce
concept of interfaces; toys and &#8220;tuckable&#8221;
interface</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">Class
Sattelite : public Task, public Displayed {}; highlight(Displayed*);
Suspend(Task*)</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">Slider:
Islider, BBslider {} (GUI from a Vendor, MI
Decouples)</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">Barton
&amp; Nackman MI
Examples</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">Concrete
classes (nonvirtual) vs. interface classes (pure
virtual)</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">class X {
int f(x); };</FONT><BR><FONT FACE="Georgia">class Y { int f(y);
};</FONT><BR><FONT FACE="Georgia">class Z : X, Y
{</FONT><BR><FONT FACE="Georgia">  using X::f;</FONT><BR><FONT FACE="Georgia"> 
int
f(Z);</FONT><BR><FONT FACE="Georgia">};</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">]]]</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="Index596"></A><A NAME="Index597"></A><A NAME="Index598"></A><FONT FACE="Georgia">You
create a new type by inheriting from more than one base class. The syntax is
exactly what you&#8217;d expect, and as long as the inheritance diagrams are
simple, MI is simple as well.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">However, MI can introduce a number of
ambiguities and strange situations, which are covered in this chapter. But
first, it helps to get a perspective on the
subject.</FONT><A NAME="_Toc305593286"></A><A NAME="_Toc305628758"></A><A NAME="_Toc312374097"></A><A NAME="_Toc519042102"></A><BR></P></DIV>
<A NAME="Heading309"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Perspective</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Before C++, the most successful
object-oriented language was Smalltalk<A NAME="Index599"></A>. Smalltalk was
created from the ground up as an OO language. It is often referred to as
<I>pure,</I> whereas C++, because it was built on top of C, is called
<I>hybrid</I>. One of the design decisions made with Smalltalk was that all
classes would be derived in a single hierarchy, rooted in a single base class
(called <B>Object</B> &#8211; this is the model for the <I>object-based
hierarchy<A NAME="Index600"></A><A NAME="Index601"></A></I>). You cannot create
a new class in Smalltalk without inheriting it from an existing class, which is
why it takes a certain amount of time to become productive in Smalltalk &#8211;
you must learn the class library before you can start making new classes. So the
Smalltalk class hierarchy is always a single monolithic
<A NAME="Index602"></A>tree.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Classes in Smalltalk usually have a
number of things in common, and always have <I>some</I> things in common (the
characteristics and behaviors of <B>Object</B>), so you almost never run into a
situation where you need to inherit from more than one base class. However, with
C++ you can create as many hierarchy trees as you want. Therefore, for logical
completeness the language must be able to combine more than one class at a time
&#8211; thus the need for multiple inheritance.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">However, this was not a crystal-clear
case of a feature that no one could live without, and there was (and still is) a
lot of disagreement about whether MI is really essential in C++. MI was added in
AT&amp;T <B>cfront</B> release 2.0 and was the first significant change to the
language. Since then, a number of other features have been added (notably
templates) that change the way we think about programming and place MI in a much
less important role. You can think of MI as a &#8220;minor&#8221; language
feature that shouldn&#8217;t be involved in your daily design
decisions.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">One of the most pressing issues that
drove MI involved containers. Suppose you want to create a container that
everyone can easily use. One approach is to use <B>void*</B> as the type inside
the container, as with <B>PStash</B> and <B>Stack</B>. The Smalltalk approach,
however, is to make a container that holds <B>Object</B>s. (Remember that
<B>Object</B> is the base type of the entire Smalltalk hierarchy.) Because
everything in Smalltalk is ultimately derived from <B>Object</B>, any container
that holds <B>Object</B>s can hold anything, so this approach works
nicely.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now consider the situation in C++.
Suppose vendor <B>A</B> creates an object-based hierarchy that includes a useful
set of containers including one you want to use called <B>Holder</B>. Now you
come across vendor <B>B</B>&#8217;s class hierarchy that contains some other
class that is important to you, a <B>BitImage</B> class, for example, which
holds graphic images. The only way to make a <B>Holder</B> of <B>BitImage</B>s
is to inherit a new class from both <B>Object</B>, so it can be held in the
<B>Holder</B>, and <B>BitImage</B>:</FONT><BR></P></DIV>
<DIV ALIGN="RIGHT"><IMG SRC="TicV202.gif"><BR></P></DIV>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This was seen as an important reason for
MI, and a number of class libraries were built on this model. However, as you
saw in Chapter XX, the addition of templates has changed the way containers are
created, so this situation isn&#8217;t a driving issue for MI.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The other reason you may need MI is
logical, related to design. Unlike the above situation, where you don&#8217;t
have control of the base classes, in this one you do, and you intentionally use
MI to make the design more flexible or useful. (At least, you may believe this
to be the case.) An example of this is in the original iostream library
design:</FONT><BR></P></DIV>
<DIV ALIGN="CENTER"><FONT FACE="Georgia"><IMG SRC="TicV203.gif"></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Both <B>istream</B> and <B>ostream</B>
are useful classes by themselves, but they can also be inherited into a class
that combines both their characteristics and behaviors.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Regardless of what motivates you to use
MI, a number of problems arise in the process, and you need to understand them
to use
it.</FONT><A NAME="_Toc305593287"></A><A NAME="_Toc305628759"></A><A NAME="_Toc312374098"></A><A NAME="_Toc519042103"></A><BR></P></DIV>
<A NAME="Heading310"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Duplicate subobjects<BR><A NAME="Index603"></A><A NAME="Index604"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When you inherit from a base class, you
get a copy of all the data members of that base class in your derived class.
This copy is referred to as a <I>subobject</I>. If you multiply inherit from
class <B>d1</B> and class <B>d2</B> into class <B>mi</B>, class <B>mi</B>
contains one subobject of <B>d1</B> and one of <B>d2</B>. So your <B>mi
</B>object looks like this:</FONT><BR></P></DIV>
<DIV ALIGN="CENTER"><FONT FACE="Georgia"><IMG SRC="TicV204.gif"></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now consider what happens if <B>d1</B>
and <B>d2</B> both inherit from the same base class, called
<B>Base</B>:</FONT><BR></P></DIV>
<DIV ALIGN="CENTER"><FONT FACE="Georgia"><IMG SRC="TicV205.gif"></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In the above diagram, both <B>d1 </B>and
<B>d2 </B>contain a subobject of <B>Base</B>, so <B>mi</B> contains <I>two</I>
subobjects of <B>Base</B>. Because of the path produced in the diagram, this is
sometimes called a &#8220;diamond&#8221; in the inheritance hierarchy. Without
diamonds<A NAME="Index605"></A><A NAME="Index606"></A>, multiple inheritance is
quite straightforward, but as soon as a diamond appears, trouble starts because
you have duplicate subobjects in your new class. This takes up extra space,
which may or may not be a problem depending on your design. But it also
introduces an
ambiguity.</FONT><A NAME="_Toc305593288"></A><A NAME="_Toc305628760"></A><A NAME="_Toc312374099"></A><A NAME="_Toc519042104"></A><BR></P></DIV>
<A NAME="Heading311"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Ambiguous
upcasting<BR><A NAME="Index607"></A><A NAME="Index608"></A><A NAME="Index609"></A><A NAME="Index610"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">What happens, in the above diagram, if
you want to cast a pointer to an <B>mi</B> to a pointer to a <B>Base</B>? There
are two subobjects of type <B>Base</B>, so which address does the cast produce?
Here&#8217;s the diagram in code:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C10:MultipleInheritance1.cpp</font>
<font color=#009900>// MI &amp; ambiguity</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <font color=#004488>"..</font><font color=#004488>/purge.h"</font>
#include &lt;iostream&gt;
#include &lt;vector&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>class</font> MBase {
<font color=#0000ff>public</font>:
  <font color=#0000ff>virtual</font> <font color=#0000ff>char</font>* vf() <font color=#0000ff>const</font> = 0;
  <font color=#0000ff>virtual</font> ~MBase() {}
};

<font color=#0000ff>class</font> D1 : <font color=#0000ff>public</font> MBase {
<font color=#0000ff>public</font>:
  <font color=#0000ff>char</font>* vf() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> <font color=#004488>"D1"</font>; }
};

<font color=#0000ff>class</font> D2 : <font color=#0000ff>public</font> MBase {
<font color=#0000ff>public</font>:
  <font color=#0000ff>char</font>* vf() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> <font color=#004488>"D2"</font>; }
};

<font color=#009900>// Causes error: ambiguous override of vf():</font>
<font color=#009900>//! class MI : public D1, public D2 {};</font>

<font color=#0000ff>int</font> main() {
  vector&lt;MBase*&gt; b;
  b.push_back(<font color=#0000ff>new</font> D1);
  b.push_back(<font color=#0000ff>new</font> D2);
  <font color=#009900>// Cannot upcast: which subobject?:</font>
<font color=#009900>//!  b.push_back(new mi);</font>

⌨️ 快捷键说明

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