📄 1is_a.html
字号:
<html>
<head>
<title>Polymorphism</title>
<meta name="description" content="Polymorphism in C++">
<meta name="keywords" content="polymorphism, inheritance, class, virtual">
<link rel="stylesheet" href="rs.css" tppabs="http://www.relisoft.com/book/rs.css">
</head>
<body background="margin.gif" tppabs="http://www.relisoft.com/book/images/margin.gif" bgcolor="#FFFFDC">
<!-- Main Table -->
<table cellpadding="6">
<tr>
<td width="78">
<td>
<h2>Polymorphism</h2>
<h3>The Meaning of is-a</h3>
<p>The fact that a <var>Star</var> is a <var>CelestialBody</var> means not only that a <var>Star</var> has all the member variables and methods of a <var>CelestialBody</var> (and more). After all that would be just syntactic sugar over straight embedding. One could embed a <var>CelestialBody</var> as a public member of <var>Star</var> and, apart from awkward semantics of the has-a relationship, one could imitate inheritance. (As a matter of fact, this is probably how your compiler implements inheritance.)
<p>There is however one big difference. Due to inheritance, a <var>Star</var> can pass as a <var>CelestialBody</var>. What does it mean? It means that a function that expects a reference or a pointer to a <var>CelestialBody</var> will happily accept a reference or a pointer to a <var>Star</var>. Here抯 an example: The class <var>BlackHole</var> has a method <var>Gobble</var> that accepts any <var>CelestialBody</var>
<!-- Code --><table width="100%" cellspacing=10><tr> <td class=codetable>
<pre>void BlackHole::Gobble (CelestialBody * pBody);</pre>
</table><!-- End Code --><p>
<p>Since a <var>Star</var> is a <var>CelestialBody</var>, it can be <var>Gobbled</var> by a <var>BlackHole</var>:
<!-- Code --><table width="100%" cellspacing=10><tr> <td class=codetable>
<pre>Star* pStar = new Star (1, 2);
TheBlackHole.Gobble (pStar); // Yumm</pre>
</table><!-- End Code -->
<p>How is the <var>CelestialBody</var> treated inside a <var>BlackHole</var>?
<!-- Code --><table width="100%" cellspacing=10><tr> <td class=codetable>
<pre>void BlackHole::Gobble (CelestialBody* pBody)
{
delete pBody;
}</pre>
</table><!-- End Code -->
<p>It is destroyed. Now the big question is: whose destructor is called? On the one hand, we know that we sent a <var>Star</var> to its fiery death, so we should hear "Destroying a star ..." On the other hand, the <var>BlackHole</var> has no idea that it is swallowing a <var>Star</var>. It will expect to hear "Destroying celestial body..." What抯 more, at compile time, the compiler has no idea what will be sent into the <var>BlackHole</var>. Imagine a situation like this:
<!-- Code --><table width="100%" cellspacing=10><tr> <td class=codetable>
<pre>Star * pStar = new Star (1, 2);
Planet * pPlanet = new Planet (3, 4);
TheBlackHole.Gobble (pStar); // Yumm
TheBlackHole.Gobble (pPlanet); // Yumm, yumm</pre>
</table><!-- End Code -->
<p>In both cases the same method <var>Gobble</var> is called, the same code is executed, therefore it is obvious that inside <var>Gobble</var> the compiler may only put the call to (or expand inline) <var>CelestialBody</var>抯 destructor. The compiler dispatches the call based on the <b><i>type of the pointer</i></b>. Notice that the same would apply to any other method of <var>CelestialBody</var> overridden by <var>Star</var> or <var>Planet</var>. If <var>Gobble</var> called any of these, the compiler would call the <var>CelestialBody</var>抯 implementation and not the one provided by <var>Star</var> or <var>Planet</var>.
<p>This solution is cheap and in many cases adequate. However, for a small additional fee, C++ can offer a very powerful feature called <b><i>polymorphism</i></b>. If you want to hear different final cries from the insides of a <var>BlackHole</var> depending on what has fallen into it, you must declare the <var>CelestialBody</var>抯 destructor <b><i>virtual</i></b>. When a virtual function is overridden in a derived class, the dispatching of calls to that function is done by <b><i>actual type</i></b> of the object pointed to, rather than by the <b><i>type of the pointer</i></b>.
<!-- Sidebar -->
<table width="100%" border=0 cellpadding=5><tr>
<td width=10>
<td bgcolor="#cccccc" class=sidebar>
If you are curious about how virtual functions are implemented and what kind of runtime overhead they incur, go on a little <a href="javascript:if(confirm('http://www.relisoft.com/book/lang/poly/2implem.html \n\nThis file was not retrieved by Teleport Pro, because it is linked too far away from its Starting Address. If you increase the in-domain depth setting for the Starting Address, this file will be queued for retrieval. \n\nDo you want to open it from the server?'))window.location='http://www.relisoft.com/book/lang/poly/2implem.html'" tppabs="http://www.relisoft.com/book/lang/poly/2implem.html">implementation sidetrip</a>.
</table>
<!-- End Sidebar -->
</table>
<!-- End Main Table -->
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -