﻿<?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/tszhao/category/16952.html</link><description>--专注C++
--MSN：tszhao10@hotmail.com</description><language>zh-cn</language><lastBuildDate>Sat, 04 Jun 2011 12:17:54 GMT</lastBuildDate><pubDate>Sat, 04 Jun 2011 12:17:54 GMT</pubDate><ttl>60</ttl><item><title>纯虚函数能为private吗？</title><link>http://www.cppblog.com/tszhao/articles/147457.html</link><dc:creator>tszhao</dc:creator><author>tszhao</author><pubDate>Sat, 28 May 2011 01:13:00 GMT</pubDate><guid>http://www.cppblog.com/tszhao/articles/147457.html</guid><wfw:comment>http://www.cppblog.com/tszhao/comments/147457.html</wfw:comment><comments>http://www.cppblog.com/tszhao/articles/147457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tszhao/comments/commentRss/147457.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tszhao/services/trackbacks/147457.html</trackback:ping><description><![CDATA[<span class="Apple-style-span" style="font-family: Arial; line-height: 25px; "><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21.75pt; "><font size="2"><span style="font-family: 宋体; ">我们把一个仅仅含有纯虚函数的类称为接口，我们也好像已经习惯了将这个接口中的所有纯虚函数全声明为</span><font face="Times New Roman">public</font><span style="font-family: 宋体; ">，而且按照这样的设计，一切都工作得不错。比如</span><font face="Times New Roman">COM</font><span style="font-family: 宋体; ">正是这样做的，它的接口中几乎不会存在</span><font face="Times New Roman">private</font><span style="font-family: 宋体; ">的纯虚函数。那么，让我们想一想，纯虚函数或者虚函数可以为</span><font face="Times New Roman">private</font><span style="font-family: 宋体; ">吗？如果这种方式是可行的，那么什么时候可以将（纯）虚函数设为</span><font face="Times New Roman">private</font></font><span style="font-family: 宋体; "><font size="2">了？这些都是本文将要讨论的主题。一起来看看。<br /></font></span><strong><span style="font-size: 12pt; font-family: 宋体; "><br /><span style="font-size: 12pt; font-family: 宋体; "><br /><font size="2">一．访问限定符与继承</font></span><strong><span style="font-size: 12pt; "><font face="Times New Roman" size="2">&nbsp;&nbsp;</font></span></strong></span></strong><strong><span style="font-size: 12pt; "><font face="Times New Roman"><font size="2">&nbsp;</font></font></span></strong></p><strong><font face="Times New Roman"></font></strong><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21pt; "><span style="font-family: 宋体; "><font size="2">如果基类隐式（间接）向子类暴露了私有成员，那么从某种意义上讲，该私有成员对于子类是可见的。</font></span></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21pt; "><font size="2"><span style="font-family: 宋体; ">任何一本讲</span><font face="Times New Roman">C++</font><span style="font-family: 宋体; ">基础的课本上都详细地介绍了访问限定符与继承的关系，在这里就不重复了，但是，课本上的东西并不全，不信？那么请先看看下面的例子：<br /></span></font></p><p style="margin-top: 5px; margin-right: auto; margin-left: auto; margin-bottom: 5px; text-indent: 0px; "><span style="font-family: 宋体; "><font size="2"></font></span></p><font size="2"><div style="border-right-color: windowtext; border-right-width: 0.5pt; border-right-style: solid; padding-right: 5.4pt; border-top-color: windowtext; border-top-width: 0.5pt; border-top-style: solid; padding-left: 5.4pt; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #e6e6e6; padding-bottom: 4px; border-left-color: windowtext; border-left-width: 0.5pt; border-left-style: solid; width: 994px; word-break: break-all; padding-top: 4px; border-bottom-color: windowtext; border-bottom-width: 0.5pt; border-bottom-style: solid; background-position: initial initial; background-repeat: initial initial; "><div><font face="Courier New"><span style="color: #000000; ">#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #0000ff; ">string</span><span style="color: #000000; ">&gt;</span></font><font face="Courier New"><span style="color: #000000; ">&nbsp;&nbsp;<br />#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">iostream</span><span style="color: #000000; ">&gt;</span></font><font face="Courier New"><span style="color: #000000; ">&nbsp;<br /></span><span style="color: #0000ff; ">using</span>&nbsp;<span style="color: #0000ff; ">namespace</span></font><font face="Courier New"><span style="color: #000000; ">&nbsp;std&nbsp;;&nbsp;<br /><br /></span><span style="color: #0000ff; ">class</span></font><font face="Courier New"><span style="color: #000000; ">&nbsp;Base&nbsp;<br />{&nbsp;<br /></span><span style="color: #0000ff; ">private</span></font><font face="Courier New"><span style="color: #000000; ">:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">string</span><span style="color: #000000; ">&nbsp;classID()&nbsp;</span><span style="color: #0000ff; ">const</span></font><span style="color: #000000; "><br /><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span><font face="Courier New"><span style="color: #0000ff; ">return</span>&nbsp;<span style="color: #0000ff; ">string</span><span style="color: #000000; ">(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Base</span><span style="color: #000000; ">"</span></font><font face="Courier New"><span style="color: #000000; ">)&nbsp;;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br /><br /></span><span style="color: #0000ff; ">protected</span></font><font face="Courier New"><span style="color: #000000; ">:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">virtual</span>&nbsp;<span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;doWork()&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&nbsp;;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">纯虚函数</span></font><span style="color: #008000; "><br /></span><span style="color: #000000; "><br /></span><span style="color: #0000ff; "><font face="Courier New">public</font></span><font face="Courier New"><span style="color: #000000; ">:&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">void</span></font><font face="Courier New"><span style="color: #000000; ">&nbsp;work()&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000; ">&lt;&lt;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">this&nbsp;class&nbsp;id&nbsp;is&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&lt;&lt;</span><span style="color: #000000; ">classID()</span><span style="color: #000000; ">&lt;&lt;</span></font><font face="Courier New"><span style="color: #000000; ">endl&nbsp;;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;doWork()&nbsp;;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">virtual</span>&nbsp;<span style="color: #000000; ">~</span></font><font face="Courier New"><span style="color: #000000; ">Base()&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />};&nbsp;<br /><br /></span><span style="color: #0000ff; ">class</span><span style="color: #000000; ">&nbsp;DerivedA&nbsp;:&nbsp;</span><span style="color: #0000ff; ">public</span></font><font face="Courier New"><span style="color: #000000; ">&nbsp;Base&nbsp;<br />{&nbsp;<br /></span><span style="color: #0000ff; ">private</span></font><font face="Courier New"><span style="color: #000000; ">:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">string</span><span style="color: #000000; ">&nbsp;classID()&nbsp;</span><span style="color: #0000ff; ">const</span></font><font face="Courier New"><span style="color: #000000; ">&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">return</span>&nbsp;<span style="color: #0000ff; ">string</span><span style="color: #000000; ">(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">DerivedA</span><span style="color: #000000; ">"</span></font><font face="Courier New"><span style="color: #000000; ">)&nbsp;;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br /><br /></span><span style="color: #0000ff; ">protected</span></font><font face="Courier New"><span style="color: #000000; ">:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">void</span></font><font face="Courier New"><span style="color: #000000; ">&nbsp;doWork()&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000; ">&lt;&lt;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">this&nbsp;is&nbsp;DerivedA&nbsp;doWork&nbsp;!</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&lt;&lt;</span></font><span style="color: #000000; "><font face="Courier New">endl&nbsp;;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />};<br /><br /></font></span></div></div><p style="margin-top: 5px; margin-right: auto; margin-left: auto; margin-bottom: 5px; text-indent: 0px; ">&nbsp;&nbsp;&nbsp; 以上的代码声明了一个基类和一个子类，不过比较奇特的是基类的提供的公共接口是非虚的，而这个非虚的公共接口却调用了一个非虚的私有函数和一个虚拟的保护函数。接着，子类重定义了这两个函数。那么下面的调用会输出什么了?&nbsp;&nbsp;&nbsp;</p><div style="border-right-color: windowtext; border-right-width: 0.5pt; border-right-style: solid; padding-right: 5.4pt; border-top-color: windowtext; border-top-width: 0.5pt; border-top-style: solid; padding-left: 5.4pt; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #e6e6e6; padding-bottom: 4px; border-left-color: windowtext; border-left-width: 0.5pt; border-left-style: solid; width: 994px; word-break: break-all; padding-top: 4px; border-bottom-color: windowtext; border-bottom-width: 0.5pt; border-bottom-style: solid; background-position: initial initial; background-repeat: initial initial; "><div><span style="color: #000000; ">Base</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;bp&nbsp;</span><span style="color: #000000; ">=</span>&nbsp;<span style="color: #0000ff; ">new</span><span style="color: #000000; ">&nbsp;DerivedA()&nbsp;;&nbsp;<br />bp</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">work()&nbsp;;&nbsp;&nbsp;<br />delete&nbsp;bp&nbsp;;&nbsp;</span></div></div></font><p style="margin-top: 5px; margin-right: auto; margin-left: auto; margin-bottom: 5px; text-indent: 0px; "><font size="2">&nbsp;&nbsp;&nbsp;以下是输出的结果：<br />&nbsp;&nbsp;&nbsp;this class id is Base&nbsp;<br />&nbsp;&nbsp;&nbsp;this is DerivedA doWork !&nbsp;<br /></font><span style="color: black; font-family: 宋体; "><font size="2"><br />&nbsp;&nbsp;&nbsp;怎么回事？为什么不是</font></span><span style="color: black; "><font size="2">&nbsp;<br /></font></span><strong><span style="color: black; "><font face="Times New Roman" size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this class id is&nbsp;</font></span></strong><strong><span style="color: black; font-family: Courier; "><font size="2">DerivedA</font></span><span style="color: black; "><font size="2">&nbsp;<br /></font></span></strong><font face="Times New Roman"><strong><span style="color: black; "><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this is DerivedA doWork !</font></span></strong><span style="color: black; "></span></font></p><font face="Times New Roman"></font><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21pt; "><font size="2"><span style="color: black; font-family: 宋体; ">子类的</span><span style="color: black; font-family: Courier; ">classID</span><span style="color: black; font-family: 宋体; ">（）不是将基类的</span><span style="color: black; font-family: Courier; ">classID</span><span style="color: black; font-family: 宋体; ">（）覆盖了么？我们来分析一下，</span><span style="color: black; font-family: 宋体; ">基类中的公共的</span><span style="color: black; "><font face="Times New Roman">work</font></span><span style="color: black; font-family: 宋体; ">（）成员函数调用了私有的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">（）成员函数，根据输出的结果来看，在子类中定义的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">方法并没有覆盖基类的同名方法，为什么呢？难道是因为</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">是</span><span style="color: black; "><font face="Times New Roman">private</font></span><span style="color: black; font-family: 宋体; ">导致的？那好，我们将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">函数改为</span><span style="color: black; "><font face="Times New Roman">public</font></span><span style="color: black; font-family: 宋体; ">再次运行，我们期望的结果出现了吗？呵呵，很抱歉，没有，希望再次破灭了，为什么会这样？这主要涉及的原因是：<strong>普通函数的调用是在编译期确定的</strong>，当</span><span style="color: black; "><font face="Times New Roman">work</font></span><span style="color: black; font-family: 宋体; ">函数一看到所调用的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">是非虚的，就会毫无疑问地去直接使用基类的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">。这一切与</span><span style="color: black; "><font face="Times New Roman">Base</font></span><span style="color: black; font-family: 宋体; ">类是否会被继承没有任何关系，跟</span><span style="color: black; "><font face="Times New Roman">Base</font></span><span style="color: black; font-family: 宋体; ">类被继承后子类会否再次定义</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">就更没有关系了。<br /></span></font><font size="2"><span style="color: black; font-family: 宋体; "><br />&nbsp;&nbsp;&nbsp;那么这种情况下，</span><span style="color: black; "><font face="Times New Roman">Base</font></span><span style="color: black; font-family: 宋体; ">类将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><span style="color: black; "><font face="Times New Roman">private</font></span><span style="color: black; font-family: 宋体; ">和</span><span style="color: black; "><font face="Times New Roman">public/protected</font></span><span style="color: black; font-family: 宋体; ">有什么区别了？当将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><span style="color: black; "><font face="Times New Roman">private</font></span><span style="color: black; font-family: 宋体; ">时，</span><span style="color: black; "><font face="Times New Roman">DerivedA</font></span><span style="color: black; font-family: 宋体; ">看不到基类的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">的声明，所以不会发生重定义；当将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><span style="color: black; "><font face="Times New Roman">public/protected</font></span><span style="color: black; font-family: 宋体; ">时，</span><span style="color: black; "><font face="Times New Roman">DerivedA</font></span><span style="color: black; font-family: 宋体; ">将看到基类的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明，于是会发生重定义，即会覆盖调基类的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">的定义。讲到这里就要提一下，如果当将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><span style="color: black; "><font face="Times New Roman">public/protected</font></span><span style="color: black; font-family: 宋体; ">，并且子类也定义同名的函数</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">，但是子类的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">与基类的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">的函数签名不同，那么此时发生的将是函数重载而不是覆盖。</span></font>&nbsp;<font size="2"><span style="font-family: 宋体; ">让我们更进一步，将基类和子类的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明都改为</span><font face="Times New Roman"><strong><span style="color: black; ">virtual public</span></strong></font><span style="color: black; font-family: 宋体; ">，再次运行程序，会得到以下输出：</span></font><span style="color: black; "><font size="2">&nbsp;<br /></font></span><strong><span style="color: black; "><font face="Times New Roman" size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this class id is&nbsp;</font></span></strong><strong><span style="color: black; font-family: Courier; "><font size="2">DerivedA</font></span><span style="color: black; "><font size="2">&nbsp;<br /></font></span></strong><font face="Times New Roman"><strong><span style="color: black; "><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this is DerivedA doWork !</font></span></strong></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21pt; "><font size="2"><span style="color: black; font-family: 宋体; ">而这正是我们所期望的，不是吗？这其中的原因也很容易理解，因为</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">是</span><span style="color: black; "><font face="Times New Roman">virtual&nbsp;</font></span><span style="color: black; font-family: 宋体; ">，并且是</span><span style="color: black; "><font face="Times New Roman">public</font></span><span style="color: black; font-family: 宋体; ">的，所以会产生多态调用。<br />&nbsp;&nbsp;&nbsp;</span></font><font size="2"><span style="font-family: 宋体; ">再往下走，将基类和子类的</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明改为</span><font face="Times New Roman"><strong><span style="color: black; ">virtual private</span></strong></font><span style="color: black; font-family: 宋体; ">，再次运行程序，看看输出了什么。<br /></span></font><strong><span style="color: black; "><font face="Times New Roman" size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this class id is&nbsp;</font></span></strong><strong><span style="color: black; font-family: Courier; "><font size="2">DerivedA</font></span><span style="color: black; "><font size="2">&nbsp;<br /></font></span></strong><font face="Times New Roman"><strong><span style="color: black; "><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this is DerivedA doWork !</font></span></strong></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21pt; "><font size="2"><span style="color: black; font-family: 宋体; ">没有变化，将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><strong><span style="color: black; "><font face="Times New Roman">virtual private</font></span></strong><span style="color: black; font-family: 宋体; ">和声明为</span><span style="color: black; "><font face="Times New Roman">&nbsp;<strong>virtual public</strong></font></span><span style="color: black; font-family: 宋体; ">得到的结果是一样的。&#8220;为什么会这样，</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">是</span><strong><span style="color: black; "><font face="Times New Roman">private</font></span></strong><span style="color: black; font-family: 宋体; ">啊？&#8221;你惊讶地叫出来。是，</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">是</span><strong><span style="color: black; "><font face="Times New Roman">private</font></span></strong><span style="color: black; font-family: 宋体; ">，但</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">也是</span><span style="color: black; "><font face="Times New Roman">virtual</font></span><span style="color: black; font-family: 宋体; ">，原因就在这里，用基类指针或引用进行虚函数调用采用的是动态绑定，看看编译器为调用</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">产生的代码就知道了：</span></font></p><p style="margin-top: 4.65pt; margin-right: 0cm; margin-left: 0cm; margin-bottom: 4.65pt; text-indent: 0px; "><font style="background-color: #d9d9d9; "><font size="2"><font face="Courier">//c++</font><span style="font-family: 宋体; ">伪码</span></font></font></p><p style="margin-top: 4.65pt; margin-right: 0cm; margin-left: 0cm; margin-bottom: 4.65pt; text-indent: 0px; "><font style="background-color: #d9d9d9; "><font face="Courier"><font size="2">(this-&gt;vptr[1])() ;</font></font></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21pt; "><font size="2"><span style="font-family: 宋体; ">在运行时期，通过</span><font face="Times New Roman">this</font><span style="font-family: 宋体; ">指针将会找到正确的</span><font face="Times New Roman">vtbl</font><span style="font-family: 宋体; ">，即</span><span style="color: black; font-family: Courier; ">DerivedA</span><span style="color: black; font-family: 宋体; ">类的</span><span style="color: black; font-family: Courier; ">vtbl</span><span style="color: black; font-family: 宋体; ">，这样自然就会出现上面的结果了。</span><span style="font-family: 宋体; ">那么将</span><span style="color: black; "><font face="Times New Roman">classID&nbsp;</font></span><span style="color: black; font-family: 宋体; ">声明为</span><font face="Times New Roman">private</font><span style="font-family: 宋体; ">限制了什么？和将非虚函数声明为</span><font face="Times New Roman">private</font><span style="font-family: 宋体; ">一样，这将使得在</span><font face="Times New Roman">Base</font><span style="font-family: 宋体; ">类外部无法调用多态函数</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">，只能在</span><span style="color: black; "><font face="Times New Roman">Base</font></span><span style="color: black; font-family: 宋体; ">内部调用，如通过</span><span style="color: black; "><font face="Times New Roman">work</font></span><span style="color: black; font-family: 宋体; ">函数调用。</span></font></p><p align="left" style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 0px; text-align: left; "><font size="2"><span style="color: black; font-family: 宋体; ">&nbsp;&nbsp;&nbsp;可见，多态性与将实现多态的函数的访问限定符没有任何关系，</span><span style="color: black; "><font face="Times New Roman">private&nbsp;</font></span><span style="color: black; font-family: 宋体; ">函数仍然可以实现多态，它的指针仍然位于</span><span style="color: black; "><font face="Times New Roman">vtbl</font></span><span style="color: black; font-family: 宋体; ">中，只不过该函数的多态一般只能在基类的内部由其他非虚函数调用该函数的时候反映出来，访问限定符仅仅限制外部对类的成员的访问权限，它并没有破坏以下规则：</span></font><span style="font-size: 10pt; color: black; ">&nbsp;<br /></span><font size="2"><span style="color: black; "><font face="Times New Roman"><br /><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</strong></font></span><strong><span style="color: black; font-family: 宋体; ">通过基类指针或引用调用成员函数时，如果该函数时非虚的，那么将采用静态绑定，即编译时绑定；如果该函数是虚拟的，则采用动态绑定，即运行时绑定。</span></strong></font><font size="2"><strong><span style="font-size: 12pt; font-family: 宋体; ">二．</span></strong><strong><span style="font-size: 12pt; "><font face="Times New Roman">virtual</font></span></strong></font><strong><span style="font-size: 12pt; font-family: 宋体; "><font size="2">与访问限定符结合</font></span></strong></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21pt; "><font size="2"><span style="font-family: 宋体; ">上面我们通过分析，已经知道了多态的实现与访问限定符没有任何关系，访问限定符只是控制类的成员对外部的可见性，但不限制多态。正如上面提到的，将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><strong><span style="color: black; "><font face="Times New Roman">virtual private</font></span></strong><span style="color: black; font-family: 宋体; ">和声明为</span><span style="color: black; "><font face="Times New Roman">&nbsp;<strong>virtual public</strong></font></span><span style="color: black; font-family: 宋体; ">后再次运行程序，得到的结果是一样的，上面我们简单的地分析了一下表面现象，但这个问题决不是这么简单，让我们挖掘更深层次的意义，我想这应该属于</span><span style="color: black; "><font face="Times New Roman">OOA</font></span><span style="color: black; font-family: 宋体; ">、</span><span style="color: black; "><font face="Times New Roman">OOD</font></span><span style="color: black; font-family: 宋体; ">的范畴了。好，让我们一步步看过来。</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21pt; "><font size="2"><span style="color: black; font-family: 宋体; ">当我们将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为非虚的</span><strong><span style="color: black; "><font face="Times New Roman">&nbsp;private</font></span></strong><span style="color: black; font-family: 宋体; ">时，子类将看不见它，当然也就无法覆盖或重载它，即在这中情况下，子类无法更改</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">的实现，但是子类继承了公共接口</span><span style="color: black; "><font face="Times New Roman">work</font></span><span style="color: black; font-family: 宋体; ">（），而这个接口调用了</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">，所以，可以看作，子类间接地继承了</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">的实现，并且这个实现是无法修改的。于是，我可以说，基类中声明一个普通私有成员函数，表示这是一个不可被更改的实现细节。</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 0px; "><font size="2"><span style="color: black; font-family: 宋体; ">再来讨论将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><strong><span style="color: black; "><font face="Times New Roman">virtual private</font></span></strong><span style="color: black; font-family: 宋体; ">的情况，声明为</span><span style="color: black; "><font face="Times New Roman">private</font></span><span style="color: black; font-family: 宋体; ">表示基类不想让子类看到这个函数，但是又声明为</span><span style="color: black; "><font face="Times New Roman">virtual</font></span><span style="color: black; font-family: 宋体; ">，表示基类想让这个函数实现多态。呵呵，基类既想实现多态，却又不让子类看见这个函数，这似乎有点自相矛盾，是吗？其实，这其中的意思是，子类既可以修改这个实现，也可以继承其基类默认的实现。所以可以这么说，如果基类中有一个虚拟私有成员函数，表示这是一个<strong>&#8220;可以&#8221;</strong>被派生类修改的实现细节。注意，当中的用词，是&#8220;可以&#8221;，而不是别的。</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21.75pt; "><font size="2"><span style="color: black; font-family: 宋体; ">最后来看看将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><strong><span style="color: black; "><font face="Times New Roman">virtual protected</font></span></strong><span style="color: black; font-family: 宋体; ">的情况。将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><strong><span style="color: black; "><font face="Times New Roman">protected</font></span></strong><span style="color: black; font-family: 宋体; ">表示基类<strong>&#8220;需要&#8221;</strong>子类看见这个函数，注意，我使用&#8220;需要&#8221;这个动词，这个词表示了一定的&#8220;强制&#8221;意味。与将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><strong><span style="color: black; "><font face="Times New Roman">virtual private</font></span></strong><span style="color: black; font-family: 宋体; ">的情况对比一下，我想你已经知道答案了，即是，如果基类中有一个虚拟保护成员函数，表示这是一个<strong>必须</strong>被派生类修改的实现细节。&#8220;必须&#8221;这个词表达了强制的意思。</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21.75pt; "><font size="2"><span style="color: black; font-family: 宋体; ">关于&#8220;</span><span style="font-family: 宋体; ">将</span><font face="Times New Roman">virtual</font><span style="font-family: 宋体; ">与访问限定符结合&#8221;的问题</span><span style="color: black; font-family: 宋体; ">就讨论这么多，你也许说，还漏掉了将</span><span style="color: black; "><font face="Times New Roman">classID</font></span><span style="color: black; font-family: 宋体; ">声明为</span><strong><span style="color: black; "><font face="Times New Roman">virtual public</font></span></strong><span style="color: black; font-family: 宋体; ">的情况。是的，其实，我并不推荐将虚拟函数声明为</span><span style="color: black; "><font face="Times New Roman">public</font></span><span style="color: black; font-family: 宋体; ">，尽管这种方式在现在很流行，我推荐将其使用</span><strong><span style="color: black; "><font face="Times New Roman">virtual protected</font></span></strong><span style="color: black; font-family: 宋体; ">来替换，这就说明基类必须另外发布一个几乎不更改的非虚</span><span style="color: black; "><font face="Times New Roman">public</font></span><span style="color: black; font-family: 宋体; ">接口，在这个接口中调用了</span><strong><span style="color: black; "><font face="Times New Roman">virtual protected</font></span></strong><span style="color: black; font-family: 宋体; ">或</span><strong><span style="color: black; "><font face="Times New Roman">virtual private</font></span></strong><span style="color: black; font-family: 宋体; ">函数，这样以来，我们就对类的内部实现作了进一步的隐藏，而这无论是对系统的可扩展性，还是可维护性都是大有帮助的。</span><span style="font-family: 宋体; ">&#8220;虚拟函数应该和数据成员一样对待&#8213;&#8213;让他们成为私有的，除非设计需求表明应该有较少的限制。提升它们到更高存取级别比把它们降到更私有的级别更容易些。&#8221;</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21.75pt; "><span style="color: black; font-family: 宋体; "><font size="2">最后，把上面所说的小结一下：</font></span></p><p align="left" style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 0px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #e0e0e0; text-align: left; background-position: initial initial; background-repeat: initial initial; "><span style="font-size: 10pt; color: black; "><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span><strong><span style="color: black; font-family: 宋体; "><font size="2">基类中的一个普通私有成员函数，表示这是一个不可被更改的实现细节。</font></span></strong><strong><span style="color: black; "><font size="2">&nbsp;<br /></font></span></strong><font size="2"><strong><span style="color: black; "><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span></strong><strong><span style="color: black; font-family: 宋体; ">基类中的一个虚拟私有成员函数，表示这是一个可以被派生类修改的实现细节。<br /></span></strong></font><font size="2"><strong><span style="color: black; "><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span></strong><strong><span style="color: black; font-family: 宋体; ">基类中的一个虚拟保护成员函数，表示这是一个必须被派生类修改的实现细节。</span></strong></font><strong><span style="color: black; "><font size="2">&nbsp;<br />&nbsp;&nbsp;&nbsp;</font></span></strong><font size="2"><strong><span style="color: black; "><font face="Times New Roman">&nbsp;&nbsp;&nbsp;</font></span></strong><strong><span style="color: black; font-family: 宋体; ">最好不要将虚拟成员函数声明为</span></strong><strong><span style="color: black; "><font face="Times New Roman">public</font></span></strong><strong><span style="color: black; font-family: 宋体; ">，而是用</span></strong><strong><span style="color: black; "><font face="Times New Roman">protected</font></span></strong><strong><span style="color: black; font-family: 宋体; ">来替换。</span></strong></font><strong></strong></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 0px; "><strong><span style="font-size: 12pt; font-family: 宋体; "><font size="2">三．模板方法模式</font></span></strong><strong></strong></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21pt; "><font size="2"><span style="font-family: 宋体; ">在理解了上面所述的内容的情况下，再来理解模板方法模式就非常</span><font face="Times New Roman">easy</font><span style="font-family: 宋体; ">了，模板方法是在</span><font face="Times New Roman">GOF</font><span style="font-family: 宋体; ">的经典大作《设计模式》中阐述了一种模式，该模式定义了一个操作中的算法的骨架，而将一些步骤的实现延迟到子类中，模板方法使得派生类可以不改变一个算法的结构即可重定义算法的某些特定步骤。在这里，我不想再重复解释这个模式如何实现的，我仅仅举个例子，这个例子将体现出模板方法中最重要的思想。</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21pt; "><font size="2"><span style="font-family: 宋体; ">假设基类定义的一个算法的骨架由</span><font face="Times New Roman">3</font><span style="font-family: 宋体; ">个步骤完成，其中第一个步骤是该继承体系中不可被改变的一个步骤，即所有的类对该步骤的实现都是一样的，那个这个步骤可以设置为非虚的</span><font face="Times New Roman">private&nbsp;</font><span style="font-family: 宋体; ">；第二个步骤是一个可以被派生类改写也可以不被改写的步骤，通过上面的讨论知道，可以将其设为</span><font face="Times New Roman">virtual private&nbsp;</font><span style="font-family: 宋体; ">；第三个步骤是针对每一个派生类的实现都不同，那么这个步骤可以被设为</span><font face="Times New Roman">virtual protected&nbsp;</font><span style="font-family: 宋体; ">，而且，步骤三只能针对特定的派生类才有意义，所以将步骤三也设为纯虚函数。如下面的代码所示：<br /></span></font></p><p align="left" style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 0px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #e0e0e0; text-align: left; background-position: initial initial; background-repeat: initial initial; "><font size="2"><span style="font-family: 宋体; ">&nbsp;</span></font></p><font size="2"><div style="border-right-color: windowtext; border-right-width: 0.5pt; border-right-style: solid; padding-right: 5.4pt; border-top-color: windowtext; border-top-width: 0.5pt; border-top-style: solid; padding-left: 5.4pt; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #e6e6e6; padding-bottom: 4px; border-left-color: windowtext; border-left-width: 0.5pt; border-left-style: solid; width: 994px; word-break: break-all; padding-top: 4px; border-bottom-color: windowtext; border-bottom-width: 0.5pt; border-bottom-style: solid; background-position: initial initial; background-repeat: initial initial; "><div><span style="color: #0000ff; "><font face="Courier New">class</font></span><font face="Courier New"><span style="color: #000000; ">&nbsp;BaseTemplate&nbsp;<br />{&nbsp;<br /></span><span style="color: #0000ff; ">private</span></font><font face="Courier New"><span style="color: #000000; ">:&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;step1(</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">)&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;不可被更改的实现细节&nbsp;</span></font><span style="color: #008000; "><br /></span><font face="Courier New"><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-style: initial; border-color: initial; " />&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-style: initial; border-color: initial; " />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">virtual</span>&nbsp;<span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;step2(</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;)&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;可以被派生类修改的实现细节&nbsp;</span></font><span style="color: #008000; "><br /></span><font face="Courier New"><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-style: initial; border-color: initial; " />&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-style: initial; border-color: initial; " />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br /><br /></span><span style="color: #0000ff; ">protected</span></font><font face="Courier New"><span style="color: #000000; ">:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">virtual</span>&nbsp;<span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;step3(</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;)&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;必须被派生类修改的实现细节&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></font><span style="color: #008000; "><br /></span><span style="color: #000000; "><br /></span><span style="color: #0000ff; "><font face="Courier New">public</font></span><font face="Courier New"><span style="color: #000000; ">:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;work(</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">)&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;骨架函数，实现了骨架&nbsp;</span></font><span style="color: #008000; "><br /></span><span style="color: #000000; "><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;step1()&nbsp;;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;step2()&nbsp;;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;step3()&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />};&nbsp;&nbsp;&nbsp;&nbsp;<br /></font></span></div></div></font><p align="left" style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 0px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #e0e0e0; text-align: left; background-position: initial initial; background-repeat: initial initial; "><font size="2"><br />&nbsp;&nbsp;&nbsp;注意，上例中根本没有暴露任何虚函数，所有的这一切都是通过<strong><span style="color: black; font-family: Courier; ">work</span></strong><strong><span style="color: black; font-family: 宋体; ">（）</span></strong><span style="color: black; font-family: 宋体; ">这个非虚的</span><span style="color: black; font-family: Courier; ">public</span><span style="color: black; font-family: 宋体; ">接口展现出来的，当我们用一个</span><span style="color: black; font-family: Courier; ">BaseTemplate</span><span style="color: black; font-family: 宋体; ">指针调用</span><strong><span style="color: black; font-family: Courier; ">work</span></strong><strong><span style="color: black; font-family: 宋体; ">（）</span></strong><span style="color: black; font-family: 宋体; ">时，表面上是一个非虚函数调用，采用静态绑定，事实上也正是这样，但是，这个调用的背后隐藏的却是多态调用，即</span><span style="color: black; font-family: Courier; ">step2</span><span style="color: black; font-family: 宋体; ">和</span><span style="color: black; font-family: Courier; ">step3</span><span style="color: black; font-family: 宋体; ">动态绑定了。看见，采用模板方法模式，不仅定义了一个算法的骨架，而且把这个骨架的实现的细节作了进一步的封装。我们可以</span><span style="font-family: 宋体; ">在模板方法模式中可以这样设计：</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 57pt; margin-bottom: 0pt; text-indent: -36pt; "><font size="2"><font face="Times New Roman">（1）<span style="font: normal normal normal 7pt/normal 'Times New Roman'; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></font><span style="font-family: 宋体; ">如果一个函数作为算法骨架中不可变更的一部分，那么可以将此函数作为基类的私有函数，并且在基类的公共骨架函数中调用该函数，即该函数作为骨架的一个不可更改的实现细节。</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 57pt; margin-bottom: 0pt; text-indent: -36pt; "><font size="2"><font face="Times New Roman">（2）<span style="font: normal normal normal 7pt/normal 'Times New Roman'; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></font><span style="font-family: 宋体; ">如果一个函数提供了算法骨架某环节的一个缺省实现，那么可以考虑将该函数作为基类的私有虚函数，表示子类可以改写它，也可以不改写它。</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 57pt; margin-bottom: 0pt; text-indent: -36pt; "><font size="2"><font face="Times New Roman">（3）<span style="font: normal normal normal 7pt/normal 'Times New Roman'; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></font><span style="font-family: 宋体; ">如果作为算法骨架一部分某个函数要求在子类中拥有不同的实现，那么可以考虑将该函数作为基类的保护（纯）虚函数，表示子类必须改写它。</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21.75pt; "><font size="2"><span style="font-family: 宋体; ">讲到这里，已经差不多了，在结束的时候，提一下语法与语义的联系。通常，语法是表象，语义是表象后面隐藏的东西，而这些隐藏的语义往往更具有价值。举个例子，</span><font face="Times New Roman">public</font><span style="font-family: 宋体; ">继承与</span><font face="Times New Roman">private</font><span style="font-family: 宋体; ">继承在语法方面似乎没有什么更多的东西值得探讨，它们的区别仅仅在于改变了继承得到的成员的可见性，但是从语义方面来分析，它们就相差太远了，</span><font face="Times New Roman">private</font><span style="font-family: 宋体; ">继承在语义上来讲是&#8220;通过基类来实现自己&#8221;，即是&#8220;实现继承&#8221;，在这种继承关系中，基类和子类的关系是很薄弱的；而</span><font face="Times New Roman">public</font><span style="font-family: 宋体; ">继承在语义上即是我们所熟知的&#8220;</span><font face="Times New Roman">IS-A</font><span style="font-family: 宋体; ">&#8221;关系，它体现了基类和子类之间的亲密性，也正是这种&#8220;</span><font face="Times New Roman">IS-A</font><span style="font-family: 宋体; ">&#8221;关系为多态性提供了基础。</span></font></p><p style="margin-top: 0cm; margin-right: 0cm; margin-left: 0cm; margin-bottom: 0pt; text-indent: 21.75pt; "><font size="2"><span style="font-family: 宋体; ">所以，通过表面的语法来挖掘其背后的语义很有意义，就像这篇文章中提到的将访问限定符与</span><font face="Times New Roman">virtual</font><span style="font-family: 宋体; ">结合起来的语法背后隐藏的语义，挖掘出这些语义，对于我们以后在进行设计时作恰当的抉择无疑是大有帮助的。</span></font></p></span><img src ="http://www.cppblog.com/tszhao/aggbug/147457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tszhao/" target="_blank">tszhao</a> 2011-05-28 09:13 <a href="http://www.cppblog.com/tszhao/articles/147457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>