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

📄 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 页
字号:
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; b.size(); i++)
    cout &lt;&lt; b[i]-&gt;vf() &lt;&lt; endl;
  purge(b);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Two problems occur here. First, you
cannot even create the class <B>mi</B> because doing so would cause a clash
between the two definitions of <B>vf(&#160;)</B> in <B>D1</B> and
<B>D2</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Second, in the array definition for <B>b[
]</B> this code attempts to create a <B>new mi</B> and upcast the address to a
<B>MBase*</B>. The compiler won&#8217;t accept this because it has no way of
knowing whether you want to use <B>D1</B>&#8217;s subobject <B>MBase</B> or
<B>D2</B>&#8217;s subobject <B>MBase</B> for the resulting
address.</FONT><A NAME="_Toc305593289"></A><A NAME="_Toc305628761"></A><A NAME="_Toc312374100"></A><A NAME="_Toc519042105"></A><BR></P></DIV>
<A NAME="Heading312"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
virtual base
classes<BR><A NAME="Index611"></A><A NAME="Index612"></A><A NAME="Index613"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To solve the first problem, you must
explicitly disambiguate the function <B>vf(&#160;)</B> by writing a redefinition
in the class <B>mi</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The solution to the second problem is a
language extension: The meaning of the <B>virtual</B> keyword is overloaded. If
you inherit a base class as <B>virtual</B>, only one subobject of that class
will ever appear as a base class. Virtual base classes are implemented by the
compiler with pointer magic in a way suggesting the implementation of ordinary
virtual functions.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because only one subobject of a virtual
base class will ever appear during multiple inheritance, there is no ambiguity
during upcasting. Here&#8217;s an example:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C10:MultipleInheritance2.cpp</font>
<font color=#009900>// Virtual base classes</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>virtual</font> <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>virtual</font> <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>// MUST explicitly disambiguate vf():</font>
<font color=#0000ff>class</font> MI : <font color=#0000ff>public</font> D1, <font color=#0000ff>public</font> D2 {
<font color=#0000ff>public</font>:
  <font color=#0000ff>char</font>* vf() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> D1::vf();}
};

<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);
  b.push_back(<font color=#0000ff>new</font> MI); <font color=#009900>// OK</font>
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; b.size(); i++)
    cout &lt;&lt; b[i]-&gt;vf() &lt;&lt; endl;
  purge(b);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The compiler now accepts the upcast, but
notice that you must still explicitly disambiguate the function
<B>vf(&#160;)</B> in <B>MI</B>; otherwise the compiler wouldn&#8217;t know which
version to
use.</FONT><A NAME="_Toc312374101"></A><A NAME="_Toc519042106"></A><BR></P></DIV>
<A NAME="Heading313"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
The "most derived" class and virtual base initialization</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The use of virtual base classes
isn&#8217;t quite as simple as that. The above example uses the
(compiler-synthesized) default constructor. If the virtual base has a
constructor, things become a bit strange. To understand this, you need a new
term: <I>most-derived</I>
class<A NAME="Index614"></A><A NAME="Index615"></A>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The most-derived class is the one
you&#8217;re currently in, and is particularly important when you&#8217;re
thinking about constructors. In the previous example, <B>MBase</B> is the
most-derived class inside the <B>MBase</B> constructor. Inside the <B>D1</B>
constructor, <B>D1</B> is the most-derived class, and inside the <B>MI</B>
constructor, <B>MI</B> is the most-derived class.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When you are using a virtual base class,
the most-derived constructor is responsible for initializing that virtual base
class. That means any class, no matter how far away it is from the virtual base,
is responsible for initializing it. Here&#8217;s an example:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C10:MultipleInheritance3.cpp</font>
<font color=#009900>// Virtual base initialization.</font>
<font color=#009900>// Virtual base classes must always be</font>
<font color=#009900>// Initialized by the "most-derived" class.</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>:
  MBase(<font color=#0000ff>int</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>virtual</font> <font color=#0000ff>public</font> MBase {
<font color=#0000ff>public</font>:
  D1() : MBase(1) {}
  <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>virtual</font> <font color=#0000ff>public</font> MBase {
<font color=#0000ff>public</font>:
  D2() : MBase(2) {}
  <font color=#0000ff>char</font>* vf() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> <font color=#004488>"D2"</font>; }
};

<font color=#0000ff>class</font> MI : <font color=#0000ff>public</font> D1, <font color=#0000ff>public</font> D2 {
<font color=#0000ff>public</font>:
  MI() : MBase(3) {}
  <font color=#0000ff>char</font>* vf() <font color=#0000ff>const</font> {
    <font color=#0000ff>return</font> D1::vf(); <font color=#009900>// MUST disambiguate</font>
  }
};

