﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-健康，快乐，勇敢的宁帅！！-文章分类-C++技术</title><link>http://www.cppblog.com/ningfangli-blog/category/3121.html</link><description>努力、努力、再努力！
没有什么能阻止我对知识的渴望。</description><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 18:41:41 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 18:41:41 GMT</pubDate><ttl>60</ttl><item><title>C++多态技术---转载</title><link>http://www.cppblog.com/ningfangli-blog/articles/15662.html</link><dc:creator>ningfangli</dc:creator><author>ningfangli</author><pubDate>Sat, 25 Nov 2006 12:36:00 GMT</pubDate><guid>http://www.cppblog.com/ningfangli-blog/articles/15662.html</guid><wfw:comment>http://www.cppblog.com/ningfangli-blog/comments/15662.html</wfw:comment><comments>http://www.cppblog.com/ningfangli-blog/articles/15662.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ningfangli-blog/comments/commentRss/15662.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ningfangli-blog/services/trackbacks/15662.html</trackback:ping><description><![CDATA[
		<center>
				<table height="5577" cellspacing="0" cellpadding="0" width="760" bgcolor="#ffffff" border="0">
						<tbody>
								<tr>
										<td valign="top" align="left" width="973" bgcolor="#ffffff" height="305">
												<p class="MsoNormal" style="TEXT-ALIGN: center" align="center">
														<b>
																<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">C++多态技术</span>
														</b>
												</p>
												<p class="MsoNormal" style="TEXT-ALIGN: center" align="center">
														<?XML:NAMESPACE PREFIX = O /?>
														<o:p>
																<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体">《程序员》2004/0</span>
														</o:p>
														<span lang="en-us" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体">2</span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<b>
																<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">摘要</span>
														</b>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<o:p>
																</o:p>
														</span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">本文介绍了<span lang="EN-US">C++中的各种多态性，重点阐述了面向对象的动态多态和基于模板的静态多态，并初探两种技术的结合使用。</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<b>
																<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">关键词</span>
														</b>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">函数多态<span lang="EN-US"><span style="mso-spacerun: yes"> 宏多态 动态多态 静态多态</span></span></span>
												</p>
												<o:p>
														<p class="MsoNormal" style="mso-layout-grid-align: none">
																<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																		<b>导言</b>
																</span>
																<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																</span>
														</p>
												</o:p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">多态（<span lang="EN-US">polymorphism）一词最初来源于希腊语</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt">polumorphos，含义是具有多种形式或形态的情形。在程序设计领域，一个广泛认可的定义是“</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">一种将不同的特殊行为和单个泛化记号相关联的能力”。和</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">纯粹的面向对象程序设计语言不同，<span lang="EN-US">C++中的多态有着更广泛的含义。除了常见的通过</span></span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">类继承和虚函数机制生效于运行期的动态多态（</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">dynamic polymorphism</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">）外，模板也允许将不同的特殊行为和单个泛化记号相关联，由于这种关联处理于编译期而非运行期，因此被称为静态多态（<span lang="EN-US">static polymorphism）。</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">事实上，带变量的宏和函数重载机制也允许将不同的特殊行为和单个泛化记号相关联。然而，习惯上我们并不将它们展现出来的行为称为多态（或静态多态）。今天，当我们谈及多态时，如果没有明确所指，默认就是动态多态，而静态多态则是指基于模板的多态。不过，在这篇以<span lang="EN-US">C++各种多态技术为主题的文章中，我们首先还是回顾一下C++社群争论已久的另一种“多态”：函数多态（function polymorphism），以及更不常提的宏多态（macro polymorphism）。</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<b>
																<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">函数多态</span>
														</b>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">也就是我们常说的函数重载（<span lang="EN-US">function overloading）。基于不同的参数列表，同一个函数名字可以指向不同的函数定义：</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<font color="#0000ff">// overload_poly.cpp</font>
																<br />
																<br />#include &lt;iostream&gt;<br />#include &lt;string&gt;<br /><br /><font color="#008000">// 定义两个重载函数</font><br /><br />int my_add(int a, int b)<br />{<br />    return a + b;<br />}<br /><br />int my_add(int a, std::string b)<br />{<br />    return a + atoi(b.c_str());<br />}<br /><br />int main()<br />{<br />    int i = my_add(1, 2);                <font color="#008000">// 两个整数相加</font><br />    int s = my_add(1, "2");              <font color="#008000">// 一个整数和一个字符串相加</font><br />    std::cout &lt;&lt; "i = " &lt;&lt; i &lt;&lt; "\n";<br />    std::cout &lt;&lt; "s = " &lt;&lt; s &lt;&lt; "\n";<br />} </span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">根据参数列表的不同（类型、个数或兼而有之），<span lang="EN-US">my_add(1, 2)和my_add(1, "2")被分别编译为对my_add(int, int)和my_add(int, std::string)的调用。实现原理在于编译器根据不同的参数列表对同名函数进行名字重整，而后这些同名函数就变成了彼此不同的函数。比方说，也许某个编译器会将my_add()函数名字分别重整为my_add_int_int()和my_add_int_str()。</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<b>
																<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">宏多态</span>
														</b>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt">带变量的宏可以实现一种初级形式的静态多态：</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<font color="#0000ff">// macro_poly.cpp</font>
																<br />
																<br />#include &lt;iostream&gt;<br />#include &lt;string&gt;<br /><br /><font color="#008000">// 定义泛化记号：宏ADD</font><br />#define ADD(A, B) (A) + (B);<br /><br />int main()<br />{<br />    int i1(1), i2(2);<br />    std::string s1("Hello, "), s2("world!");<br />    int i = ADD(i1, i2);                        <font color="#008000">// 两个整数相加</font><br />    std::string s = ADD(s1, s2);                <font color="#008000">// 两个字符串“相加”</font><br />    std::cout &lt;&lt; "i = " &lt;&lt; i &lt;&lt; "\n";<br />    std::cout &lt;&lt; "s = " &lt;&lt; s &lt;&lt; "\n";<br />}</span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">当程序被编译时，表达式<span lang="EN-US">ADD(i1, i2)和ADD(s1, s2)分别被替换为两个整数相加和两个字符串相加的具体表达式。整数相加体现为求和，而字符串相加则体现为连接。程序的输出结果符合直觉：</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">1 + 2 = 3<br />Hello, + world! = Hello, world!<o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<b>
																<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">动态多态</span>
														</b>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<o:p>
																</o:p>
														</span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">这就是众所周知的的多态。现代面向对象语言对这个概念的定义是一致的。其技术基础在于</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">继承机制和虚函数。例如，我们可以定义一个抽象基类<span lang="EN-US">Vehicle</span></span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">和两个派生于<span lang="EN-US">Vehicle的具体类Car和Airplane：</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">
																<font color="#0000ff">// dynamic_poly.h</font>
																<br />
																<br />#include &lt;iostream&gt;<br /><br /><font color="#008000">// 公共抽象基类Vehicle</font><br />class Vehicle<br />{<br />public:<br />    virtual void run() const = 0;<br />};<br /><br /><font color="#008000">// 派生于Vehicle的具体类Car</font><br />class Car: public Vehicle<br />{<br />public:<br />    virtual void run() const<br />    {<br />        std::cout &lt;&lt; "run a car\n";<br />    }<br />};<br /><br /><font color="#008000">// 派生于Vehicle的具体类Airplane</font><br />class Airplane: public Vehicle<br />{<br />public:<br />    virtual void run() const<br />    {<br />        std::cout &lt;&lt; "run a airplane\n";<br />    }<br />};</span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">客户程序可以通过指向基类<span lang="EN-US">Vehicle的指针（或引用）来操纵具体对象。通过指向基类对象的指针（或引用）来调用一个虚函数，会导致对被指向的具体对象之相应成员的调用：</span></span>
												</p>
												<p class="MsoNormal">
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<font color="#0000ff">// dynamic_poly_1.cpp</font>
																<br />
																<br />#include &lt;iostream&gt;<br />#include &lt;vector&gt;<br />#include "dynamic_poly.h"<br /><br /><font color="#008000">// 通过指针run任何vehicle</font><br />void run_vehicle(const Vehicle* vehicle)<br />{<br />    vehicle-&gt;run();            <font color="#008000">// 根据vehicle的具体类型调用对应的run()</font><br />}<br /><br />int main()<br />{<br />    Car car;<br />    Airplane airplane;<br />    run_vehicle(&amp;car);         <font color="#008000">// 调用Car::run()</font><br />    run_vehicle(&amp;airplane);    <font color="#008000">// 调用Airplane::run()</font><br />}</span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">此例中，关键的多态接口元素为</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">虚函数<span lang="EN-US">run()。由于</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">run_vehicle()的参数为指向基类Vehicle的指针</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">，因而无法在编译期决定使用哪一个版本的<span lang="EN-US">run()。在运行期，为了分派函数调用，虚函数被调用的那个对象的完整动态类型将被访问。这样一来，对一个Car对象调用</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">run_vehicle()</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">，</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">实际上将</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">调用<span lang="EN-US">Car::run()，而对于Airplane对象而言将调用Airplane::run()。</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<o:p>
																</o:p>
														</span>
												</p>
												<p class="MsoNormal" style="TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">或许动态多态最吸引人之处在于处理异质对象集合的能力：</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<font color="#0000ff">// dynamic_poly_2.cpp</font>
																<br />
																<br />#include &lt;iostream&gt;<br />#include &lt;vector&gt;<br />#include "dynamic_poly.h"<br /><br /><font color="#008000">// run异质vehicles集合</font><br />void run_vehicles(const std::vector&lt;Vehicle*&gt;&amp; vehicles)<br />{<br />    for (unsigned int i = 0; i &lt; vehicles.size(); ++i)<br />    {<br />        vehicles[i]-&gt;run();     <font color="#008000">// 根据具体vehicle的类型调用对应的run()</font><br />    }<br />}<br /><br />int main()<br />{<br />    Car car;<br />    Airplane airplane;<br />    std::vector&lt;Vehicle*&gt; v;    <font color="#008000">// 异质vehicles集合</font><br />    v.push_back(&amp;car);<br />    v.push_back(&amp;airplane);<br />    run_vehicles(v);            <font color="#008000">// run不同类型的vehicles</font><br />}</span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">在<span lang="EN-US">run_vehicles()中，vehicles[i]-&gt;run()</span></span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">依据正被迭代的元素的类型而调用不同的成员函数。这从一个侧面体现了面向对象编程风格的优雅。</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<o:p>
																</o:p>
														</span>
												</p>
												<p class="MsoNormal">
														<b>
																<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">静态多态</span>
														</b>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">如果说动态多态是通过虚函数来表达共同接口的话，那么静态多态则是通过“彼此单独定义但支持共同操作的具体类”来表达共同性，换句话说，必须存在必需的同名成员函数。</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> </span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">
																<o:p>
																</o:p>
														</span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-FAMILY: 宋体">
																<span style="FONT-SIZE: 9pt; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">我们可以采用静态多态机制重写上一节的例子。这一次，我们不再定义vehicles类层次结构，相反，我们编写彼此无关的具体类Car和Airplane（它们都有一个run()成员函数）：</span>
														</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<font color="#0000ff">// static_poly.h</font>
																<br />
																<br />#include &lt;iostream&gt;<br /><br /><font color="#008000">//具体类Car</font><br />class Car<br />{<br />public:<br />    void run() const<br />    {<br />        std::cout &lt;&lt; "run a car\n";<br />    }<br />};<br /><br /><font color="#008000">//具体类Airplane</font><br />class Airplane<br />{<br />public:<br />    void run() const<br />    {<br />        std::cout &lt;&lt; "run a airplane\n";<br />    }<br />};<br /></span>
												</p>
												<p class="MsoNormal">
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">run_vehicle()应用程序被改写如下： <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">
																<font color="#0000ff">// static_poly_1.cpp</font>
																<br />
																<br />#include &lt;iostream&gt;<br />#include &lt;vector&gt;<br />#include "static_poly.h"<br /><br /><font color="#008000">// 通过引用而run任何vehicle</font><br />template &lt;typename Vehicle&gt;<br />void run_vehicle(const Vehicle&amp; vehicle)<br />{<br />    vehicle.run();            <font color="#008000">// 根据vehicle的具体类型调用对应的run()</font><br />}<br /> <br />int main()<br />{<br />    Car car;<br />    Airplane airplane;<br />    run_vehicle(car);         <font color="#008000">// 调用Car::run()</font><br />    run_vehicle(airplane);    <font color="#008000">// 调用Airplane::run()</font><br />} </span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">现在</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">Vehicle用作</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">模板参数而非公共基类对象（事实上，这里的</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">Vehicle只是一个符合直觉的记号而已，此外别无它意</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">）。经过编译器处理后，我们最终会得到</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">run_vehicle</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">&lt;Car&gt;()</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">和 </span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">run_vehicle</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">&lt;Airplane&gt;()两个不同的函数</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">。</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">这和动态多态不同，动态多态</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">凭借虚函数分派机制</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">在运行期只有一个</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">run_vehicle</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">()函数。</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">我们无法再透明地处理异质对象集合了，因为所有类型都必须在编译期予以决定。不过，为不同的<span lang="EN-US">vehicles引入不同的集合只是举手之劳。由于无需再将集合元素局限于指针或引用，我们现在可以从执行性能和类型安全两方面获得好处：</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<font color="#0000ff">// static_poly_2.cpp<br /></font>
																<br />#include &lt;iostream&gt;<br />#include &lt;vector&gt;<br />#include "static_poly.h"<br /><br /><font color="#008000">// run同质vehicles集合</font><br />template &lt;typename Vehicle&gt;<br />void run_vehicles(const std::vector&lt;Vehicle&gt;&amp; vehicles)<br />{<br />    for (unsigned int i = 0; i &lt; vehicles.size(); ++i) <br />    {<br />        vehicles[i].run();            <font color="#008000">// 根据vehicle的具体类型调用相应的run()</font><br />    }<br />}<br /><br />int main()<br />{<br />    Car car1, car2;<br />    Airplane airplane1, airplane2;<br /><br />    std::vector&lt;Car&gt; vc;              <font color="#008000">// 同质cars集合</font><br />    vc.push_back(car1);<br />    vc.push_back(car2);<br />   <font color="#ff0000"> //vc.push_back(airplane1);        // 错误：类型不匹配</font><br />    run_vehicles(vc);                 <font color="#008000">// run cars</font><br /><br />    std::vector&lt;Airplane&gt; vs;         <font color="#008000">// 同质airplanes集合</font><br />    vs.push_back(airplane1);<br />    vs.push_back(airplane2);<br />    <font color="#ff0000">//vs.push_back(car1);             // 错误：类型不匹配</font><br />    run_vehicles(vs);                 <font color="#008000">// run airplanes</font><br />}<br /></span>
												</p>
												<p class="MsoNormal">
														<b>
																<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">两种多态机制的结合使用</span>
														</b>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">在一些高级<span lang="EN-US">C++应用中，我们可能需要结合使用动态多态和静态多态两种机制，以期达到对象操作的优雅、安全和高效。例如，我们既希望一致而优雅地处理vehicles的run问题，又希望“安全而高效”地完成给飞行器（飞机、飞艇等）进行“空中加油”这样的高难度动作。为此，我们首先将上面的vehicles类层次结构改写如下：</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<font color="#0000ff">// dscombine_poly.h</font>
																<br />
																<br />#include &lt;iostream&gt;<br />#include &lt;vector&gt;<br /><br /><font color="#008000">// 公共抽象基类Vehicle</font><br />class Vehicle<br />{<br />    public:<br />    virtual void run() const = 0;<br />};<br /><br /><font color="#008000">// 派生于Vehicle的具体类Car</font><br />class Car: public Vehicle<br />{<br />public:<br />    virtual void run() const<br />    {<br />        std::cout &lt;&lt; "run a car\n";<br />    }<br />};<br /><br /><font color="#008000">// 派生于Vehicle的具体类Airplane</font><br />class Airplane: public Vehicle<br />{<br />public:<br />    virtual void run() const<br />    {<br />        std::cout &lt;&lt; "run a airplane\n";<br />    }<br />　</span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">    void add_oil() const<br />    {<br />        std::cout &lt;&lt; "add oil to airplane\n";<br />    }<br />};<br /><br /><font color="#008000">// 派生于Vehicle的具体类Airship</font><br />class Airship: public Vehicle<br />{<br />public:<br />    virtual void run() const<br />    {<br />        std::cout &lt;&lt; "run a airship\n";<br />    }<br />  </span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">    void add_oil() const<br />    {<br />        std::cout &lt;&lt; "add oil to airship\n";<br />    }<br />};<br /></span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">我们理想中的应用程序可以编写如下：</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">
																<font color="#0000ff">// dscombine_poly.cpp</font>
																<br />
																<br />#include &lt;iostream&gt;<br />#include &lt;vector&gt;<br />#include "dscombine_poly.h"<br /><br /><font color="#008000">// run异质vehicles集合</font><br />void run_vehicles(const std::vector&lt;Vehicle*&gt;&amp; vehicles)<br />{<br />    for (unsigned int i = 0; i &lt; vehicles.size(); ++i)<br />    {<br />        vehicles[i]-&gt;run();                 <font color="#008000">// 根据具体的vehicle类型调用对应的run()</font><br />    }<br />}<br /><br /><font color="#008000">// 为某种特定的aircrafts同质对象集合进行“空中加油”</font><br />template &lt;typename Aircraft&gt;<br />void add_oil_to_aircrafts_in_the_sky(const std::vector&lt;Aircraft&gt;&amp; aircrafts)<br />{<br />    for (unsigned int i = 0; i &lt; aircrafts.size(); ++i)<br />    {<br />        aircrafts[i].add_oil();<br />    }<br />}<br /><br />int main()<br />{<br />    Car car1, car2;<br />    Airplane airplane1, airplane2;<br /><br />    Airship airship1, airship2;<br />    std::vector&lt;Vehicle*&gt; v;                <font color="#008000">// 异质vehicles集合</font><br />    v.push_back(&amp;car1);<br />    v.push_back(&amp;airplane1);<br />    v.push_back(&amp;airship1);<br />    run_vehicles(v);                        <font color="#008000">// run不同种类的vehicles</font><br /><br />    std::vector&lt;Airplane&gt; vp;               <font color="#008000">// 同质airplanes集合</font><br />    vp.push_back(airplane1);<br />    vp.push_back(airplane2);<br />    add_oil_to_aircrafts_in_the_sky(vp);    <font color="#008000">// 为airplanes进行“空中加油”</font><br /><br />    std::vector&lt;Airship&gt; vs;                <font color="#008000">// 同质airships集合</font><br />    vs.push_back(airship1);<br />    vs.push_back(airship2);<br />    add_oil_to_aircrafts_in_the_sky(vs);    <font color="#008000">// 为airships进行“空中加油”</font><br />} <br /></span>
												</p>
												<p class="MsoNormal">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">我们保留了类层次结构，目的是为了能</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">够利用</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">run_vehicles()一致而优雅地处理</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">异质对象集合</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">vehicles的run问题。同时，利用函数模板add_oil_to_aircrafts_in_the_sky&lt;Aircraft&gt;()，我们仍然可以处理特定种类的vehicles — aircrafts（包括airplanes和airships）的“空中加油”问题。其中，我们避开使用指针，从而在</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">执行性能和类型安全两方面达到了预期目标。</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal">
														<b>
																<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt">结语</span>
														</b>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">长期以来，<span lang="EN-US">C++社群对于多态的内涵和外延一直争论不休。在comp.object这样的网络论坛上，此类话题争论至今仍随处可见。曾经有人将动态多态称为inclusion polymorphism，而将静态多态称为parametric polymorphism或parameterized polymorphism。</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">我注意到<span lang="EN-US">2003年斯坦福大学公开的一份</span>《C++ and Object-Oriented Programming》教案中<span lang="EN-US">明确提到了函数多态概念 — “Function overloading is also referred to as function polymorphism as it involves one function having many forms”。文后的“参考文献”单元给出了这个网页链接。</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">可能你是第一次看到宏多态<span lang="EN-US">这个术语。不必讶异，也许我就是造出这个术语的“第一人”。显然，带变量的宏（或类似于函数的宏或伪函数宏）的替换机制除了免除小型函数的调用开销之外，也表现出了类似的多态性。在我们上面的例子中，字符串相加所表现出来的符合直觉的连接操作，事实上是由底部运算符重载机制支持的。值得指出的是，C++社群中有人将运算符重载所表现出来的多态称为ad hoc polymorphism。</span></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">David Vandevoorde和Nicolai M. Josuttis在他们的著作《C++ Templates: The </span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">Complete Guide》一<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">书中系统地阐述了静态多态和动态多态技术。因为认为“</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">和其他语言机制关系不大”，这本书没有提及宏多态（以及函数多态）。（需要说明的是，笔者本人是这本书的繁体中文版译者之一，本文正是基于这本书的第14章“The Polymorphic Power of Templates”写作而成）</span></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">动态多态只需要一个多态函数，生成的可执行代码尺寸较小，静态多态必须针对不同的类型产生不同的模板实体，尺寸会大一些，但生成的代码会更快，因为无需通过指针进行间接操作。静态多态比动态多态更加类型安全，因为全部绑定都被检查于编译期。正如前面例子所示，你不可将一个错误的类型的对象插入到从一个模板实例化而来的容器之中。此外，正如你已经看到的那样，动态多态可以优雅地处理异质对象集合，而静态多态可以用来实现安全、高效的同质对象集合操作。</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">静态多态为<span lang="EN-US">C++带来了泛型编程（generic programming）的概念。泛型编程可以认为是“组件功能基于框架整体而设计”的模板编程。STL就是泛型编程的一个典范。STL是一个框架，它提供了大量的算法、容器和迭代器，全部以模板技术实现。从理论上讲，STL的功能当然可以使用动态多态来实现，不过这样一来其性能必将大打折扣。</span></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt"> <o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">静态多态还为C++社群带来了泛型模式（generic patterns）的概念。理论上，每一个需要通过虚函数和类继承而支持的设计模式都可以利用基于模板的静态多态技术（甚至可以结合使用动态多态和静态多态两种技术）而实现。正如你看到的那样，Andrei Alexandrescu的天才作品《Modern C++ Design: Generic Programming and Design Patterns Applied》（Addison-Wesley）和Loki程序库</span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">已经走在了我们的前面。</span>
												</p>
												<p class="MsoNormal" style="mso-layout-grid-align: none">
														<b>
																<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">参考文献</span>
														</b>
												</p>
												<p class="MsoNormal" style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt; mso-layout-grid-align: none; mso-list: l2 level1 lfo3; tab-stops: list 18.0pt">
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">1. </span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">David Vandevoorde, Nicolai M. Josuttis, <i>C++ Templates: The Complete Guide</i>, Addison Wesley, 2002.<o:p></o:p></span>
												</p>
												<p class="MsoNormal" style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt; mso-layout-grid-align: none; mso-list: l2 level1 lfo3; tab-stops: list 18.0pt">
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">2. </span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 0pt">Chris Neumann, CS193d (Summer 2003) <i>C++ and Object-Oriented Programming</i>, <a href="http://www.stanford.edu/class/cs193d" target="_blank">http://www.stanford.edu/class/cs193d/</a>, 2003.</span>
												</p>
												<p class="MsoNormal" style="TEXT-ALIGN: right" align="right">
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体">荣耀<br /></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体">200</span>
														<span lang="en-us" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体">3</span>
														<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体">年<span lang="EN-US">10</span>月<br />南京师范大学<br /></span>
														<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体">www.royaloo.com</span>
												</p>
										</td>
								</tr>
								<tr>
										<td valign="top" align="left" width="910" bgcolor="#ffffff" height="15">
										</td>
								</tr>
								<tr>
										<td valign="bottom" align="left" width="973" bgcolor="#ffffff" height="16">
										</td>
								</tr>
						</tbody>
				</table>
		</center>
<img src ="http://www.cppblog.com/ningfangli-blog/aggbug/15662.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ningfangli-blog/" target="_blank">ningfangli</a> 2006-11-25 20:36 <a href="http://www.cppblog.com/ningfangli-blog/articles/15662.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>