<font color=#0000ff>class</font> X : <font color=#0000ff>public</font> MI {
<font color=#0000ff>public</font>:
  <font color=#009900>// You must ALWAYS init the virtual base:</font>
  X() : MBase(4) {}
};

<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);
  b.push_back(<font color=#0000ff>new</font> MI); <font color=#009900>// OK</font>
  b.push_back(<font color=#0000ff>new</font> X);
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; b.size(); i++)
    cout &lt;&lt; b[i]-&gt;vf() &lt;&lt; endl;
  purge(b);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As you would expect, both <B>D1</B> and
<B>D2</B> must initialize <B>MBase</B> in their constructor. But so must <B>MI
</B>and <B>X</B>, even though they are more than one layer away! That&#8217;s
because each one in turn becomes the most-derived class. The compiler
can&#8217;t know whether to use <B>D1</B>&#8217;s initialization of <B>MBase</B>
or to use <B>D2</B>&#8217;s version. Thus you are always forced to do it in the
most-derived class. Note that only the single selected virtual base constructor
is
called.</FONT><A NAME="_Toc312374102"></A><A NAME="_Toc519042107"></A><BR></P></DIV>
<A NAME="Heading314"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
"Tying off" virtual bases with a default
constructor<BR><A NAME="Index616"></A><A NAME="Index617"></A><A NAME="Index618"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Forcing the most-derived class to
initialize a virtual base that may be buried deep in the class hierarchy can
seem like a tedious and confusing task to put upon the user of your class.
It&#8217;s better to make this invisible, which is done by creating a default
constructor for the virtual base class, like this:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C10:MultipleInheritance4.cpp</font>
<font color=#009900>// "Tying off" virtual bases so you don't have</font>
<font color=#009900>// to worry about them in derived classes.</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=#009900>// Default constructor removes responsibility:</font>
  MBase(<font color=#0000ff>int</font> = 0) {}
  <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>virtual</font> <font color=#0000ff>public</font> MBase {
<font color=#0000ff>public</font>:
  D1() : MBase(1) {}
  <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>virtual</font> <font color=#0000ff>public</font> MBase {
<font color=#0000ff>public</font>:
  D2() : MBase(2) {}
  <font color=#0000ff>char</font>* vf() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> <font color=#004488>"D2"</font>; }
};

<font color=#0000ff>class</font> MI : <font color=#0000ff>public</font> D1, <font color=#0000ff>public</font> D2 {
<font color=#0000ff>public</font>:
  MI() {} <font color=#009900>// Calls default constructor for MBase</font>
  <font color=#0000ff>char</font>* vf() <font color=#0000ff>const</font> {
    <font color=#0000ff>return</font> D1::vf(); <font color=#009900>// MUST disambiguate</font>
  }
};

<font color=#0000ff>class</font> X : <font color=#0000ff>public</font> MI {
<font color=#0000ff>public</font>:
  X() {} <font color=#009900>// Calls default constructor for MBase</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);
  b.push_back(<font color=#0000ff>new</font> MI); <font color=#009900>// OK</font>
  b.push_back(<font color=#0000ff>new</font> X);
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; b.size(); i++)
    cout &lt;&lt; b[i]-&gt;vf() &lt;&lt; endl;
  purge(b);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you can always arrange for a virtual
base class to have a default constructor, you&#8217;ll make things much easier
for anyone who inherits from that
class.</FONT><A NAME="_Toc312374103"></A><A NAME="_Toc305593290"></A><A NAME="_Toc305628762"></A><A NAME="_Toc519042108"></A><BR></P></DIV>
<A NAME="Heading315"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Overhead<BR><A NAME="Index619"></A><A NAME="Index620"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The term &#8220;pointer magic&#8221; has
been used to describe the way virtual inheritance is implemented. You can see
the physical overhead of virtual inheritance with the following
program:</FONT><BR></P></DIV>

⌨️ 快捷键说明

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