﻿<?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++博客-Focus on ACE-随笔分类-C++&amp;OOP</title><link>http://www.cppblog.com/ace/category/1169.html</link><description>&lt;table style="border:1px solid #aa0033; font-size:small" align=center&gt;
  &lt;tr&gt;
    &lt;td rowspan=3&gt;
    
    &lt;/td&gt;
    &lt;td colspan=2 align=center&gt;&lt;b&gt;订阅 ace-china&lt;/b&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;form action="http://groups.google.com/group/ace-china/boxsubscribe"&gt;
  &lt;input type=hidden name="hl" value="zh-CN"&gt;
  &lt;tr&gt; 
    &lt;td&gt;电子邮件： &lt;input type=text name=email&gt;&lt;/td&gt;
    &lt;td&gt;
      &lt;table 
       style="background-color:#ffcc33;padding:2px;border:2px outset #ffcc33;"&gt;
      &lt;tr&gt;
        &lt;td&gt;
         &lt;input type=submit name="sub" value="订阅"&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
      &lt;/table&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
   &lt;/form&gt;
  &lt;tr&gt;&lt;td colspan=2 align=center&gt; 浏览存于  
	&lt;a href="http://groups.google.com/group/ace-china"&gt;groups.google.com&lt;/a&gt; 上的&lt;a href="http://groups.google.com/group/ace-china"&gt;所有帖子&lt;/a&gt; &lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</description><language>zh-cn</language><lastBuildDate>Tue, 20 May 2008 01:09:29 GMT</lastBuildDate><pubDate>Tue, 20 May 2008 01:09:29 GMT</pubDate><ttl>60</ttl><item><title>在Visual Studio 2005下使用CPPUnit向导</title><link>http://www.cppblog.com/ace/archive/2006/08/04/10842.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Fri, 04 Aug 2006 07:35:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/08/04/10842.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/10842.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/08/04/10842.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/10842.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/10842.html</trackback:ping><description><![CDATA[<p>使用CPPUnitProjectWizard向导创建支持使用CPPUnit的测试类的Visual Studio 2005项目。</p>
		<p>安装向导<br />0. 下载 CPPUnitProjectWizard<br />    <a href="http://cppunit.sourceforge.net/cppunit-wiki/CppUnitVisualStudio2005Wizard?action=AttachFile&amp;do=get&amp;target=CPPUnitProjectWizard.7z">http://cppunit.sourceforge.net/cppunit-wiki/CppUnitVisualStudio2005Wizard?action=AttachFile&amp;do=get&amp;target=CPPUnitProjectWizard.7z</a></p>
		<p>1. 复制文件<br />     CPPUnitProjectWizard.vsdir  - 为向导命名<br />     CPPUnitProjectWizard.vsz    - 让VS8知道从哪里找到向导<br />    到您的Visual Studio 8安装目录下的 VSProjects 文件夹中。<br />    <br />2. 把整个CPPUnitProjectWizard解决方案文件夹复制到您的Visual Studio 8安装目录下的VCWizards文件夹中。<br />   比如，我放在c:\Program Files\Microsoft Visual Studio 8\VC\VCWizards\CPPUnitProjectWizard\CPPUnitProjectWizard<br />   或者，也可以放在你想放置的其它地方，然后编译CPPUnitProjectWizard.vsz，定义参数 ABSOLUTE_PATH<br />   Param="ABSOLUTE_PATH = c:\Program Files\Microsoft Visual Studio 8\VC\VCWizards\CPPUnitProjectWizard\CPPUnitProjectWizard"<br />   <br />3. 该项目需要定义环境变量 CPPUNITDIR<br />   比如，我的环境变量  %CPPUNITDIR% = D:\cppunit-1.12.0<br />   最后，修改 环境变量 %PATH%,在PATH路径中，增加 %CPPUNITDIR%/lib，以便程序加载时能找到 cppunit_dll.dll<br />4. 在开发环境中，设置好Include/Lib路径<br />    %CPPUNITDIR%\Include<br />    %CPPUNITDIR%\LIB <br />    </p><img src ="http://www.cppblog.com/ace/aggbug/10842.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-08-04 15:35 <a href="http://www.cppblog.com/ace/archive/2006/08/04/10842.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>面向对象vs基于对象</title><link>http://www.cppblog.com/ace/archive/2006/06/25/8985.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Sun, 25 Jun 2006 08:18:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/06/25/8985.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/8985.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/06/25/8985.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/8985.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/8985.html</trackback:ping><description><![CDATA[<h1>面向对象vs基于对象</h1>
		<div>
		</div>
		<div>看到了一种说法，很多所谓面向对象开发只不过是基于对象的开发<wbr>。反思自身，发觉一针见血。</wbr></div>
		<div>
		</div>
		<div>我们所谓的面向对象，实际上只不过封装了业务对象，分出了层次<wbr>，提供了接口。虽然在设计和实现的时候使用到了面向对象的封装<wbr>，但现在看来还算不上真正的面向对象，只能算是基于对象而已。</wbr></wbr></div>
		<div>
		</div>
		<div>面向对象的原则并没有符合。面向对象的优势也没有发挥，反而感觉一个小变化就牵扯到多层的变动，麻烦。就好比去年的项目，数据库采用ORACLE，实际本身对ORACL<wbr>E并不熟悉，只经过不到一周的学习，就上马了。结果只不过将ORACLE当成MSSQL使用<wbr>。ORACLE的强大不但没有体现（到现在也没有搞明白），反而失去了MSS<wbr>QL的好的经验。得不偿失。 </wbr></wbr></wbr></div>
		<div>
		</div>
		<div>不过，如何才算真正的面向对象呢？想了想一个好的面向对象的实践<wbr>，应该是达到最大限度的软件复用，并且可以快速适应不断变化的需求，而对已有的部分影响最小<wbr>。</wbr></wbr></div>
		<div>
		</div>
		<div>这不是一蹴而就的事情，如果想真正的用项目来实践的话，正确的步骤也许应该是：</div>
		<div>首先采用本身较熟悉的开发方法（基于对象或是面向过程）满足业务需求<wbr>。这一步很关键，只有有了这样一个原型才可以验证对需求的满足<wbr>程度。个人感觉直接面向对象会陷入设计过度，并且在前期耗费大量的<wbr>精力。更重要的是使用不熟悉的技术会带来风险，得不偿失。</wbr></wbr></wbr></div>
		<div>
		</div>
		<div>然后逐渐的将采用真正的面向对象的方法将现有的原型进行重构。目的是提高性能，灵活性<wbr>，扩展性，可复用性等等，这是一个长期的不断迭代的过程。可以参看经典的《重构-改善代码质量》。</wbr></div>
		<div>
		</div>
		<div>最后一步是架构的提炼。将系统中的可以外部复用的部分提炼出来形成<wbr>一个可以复用的框架架构。有了它，以后的开发相会事半功倍<wbr>。此步骤将会用到重构和设计模式。整个的过程除了第一步和面向对象无大关系外，后两步则完全的面向<wbr>对象的思想。</wbr></wbr></wbr></div>
		<div>
		</div>
		<div>在此之前总是希望先有一个设计良好的架构，一直这样不断的学习和进行实践。结果却不尽人意。经验说明这样做确实有些本末倒置。正如模式的使用一样<wbr>，在动机不明确的情况下盲目的套用模式是没有意义的。</wbr></div>
		<div>
		</div>
		<div>每一个开发人员的脑袋中有一些非常美妙的创意，这些创意没有实现的一个原因就是，太过关注细节。对于面向对象还是基于对象开发，对于实现需求，完成项目的初期阶段，真的无所谓。当需要考虑提高开发和维护效率的时候，面向对象就成了很不错的选择。</div><img src ="http://www.cppblog.com/ace/aggbug/8985.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-06-25 16:18 <a href="http://www.cppblog.com/ace/archive/2006/06/25/8985.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员的八荣八耻 -- 来源不详</title><link>http://www.cppblog.com/ace/archive/2006/06/08/8289.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Thu, 08 Jun 2006 03:03:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/06/08/8289.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/8289.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/06/08/8289.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/8289.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/8289.html</trackback:ping><description><![CDATA[<p>程序员的八荣八耻</p>
		<p>
				<br />以塌实编码为荣 以心浮气躁为耻</p>
		<p>以详细注释为荣 以注释残缺为耻</p>
		<p>以勤于测试为荣 以懒于测试为耻</p>
		<p>以简明文档为荣 以冗余文档为耻</p>
		<p>以注重团队为荣 以孤傲自大为耻</p>
		<p>以刻苦钻研为荣 以敷衍了事为耻</p>
		<p>以善于总结为荣 以不思进取为耻</p>
		<p>以质效并进为荣 以单取其一为耻</p><img src ="http://www.cppblog.com/ace/aggbug/8289.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-06-08 11:03 <a href="http://www.cppblog.com/ace/archive/2006/06/08/8289.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于用例的随笔 </title><link>http://www.cppblog.com/ace/archive/2006/06/06/8214.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Tue, 06 Jun 2006 07:56:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/06/06/8214.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/8214.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/06/06/8214.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/8214.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/8214.html</trackback:ping><description><![CDATA[<p>
				<a id="Editor_Edit_hlEntryLink" title="view: 关于用例的随笔 " href="/ace/archive/2006/06/06/8214.html" target="_blank">
						<font color="#002c99">http://www.cppblog.com/ace/archive/2006/06/06/8214.html</font>
				</a>
				<br />
				<br />近来因工作需要，我细阅读了一些与UML相关的书籍。</p>
		<p>这里，以流水帐的方式，作一起笔录。</p>
		<p>关于用例：</p>
		<p>1. 用例即是需求，但需求并不是用例。<br />   用例是描述讨论的系统(SuD)功能性需求的，所以可以说用例就是需求。但需求除了功能性需求，还有非功能性需求。所以，不能说需求就是用例。</p>
		<p>2. 用例不等于功能<br />   用例是描述系统功能的，但用例不是功能。功能是系统要达到或满足的目标，用例是用例的执行者(Actor)与系统交互的操作序列。两者是有差异的。</p>
		<p>3. 用例是文本而不是图形<br />   用例是描述执行者与系统交互的操作序列，要体现它的执行者在与系统交互产生的可观查的价值。图形仅仅是用例的概述，只画图是不够的。由于这一点，用例建模是撰写文档的过程，而不是画图的过程。</p>
		<p>4. 用例模型不仅仅是小人加随圆<br />   用例模型不仅是需求方面的工件(artifact)，它还包括补充说明(描述非功能需求的)，词汇表，愿景和业务规则。这些合在一起才是需求分析的产物。</p>
		<p>5. 用例技术无须对象技术，在通过用例发现，描述，管理需求的时候，用不到对象技术。但是，用例是面向对象的分析和设计的关键需求。</p>
		<p>6. 用例必须有一个主执行者 (Primary actor)<br />   主执行者确定了用例的名称。用例命令通常是以主执行者视角的主动语态的运宾结构的短语。因为只有这样的短语才能充分的描述出系统的价值。用例建模的核心就是要描述出系统的价值。</p>
		<p>7. 三种类型的执行者<br />   基本执行者 (Primary actor)  :这种用例通过与系统交互能达到目标<br />   支持执行者 (Supporting actor ) : 为讨论的系统（SuD)提供服务<br />   幕后执行者 (Offstage actor ) :除了上述两种，又对上述两种执行者与系统交互过程和结果感兴趣的人或物。</p><img src ="http://www.cppblog.com/ace/aggbug/8214.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-06-06 15:56 <a href="http://www.cppblog.com/ace/archive/2006/06/06/8214.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>介绍一些在C++用户组中常出现的缩略语</title><link>http://www.cppblog.com/ace/archive/2006/06/04/8144.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Sun, 04 Jun 2006 04:18:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/06/04/8144.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/8144.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/06/04/8144.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/8144.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/8144.html</trackback:ping><description><![CDATA[<p>Here's a partial list of acronyms in alphabetical order: 
</p>
		<ul>
				<li>AFAICS = As far as I can see 
</li>
				<li>BTW = By the way 
</li>
				<li>FWIW = For what it's worth 
</li>
				<li>FYI = For your information 
</li>
				<li>HAND = Have a nice day 
</li>
				<li>IMHO = In my humble opinion (egoless) 
</li>
				<li>IMAO = In my arrogant opinion (oodles of ego) 
</li>
				<li>IMNSHO = In my not-so humble opinion (a lot of ego) 
</li>
				<li>IMO = In my opinion (not much ego) 
</li>
				<li>KUTGW = Keep up the good work 
</li>
				<li>MYOB = Mind your own business 
</li>
				<li>OO = Object-oriented 
</li>
				<li>OTOH = On the other hand 
</li>
				<li>PEBCAC = Problem exists between chair and computer 
</li>
				<li>PEBCAK = Problem exists between chair and keyboard 
</li>
				<li>PMFJI = Pardon me for jumping in 
</li>
				<li>RTFM = Read the ___ manual 
</li>
				<li>SO = Significant other (as in, "My SO and I went for a walk...") 
</li>
				<li>SSO = Small String Optimization (where short strings don't use the heap) 
</li>
				<li>YHBT = You have been trolled 
</li>
				<li>YHL = You have lost </li>
		</ul><img src ="http://www.cppblog.com/ace/aggbug/8144.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-06-04 12:18 <a href="http://www.cppblog.com/ace/archive/2006/06/04/8144.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于用例模式的一句话评论</title><link>http://www.cppblog.com/ace/archive/2006/06/02/8070.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Fri, 02 Jun 2006 01:33:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/06/02/8070.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/8070.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/06/02/8070.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/8070.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/8070.html</trackback:ping><description><![CDATA[用例模式一组经过实践证明，能更精确地反应真时需求的模式集合，正确地使用它，能很好地把用例转化到工作的系统中并且更易于维护；使用这些模式，构架设计师、系统分析员、开发工程师以及管理人员，能像使用框杆一样把自己数十年艰苦努力获得的知识和经验用于更快地获得更好的结果。<br /><br /><br /><br />书籍推荐 "<strong><em>Use Cases Patterns and Blueprints</em></strong>"<br /><table cellspacing="0" cellpadding="0" width="469" border="0"><tbody><tr><td class="v2" colspan="3" height="18">By <a class="v1" target="_new">Gunnar Övergaard</a>, <a class="v1" target="_new">Karin Palmkvist</a></td></tr><tr><td class="v2" width="68" height="18"> </td><td class="v2" align="right" colspan="2"></td></tr><tr><th class="v2" scope="row" align="right" width="68" height="18">Publisher</th><td class="v2" colspan="2">: Addison Wesley Professional</td></tr><tr><th class="v2" scope="row" align="right" width="68" height="18">Pub Date</th><td class="v2" colspan="2">: November 12, 2004</td></tr><tr><th class="v2" scope="row" align="right" width="68" height="18">ISBN</th><td class="v2" colspan="2">: 0-13-145134-0</td></tr><tr><th class="v2" scope="row" align="right" width="68" height="18">Pages</th><td class="v2" colspan="2">: 464</td></tr><tr><th class="v2" scope="row" align="right" width="68" height="18"></th><td class="v2"></td></tr></tbody></table><img src ="http://www.cppblog.com/ace/aggbug/8070.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-06-02 09:33 <a href="http://www.cppblog.com/ace/archive/2006/06/02/8070.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>static_cast&lt;&gt;揭密 (转)</title><link>http://www.cppblog.com/ace/archive/2006/05/22/7510.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Mon, 22 May 2006 13:18:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/05/22/7510.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/7510.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/05/22/7510.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/7510.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/7510.html</trackback:ping><description><![CDATA[<p align="center">
				<b>static_cast&lt;&gt;揭密<br /></b>
				<br />
				<br />作者：Sam NG </p>
		<p align="center">译者：<a href="mailto:zhaotide@vckbase.com">小刀人</a></p>
		<p>
				<br />原文链接：<a href="http://www.codeproject.com/cpp/static_cast.asp">What static_cast&lt;&gt; is actually doing</a><br /><br />本文讨论static_cast&lt;&gt; 和 reinterpret_cast&lt;&gt;。 
</p>
		<p>
				<strong>介绍</strong>
				<br />大多程序员在学C++前都学过C，并且习惯于C风格（类型）转换。当写C++（程序）时，有时候我们在使用static_cast&lt;&gt;和reinterpret_cast&lt;&gt;时可能会有点模糊。在本文中，我将说明static_cast&lt;&gt;实际上做了什么，并且指出一些将会导致错误的情况。<br /><br /><strong>泛型（Generic Types）</strong><br /><br /></p>
		<pre>        float f = 12.3;<br />
        float* pf = &amp;f;
      <p>// static cast&lt;&gt;<br />
        // 成功编译, n = 12<br />
        int n = static_cast&lt;int&gt;(f);<br />
        // 错误,指向的类型是无关的（译注：即指针变量pf是float类型，现在要被转换为int类型）
        //int* pn = static_cast&lt;int*&gt;(pf);<br />
        //成功编译<br />
        void* pv = static_cast&lt;void*&gt;(pf);<br />
        //成功编译, 但是 *pn2是无意义的内存（rubbish）<br />
        int* pn2 = static_cast&lt;int*&gt;(pv);</p><p>// reinterpret_cast&lt;&gt;<br />
        //错误,编译器知道你应该调用static_cast&lt;&gt;<br />
        //int i = reinterpret_cast&lt;int&gt;(f);<br />
        //成功编译, 但是 *pn 实际上是无意义的内存,和 *pn2一样<br />
        int* pi = reinterpret_cast&lt;int*&gt;(pf);</p></pre>简而言之，static_cast&lt;&gt; 将尝试转换，举例来说，如float-到-integer，而reinterpret_cast&lt;&gt;简单改变编译器的意图重新考虑那个对象作为另一类型。<br /><br /><strong>指针类型（Pointer Types）</strong><br /><br />指针转换有点复杂，我们将在本文的剩余部分使用下面的类：<br /><pre>class CBaseX<br />
      {<br />
      public:<br />
      int x;<br />
      CBaseX() { x = 10; }<br />
      void foo() { printf("CBaseX::foo() x=%d\n", x); }<br />
      };
      <p>class CBaseY<br />
        {<br />
        public:<br />
        int y;<br />
        int* py;<br />
        CBaseY() { y = 20; py = &amp;y; }<br />
        void bar() { printf("CBaseY::bar() y=%d, *py=%d\n", y, *py); 
        }<br />
        };</p><p>class CDerived : public CBaseX, public CBaseY<br />
        {<br />
        public:<br />
        int z;<br />
        };</p></pre><strong>情况1：两个无关的类之间的转换 
<p></p></strong><br /><br /><pre>      // Convert between CBaseX* and CBaseY*<br />
      // CBaseX* 和 CBaseY*之间的转换<br />
      CBaseX* pX = new CBaseX();<br />
      // Error, types pointed to are unrelated<br />
      // 错误， 类型指向是无关的<br />
      // CBaseY* pY1 = static_cast&lt;CBaseY*&gt;(pX);<br />
      // Compile OK, but pY2 is not CBaseX<br />
      // 成功编译, 但是 pY2 不是CBaseX<br />
      CBaseY* pY2 = reinterpret_cast&lt;CBaseY*&gt;(pX);<br />
      // System crash!!<br />
      // 系统崩溃!!<br />
      // pY2-&gt;bar();</pre>正如我们在泛型例子中所认识到的，如果你尝试转换一个对象到另一个无关的类static_cast&lt;&gt;将失败，而reinterpret_cast&lt;&gt;就总是成功“欺骗”编译器：那个对象就是那个无关类。<br /><br /><strong>情况2：转换到相关的类</strong><br /><pre>      1. CDerived* pD = new CDerived();<br />
      2. printf("CDerived* pD = %x\n", (int)pD);<br />
      3. <br />
      4. // static_cast&lt;&gt; CDerived* -&gt; CBaseY* -&gt; CDerived*<br />
      //成功编译，隐式static_cast&lt;&gt;转换<br />
      5. CBaseY* pY1 = pD;<br />
      6. printf("CBaseY* pY1 = %x\n", (int)pY1);<br />
      // 成功编译, 现在 pD1 = pD<br />
      7. CDerived* pD1 = static_cast&lt;CDerived*&gt;(pY1);<br />
      8. printf("CDerived* pD1 = %x\n", (int)pD1);<br />
      9. <br />
      10. // reinterpret_cast<br />
      // 成功编译, 但是 pY2 不是 CBaseY*<br />
      11. CBaseY* pY2 = reinterpret_cast&lt;CBaseY*&gt;(pD);<br />
      12. printf("CBaseY* pY2 = %x\n", (int)pY2);<br />
      13. <br />
      14. // 无关的 static_cast&lt;&gt;<br />
      15. CBaseY* pY3 = new CBaseY();<br />
      16. printf("CBaseY* pY3 = %x\n", (int)pY3);<br />
      // 成功编译,尽管 pY3 只是一个 "新 CBaseY()"<br />
      17. CDerived* pD3 = static_cast&lt;CDerived*&gt;(pY3);<br />
      18. printf("CDerived* pD3 = %x\n", (int)pD3);<br /></pre><pre>      ---------------------- 输出 ---------------------------<br />
      CDerived* pD = 392fb8<br />
      CBaseY* pY1 = 392fbc<br />
      CDerived* pD1 = 392fb8<br />
      CBaseY* pY2 = 392fb8<br />
      CBaseY* pY3 = 390ff0<br />
      CDerived* pD3 = 390fec<br /><br /></pre><p>注意：在将CDerived*用隐式 static_cast&lt;&gt;转换到CBaseY*（第5行）时，结果是（指向）CDerived*（的指针向后） 偏移了4（个字节）（译注：4为int类型在内存中所占字节数）。为了知道static_cast&lt;&gt; 实际如何，我们不得不要来看一下CDerived的内存布局。</p><p align="left"><strong>CDerived的内存布局（Memory Layout）</strong><br /><br /><img height="224" src="http://www.vckbase.com/document/journal/vckbase48/images/static_cast_layout.gif" width="355" /><br /><br />如图所示，CDerived的内存布局包括两个对象，CBaseX 和 CBaseY，编译器也知道这一点。因此，当你将CDerived* 转换到 CBaseY*时，它给指针添加4个字节，同时当你将CBaseY*转换到CDerived*时，它给指针减去4。然而，甚至它即便不是一个CDerived你也可以这样做。<br />当然，这个问题只在如果你做了多继承时发生。在你将CDerived转换 到 CBaseX时static_cast&lt;&gt; 和 reinterpret_cast&lt;&gt;是没有区别的。<br /><br /><strong>情况3：void*之间的向前和向后转换</strong><br /><br />因为任何指针可以被转换到void*，而void*可以被向后转换到任何指针（对于static_cast&lt;&gt; 和 reinterpret_cast&lt;&gt;转换都可以这样做），如果没有小心处理的话错误可能发生。<br /><br /></p><pre>    CDerived* pD = new CDerived();<br />
        printf("CDerived* pD = %x\n", (int)pD);<p></p><p>    CBaseY* pY = pD; // 成功编译, pY = pD + 4<br />
        printf("CBaseY* pY = %x\n", (int)pY);</p><p>      void* pV1 = pY; //成功编译, pV1 = pY<br />
        printf("void* pV1 = %x\n", (int)pV1);</p><p>         // pD2 = pY, 但是我们预期 pD2 = pY - 4<br />
        CDerived* pD2 = static_cast&lt;CDerived*&gt;(pV1);<br />
        printf("CDerived* pD2 = %x\n", (int)pD2);<br />
        // 系统崩溃<br />
        // pD2-&gt;bar();<br /></p></pre><pre>        ---------------------- 输出 ---------------------------<br />
        CDerived* pD = 392fb8<br />
        CBaseY* pY = 392fbc<br />
        void* pV1 = 392fbc<br />
        CDerived* pD2 = 392fbc<br /></pre><p>一旦我们已经转换指针为void*，我们就不能轻易将其转换回原类。在上面的例子中，从一个void* 返回CDerived*的唯一方法是将其转换为CBaseY*然后再转换为CDerived*。 <br />但是如果我们不能确定它是CBaseY* 还是 CDerived*，这时我们不得不用dynamic_cast&lt;&gt; 或typeid[2]。<br /><br /><strong>注释：</strong><br />1. dynamic_cast&lt;&gt;，从另一方面来说，可以防止一个泛型CBaseY* 被转换到CDerived*。<br />2. dynamic_cast&lt;&gt;需要类成为多态，即包括“虚”函数，并因此而不能成为void*。<br /><strong>参考：</strong><br />1. [MSDN] C++ Language Reference -- Casting <br />2. Nishant Sivakumar, Casting Basics - Use C++ casts in your VC++.NET programs <br />3. Juan Soulie, C++ Language Tutorial: Type Casting<br /></p><img src ="http://www.cppblog.com/ace/aggbug/7510.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-05-22 21:18 <a href="http://www.cppblog.com/ace/archive/2006/05/22/7510.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C/C++ 内存管理 Heap  vs Stack</title><link>http://www.cppblog.com/ace/archive/2006/05/17/7313.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Wed, 17 May 2006 09:09:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/05/17/7313.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/7313.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/05/17/7313.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/7313.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/7313.html</trackback:ping><description><![CDATA[<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />转注:<br /><span style="COLOR: #000000">    今天有网友问到这个问题,于是在网上搜索了一下,转贴这此.<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />相似的太多了,出处不详.在此感谢原作者精彩讲解.</span></div>
		<br />
		<br />一、预备知识—程序的内存分配 <br />一个由c/C++编译的程序占用的内存分为以下几个部分 <br />1、栈区（stack）— 由编译器自动分配释放 ，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的栈。 <br />2、堆区（heap） — 一般由程序员分配释放， 若程序员不释放，程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事，分配方式倒是类似于链表，呵呵。 <br />3、全局区（静态区）（static）—，全局变量和静态变量的存储是放在一块的，初始化的全局变量和静态变量在一块区域， 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 <br />4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放 <br />5、程序代码区—存放函数体的二进制代码。 <br /><br />二、例子程序 <br />这是一个前辈写的，非常详细 <br /><br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #008000">//</span><span style="COLOR: #008000">main.cpp </span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> a </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; 全局初始化区 <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p1; 全局未初始化区 <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />main() <br /><img id="Codehighlighter1_58_337_Open_Image" onclick="this.style.display='none'; Codehighlighter1_58_337_Open_Text.style.display='none'; Codehighlighter1_58_337_Closed_Image.style.display='inline'; Codehighlighter1_58_337_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_58_337_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_58_337_Closed_Text.style.display='none'; Codehighlighter1_58_337_Open_Image.style.display='inline'; Codehighlighter1_58_337_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_58_337_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_58_337_Open_Text"><span style="COLOR: #000000">{ <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> b;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 栈 </span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> s[] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">abc</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">栈 </span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p2; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">栈 </span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p3 </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">123456</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">; </span><span style="COLOR: #000000">123456</span><span style="COLOR: #000000">\</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;//在常量区，p3在栈上。 </span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> c </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">； </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">全局（静态）初始化区 </span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">p1 </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)malloc(</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">); <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />p2 </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)malloc(</span><span style="COLOR: #000000">20</span><span style="COLOR: #000000">); <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">分配得来得10和20字节的区域就在堆区。 </span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">strcpy(p1, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">123456</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">123456\0放在常量区，编译器可能会将它与p3所指向的"123456"优化成一个地方。 </span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" /></span><span style="COLOR: #000000">}</span></span><span style="COLOR: #000000">  <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div><br />三、堆和栈的理论知识 <br />3.1申请方式 <br />stack: <br />由系统自动分配。 例如，声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间 <br />heap: <br />需要程序员自己申请，并指明大小，在c中malloc函数 <br />如p1 = (char *)malloc(10); <br />在C++中用new运算符 <br />如p2 = (char *)malloc(10); <br />但是注意p1、p2本身是在栈中的。 <br />3.2 申请后系统的响应 <br />栈：只要栈的剩余空间大于所申请空间，系统将为程序提供内存，否则将报异常提示栈溢出。 <br />堆：首先应该知道操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时， <br />会遍历该链表，寻找第一个空间大于所申请空间的堆结点，然后将该结点从空闲结点链表中删除，并将该结点的空间分配给程序，另外，对于大多数系统，会在这块内存空间中的首地址处记录本次分配的大小，这样，代码中的delete语句才能正确的释放本内存空间。另外，由于找到的堆结点的大小不一定正好等于申请的大小，系统会自动的将多余的那部分重新放入空闲链表中。 <br />3.3申请大小的限制 <br />栈：在Windows下,栈是向低地址扩展的数据结构，是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的，在 WINDOWS下，栈的大小是2M（也有的说是1M，总之是一个编译时就确定的常数），如果申请的空间超过栈的剩余空间时，将提示overflow。因此，能从栈获得的空间较小。 <br />堆：堆是向高地址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的，自然是不连续的，而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见，堆获得的空间比较灵活，也比较大。 <br />3.4申请效率的比较： <br />栈由系统自动分配，速度较快。但程序员是无法控制的。 <br />堆是由new分配的内存，一般速度比较慢，而且容易产生内存碎片,不过用起来最方便. <br />另外，在WINDOWS下，最好的方式是用VirtualAlloc分配内存，他不是在堆，也不是在栈是直接在进程的地址空间中保留一快内存，虽然用起来最不方便。但是速度快，也最灵活 <br />3.5堆和栈中的存储内容 <br />栈： 在函数调用时，第一个进栈的是主函数中后的下一条指令（函数调用语句的下一条可执行语句）的地址，然后是函数的各个参数，在大多数的C编译器中，参数是由右往左入栈的，然后是函数中的局部变量。注意静态变量是不入栈的。 <br />当本次函数调用结束后，局部变量先出栈，然后是参数，最后栈顶指针指向最开始存的地址，也就是主函数中的下一条指令，程序由该点继续运行。 <br />堆：一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。 <br />3.6存取效率的比较 <br /><br />char s1[] = "aaaaaaaaaaaaaaa"; <br />char *s2 = "bbbbbbbbbbbbbbbbb"; <br />aaaaaaaaaaa是在运行时刻赋值的； <br />而bbbbbbbbbbb是在编译时就确定的； <br />但是，在以后的存取中，在栈上的数组比指针所指向的字符串(例如堆)快。 <br />比如： <br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">; <br /></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> main() <br />{ <br /></span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> a </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">; <br /></span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> c[] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">1234567890</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">; <br /></span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">1234567890</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">; <br />a </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> c[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]; <br />a </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> p[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]; <br /></span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">; <br />} </span></div><br />对应的汇编代码 <br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">10: a = c[1]; <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />0040106A 88 4D FC mov byte ptr [ebp-4],cl <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />11: a = p[1]; <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />00401070 8A 42 01 mov al,byte ptr [edx+1] <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />00401073 88 45 FC mov byte ptr [ebp-4],al </span></div><br />第一种在读取时直接就把字符串中的元素读到寄存器cl中，而第二种则要先把指针值读到edx中，在根据edx读取字符，显然慢了。 <br /><br /><br />3.7小结： <br />堆和栈的区别可以用如下的比喻来看出： <br />使用栈就象我们去饭馆里吃饭，只管点菜（发出申请）、付钱、和吃（使用），吃饱了就走，不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作，他的好处是快捷，但是自由度小。 <br />使用堆就象是自己动手做喜欢吃的菜肴，比较麻烦，但是比较符合自己的口味，而且自由度大。 <br /><br />堆和栈的区别主要分： <br />操作系统方面的堆和栈，如上面说的那些，不多说了。 <br />还有就是数据结构方面的堆和栈，这些都是不同的概念。这里的堆实际上指的就是（满足堆性质的）优先队列的一种数据结构，第1个元素有最高的优先权；栈实际上就是满足先进后出的性质的数学或数据结构。 <br />虽然堆栈，堆栈的说法是连起来叫，但是他们还是有很大区别的，连着叫只是由于历史的原因。<br /><br /><img src ="http://www.cppblog.com/ace/aggbug/7313.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-05-17 17:09 <a href="http://www.cppblog.com/ace/archive/2006/05/17/7313.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>避免依赖的消息处理方式 (试译)</title><link>http://www.cppblog.com/ace/archive/2006/05/04/6629.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Thu, 04 May 2006 12:52:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/05/04/6629.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6629.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/05/04/6629.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6629.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6629.html</trackback:ping><description><![CDATA[<p>避免依赖的消息处理方式<br /><br />Anthony Williams<br />url: <a href="http://www.ddj.com/dept/cpp/184429055">http://www.ddj.com/dept/cpp/184429055</a><br />译者: <a title="Focus on ACE" href="http://www.cppblog.com/ace" >Stone Jiang</a><br />译者说明：本人还在学习英文的过程中，有些句子很难译，这里给出原文的链接，欢迎就其中译得不准确的地方与我交换意见。<br /></p>
		<p>在您维护安全类型和避免集成电路般函数时,你可以使用C++的强大的力量进行消息传递。</p>
		<p>Anthony是Just Software Solution有限公司的一位软件开发者和执行管理者。可以通过<a href="mailto:anthony@justsoftwaresolutions.co.uk">anthony@justsoftwaresolutions.co.uk</a>与之联系。</p>
		<p>使用通用的消息传递方式传递数据在C++程序中很普遍。这种技术经常用于在线程间以及从/到GUI组件间传递数据。但是消息传递仍然很难实现得良好，这是因为在常见的消息传递方式中，暴露出了过多的藕合、缺少类型安全和集成电路般的消息处理函数。</p>
		<p>在本文中，我提出了一种技术，这种技术利用C++的强大力量来避免上述缺陷——在消息传递中避免不适当的藕合，维护类型安全，以及消除集成电路般的消息处理函。( The only translation units that need to known the details of a message are those containning the source and handler functions for that specific message type.) 需要转换的单元，即需要知道的消息详细内容是包含了特定消息的类型的源代码和处理函数。</p>
		<h2>传统技术</h2>
		<p>
				<br />大概应用得最为广泛的消息传递技术是使用一个带有特殊成员来表示消息类型的结构体，该消息类型是消息的标识。这种方式被广泛应用归咎于使用了基于C的API，比如X11和Microsoft Windows。在这种方法中，消息结构体中要么有一个通用的字体用于区别不同消息的意义，这个字段可被所有消息重用，或者它是更大结构的第一个成员，它的类型由类型代码来确定。Windows API使用前面的技术，而X11使用后面的方法。无论用哪种方式，处理消息的代码都须检查类型编码，用以决定怎么处理该消息。</p>
		<p>这些技术的问题是:缺乏类型安全，集成电路般的处理函数，需要管理类型编码来确保消息唯一性的适当层次。特别的，缺乏类型安全意味着使用之前，使用代码必须把消息数据转换成适当的类型。这一步是极易出错的，尤其在当复制和粘贴代码时(这种非常的手段常发生在为处理相似消息编写代码的时候)，编译器不会在这种错误给出任何警告。</p>
		<p>缺乏类型安全还有一个额外的问题——即它不可能简单有效的通过消息系统传递资源或变长的数据， 这是因为消息的发送方总是不能知道何时（或是否）该消息已被处理过了。</p>
		<p>在这部分，集成电路般的消息处理函数是必须用于确定消息类型的产物，通过已接收的消息来消息类型，然后得到如何处理它的方式。这种处理函数往往实现为一个很大的switch语句或是一串if eles if。一些框架，如MFC，提供一些宏来减弱这种问题的影响，它这不能完全消除这个问题。</p>
		<p>最后的问题是管理类型代码。它必须要求接收消息代码清楚地知道是哪一个消息，以便于正确的处理它。所以，类型代码需要在处理它的相关代码中确保唯一性。比如，在Windows API中，指定范围的消息类型在不同的应用程序中代表不同的意义，并且，在同一个应就用程序中，其它范围的消息类型在不同窗口或GUI组件中代表不同的意义。 通常,需要所有类型代码的列表，该列表要求在给定的范围中保持唯一，以便于检查它们的唯一性。列表常常是以头文件的形式给出，头文件中定义了类型代码，包含在需要知道消息类型的所有地方。这种方式容易导致应用程序不同部分之间的藕合,而这些部分之间却没有任何关系。由于这种过度的藕，简单的变更导致过多的重新编译。</p>
		<p>
				<strong>面向对象技术<br /></strong>
				<br />对象技术的一个常见特征是所有相关消息类派生自一个通用的基类。该特征用编译器能认识的真实类型代替了显式的类型代码。不仅如此，它还有了一个重要的，超越C风格技术的优点——类型安全。它提供的通用基类的析构函数是虚函数，所以派生的消息类能自由地管理资源，如变长的数据，这些数据可以在析构函数中释放。仅有的需求是接受消息的代码能正确地销毁消息对象，无论它们是否被处理。</p>
		<p>管理类型代码现在被替换为管理类。这是一个更加简单的任务，由于可能的消息名字的范围是没有限制的，可能存在名字冲突，但这一点可以通过名字空间来解决。</p>
		<h2>
				<font size="3">保持简单</font>
		</h2>
		<p>最简单的OOP技术就是用dynamic_cast检查实际的消息类型代替检查消息编码。然而，这依然面临着集成电路般地消息处理方式——现在通过包括dynamic_cast的比较链也优于通过类型编码字段比较链。如列表1:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> handleMessage(Message</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> message)<br /><img id="Codehighlighter1_37_239_Open_Image" onclick="this.style.display='none'; Codehighlighter1_37_239_Open_Text.style.display='none'; Codehighlighter1_37_239_Closed_Image.style.display='inline'; Codehighlighter1_37_239_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_37_239_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_37_239_Closed_Text.style.display='none'; Codehighlighter1_37_239_Open_Image.style.display='inline'; Codehighlighter1_37_239_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_37_239_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_37_239_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">if</span>
						<span style="COLOR: #000000">(Message1</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> m</span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">dynamic_cast</span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000">Message1</span>
						<span style="COLOR: #000000">*&gt;</span>
						<span style="COLOR: #000000">(message))<br /><img id="Codehighlighter1_96_129_Open_Image" onclick="this.style.display='none'; Codehighlighter1_96_129_Open_Text.style.display='none'; Codehighlighter1_96_129_Closed_Image.style.display='inline'; Codehighlighter1_96_129_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_96_129_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_96_129_Closed_Text.style.display='none'; Codehighlighter1_96_129_Open_Image.style.display='inline'; Codehighlighter1_96_129_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_96_129_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_96_129_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        handleMessage1(m);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">else</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">if</span>
						<span style="COLOR: #000000">(Message2</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> m</span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">dynamic_cast</span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000">Message2</span>
						<span style="COLOR: #000000">*&gt;</span>
						<span style="COLOR: #000000">(message))<br /><img id="Codehighlighter1_193_226_Open_Image" onclick="this.style.display='none'; Codehighlighter1_193_226_Open_Text.style.display='none'; Codehighlighter1_193_226_Closed_Image.style.display='inline'; Codehighlighter1_193_226_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_193_226_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_193_226_Closed_Text.style.display='none'; Codehighlighter1_193_226_Open_Image.style.display='inline'; Codehighlighter1_193_226_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_193_226_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_193_226_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        handleMessage2(m);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> <img src="http://www.cppblog.com/images/dot.gif" /></span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />
						</span>
						<span style="COLOR: #000000">}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
		</div>
		<p>[列表1]</p>
		<p>一般而言，由于仅仅是消息的源代码和接受消息的源代码需求知道相关的消息，所以依赖得到降低。然后，集成电路般地处理函数现在需要知道消息的有关细节，所以dynamic_cast需要消息的完整定义——如果分派给另外的函数处理实际的消息，C风格技术的处理函数不需求知道消息的细节。</p>
		<h2>双重分派</h2>
		<p>(Direct testing of a class's type using dynamic_cast is generally indicative of a design problem;)类的类型用dynamic_cast的直测试一般可表示为设计问题;然而，简单地把虚函数放在消息类中起不到任何作用——它将把消息处理与消息缠绕在一起，这个消息使在第一个地方发送消息的目的失败。</p>
		<p>双重分派的关键点是，在消息类中的虚函数带有一个作为参数的处理器，然后在处理器上把自已作为参数传递传递给另一个函数并完成调用。因为这里的第二次到处理器的回调已经在实际的派生类中完成，所以真实的消息类型已经知道，在处理器上能调用适当的函数，无论这个函数是通过重载的方式实现还是另外独立命名的函数来实现(列表2)。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Message<br />{<br /></span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000">:<br />    </span>
				<span style="COLOR: #0000ff">virtual</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> dispatch(MessageHandler</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> handler)</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">;<br />};<br /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Message1:<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> Message<br />{<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> dispatch(MessageHandler</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> handler)<br />    {<br />        handler</span>
				<span style="COLOR: #000000">-&gt;</span>
				<span style="COLOR: #000000">process(</span>
				<span style="COLOR: #0000ff">this</span>
				<span style="COLOR: #000000">);<br />    }<br />};<br /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Message2:<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> Message<br />{<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> dispatch(MessageHandler</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> handler)<br />    {<br />        handler</span>
				<span style="COLOR: #000000">-&gt;</span>
				<span style="COLOR: #000000">process(</span>
				<span style="COLOR: #0000ff">this</span>
				<span style="COLOR: #000000">);<br />    }<br />};<br /></span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> other message classes</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> MessageHandler<br />{<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(Message1</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">);<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(Message2</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">);<br />    </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> overloads of process for other messages</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">};</span>
		</div>
		<p>[列表2]</p>
		<p>依赖于重载的方式来区别不同的消息有利于大多数平衡——现在在每个消息类中虚函数的实现方式是相同的，如果需要，可以通过宏来一致地包装，或通过从一个消息到另一个消息中直接复制，不会有出错的机会。</p>
		<p>双重分派存在一个缺点——高度藕合。由于通过重载方式在处理器类中的选择处理函数，在消息类中虚函数的实现需要知道处理器类的定义的全部，因此必须注意到在系统中每个其它的类的名字。不光这些，如果要支持不同的处理器类，处理函数必须在通用的处理器的基类中声明为虚函数，所以每个处理器类必须在系统中注意到所有的消息类型(列表3)。增加或删除一个消息类型会引起应用程序大部分代码重新编译。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> MessageHandler<br /><img id="Codehighlighter1_21_226_Open_Image" onclick="this.style.display='none'; Codehighlighter1_21_226_Open_Text.style.display='none'; Codehighlighter1_21_226_Closed_Image.style.display='inline'; Codehighlighter1_21_226_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_21_226_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_21_226_Closed_Text.style.display='none'; Codehighlighter1_21_226_Open_Image.style.display='inline'; Codehighlighter1_21_226_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_21_226_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_21_226_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">virtual</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message1</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">)</span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">virtual</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message2</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">)</span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">virtual</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message3</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">)</span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">virtual</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message4</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">)</span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> overloads of process for other messages</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />
						</span>
						<span style="COLOR: #000000">}</span>
				</span>
				<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> SpecificMessageHandler:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> MessageHandler<br /><img id="Codehighlighter1_285_450_Open_Image" onclick="this.style.display='none'; Codehighlighter1_285_450_Open_Text.style.display='none'; Codehighlighter1_285_450_Closed_Image.style.display='inline'; Codehighlighter1_285_450_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_285_450_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_285_450_Closed_Text.style.display='none'; Codehighlighter1_285_450_Open_Image.style.display='inline'; Codehighlighter1_285_450_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_285_450_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_285_450_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message1</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message2</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message3</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message4</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> overloads of process for other messages</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />
						</span>
						<span style="COLOR: #000000">}</span>
				</span>
				<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> OtherSpecificMessageHandler:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> MessageHandler<br /><img id="Codehighlighter1_514_679_Open_Image" onclick="this.style.display='none'; Codehighlighter1_514_679_Open_Text.style.display='none'; Codehighlighter1_514_679_Closed_Image.style.display='inline'; Codehighlighter1_514_679_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_514_679_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_514_679_Closed_Text.style.display='none'; Codehighlighter1_514_679_Open_Image.style.display='inline'; Codehighlighter1_514_679_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_514_679_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_514_679_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message1</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message2</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message3</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> process(Message4</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> overloads of process for other messages</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />
						</span>
						<span style="COLOR: #000000">}</span>
				</span>
				<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
		</div>
		<p>[列表3]<br /><br /><strong>动态双重分派<br /></strong><br />（It was against this backdrop that I developed the technique I call "Dynamic Double Dispatch."）我开发了一种技术，我称其为“动态双重分派”，这种技术用于解决上述问题。尽管有基本的双重分派技术，但选择的消息处理函数使用的是在编译阶段确定的重载技术(尽管发现在正确的消息处理器类中的实现是使用虚函数机制),而动态双重分派是在运行时检查在处理器上适当的处理函数的。结论是动态双重分派消除了双重分派的依赖问题。消息类型不在需要注意到其它的消息类型，并且处理器类仅需要注意到它的它要处理的消息。</p>
		<p>动态检查的关键点是：每一个消息类型有一个独立的基类——处理器类从适当的，设计为处理消息的基类派生。然后在每个消息类中的分派函数能用dynamic_cast来检查从正派基类派生的处理器类，因而实现了正确的处理函数。(列表4)</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> MessageHandlerBase<br />{};<br /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Message1HandlerBase:<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">virtual</span>
				<span style="COLOR: #000000"> MessageHandlerBase<br />{<br />    </span>
				<span style="COLOR: #0000ff">virtual</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(Message1</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">)</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">;<br />};<br /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Message1<br />{<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> dispatch(MessageHandlerBase</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> handler)<br />    {<br />        dynamic_cast</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">Message1HandlerBase</span>
				<span style="COLOR: #000000">&amp;&gt;</span>
				<span style="COLOR: #000000">(</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">handler).process(</span>
				<span style="COLOR: #0000ff">this</span>
				<span style="COLOR: #000000">);<br />    }<br />};<br /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Message2HandlerBase:<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">virtual</span>
				<span style="COLOR: #000000"> MessageHandlerBase<br />{<br />    </span>
				<span style="COLOR: #0000ff">virtual</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(Message2</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">)</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">;<br />};<br /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Message2:<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> MessageBase<br />{<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> dispatch(MessageHandlerBase</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> handler)<br />    {<br />        dynamic_cast</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">Message2HandlerBase</span>
				<span style="COLOR: #000000">&amp;&gt;</span>
				<span style="COLOR: #000000">(</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">handler).process(</span>
				<span style="COLOR: #0000ff">this</span>
				<span style="COLOR: #000000">);<br />    }<br />};<br /></span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> <img src="http://www.cppblog.com/images/dot.gif" /></span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> SpecificMessageHandler:<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> Message1HandlerBase,<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> Message2HandlerBase<br />{<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(Message1</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">);<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(Message2</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">);<br />};<br /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> OtherSpecificMessageHandler:<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> Message3HandlerBase,<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> Message4HandlerBase<br />{<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(Message3</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">);<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(Message4</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">);<br />};<br /></span>
		</div>
		<p>[列表4]</p>
		<p>(Of course, having a completely separate handler base class for each message type would add excessive complication, as the dispatch function for each message type would now be specific to that message type, and the base classes would have to be written separately, despite being fundamentally the same, except for the message type they referenced.) <br />诚然，为每个消息类型分别编写的处理器基类将增加过多的复杂性，同样地，每个消息类型各自的分派函数现在需要特别指定，基类也需求分别编写,然后除了它们引用的消息类型外基础是相同的。消除这种重复的关键是使基类成为模板，用消息类型作为模板参数——分派函数引用到模板的实现好于指定类型；请看列表5。</p>
		<p> </p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #000000">template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">typename MessageType</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> MessageHandler:<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">virtual</span>
				<span style="COLOR: #000000"> MessageHandlerBase<br />{<br />    </span>
				<span style="COLOR: #0000ff">virtual</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(MessageType</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">)</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">;<br />};<br /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Message1<br />{<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> dispatch(MessageHandlerBase</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> handler)<br />    {<br />        dynamic_cast</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">MessageHandler</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">Message1</span>
				<span style="COLOR: #000000">&gt;&amp;&gt;</span>
				<span style="COLOR: #000000">(</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">handler).process(</span>
				<span style="COLOR: #0000ff">this</span>
				<span style="COLOR: #000000">);<br />    }<br />};<br /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> SpecificMessageHandler:<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> MessageHandler</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">Message1</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">,<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> MessageHandler</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">Message2</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />{<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(Message1</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">);<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> process(Message2</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">);<br />};<br /></span>
		</div>
		<p>[列表5]<br />出于简化原因，在消息类中的分派函数几乎相同，但也不是完全相同——它们必须明确的指定属于它们的指定消息类，以便于转换为适当的处理器基类。像软件中许多事情一样，这个问题可以增加一个额外的层来解决——分派函数可以委托给单个模板函数，这个模板函数使用模板参数类型来确定消息类型和把处理器转换到适当的类型上。(列表6)</p>
		<p> </p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Message<br />{<br /></span>
				<span style="COLOR: #0000ff">protected</span>
				<span style="COLOR: #000000">:<br />    template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">typename MessageType</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> dynamicDispatch(MessageHandlerBase</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> handler,MessageType</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> self)<br />    {<br />        dynamic_cast</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">MessageHandler</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">MessageType</span>
				<span style="COLOR: #000000">&gt;&amp;&gt;</span>
				<span style="COLOR: #000000">(</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">handler).process(self);<br />    }<br />};<br /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Message1:<br />    </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> MessageBase<br />{<br />    </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> dispatch(MessageHandlerBase</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> handler)<br />    {<br />        dynamicDispatch(handler,</span>
				<span style="COLOR: #0000ff">this</span>
				<span style="COLOR: #000000">);<br />    }<br />};<br /></span>
		</div>
		<p>[列表6]</p>
		<p>通过进一步抽象在消息对象中分派函数的不同之处,我们把工作集中到一个地方——模板函数的定义；它提供了为修改行为的单一点。在消息类中剩下的分派函数都是相同的，这足以把它们简化到隐藏细节的宏中或在消息类之间中逐字复制。</p>
		<p>
				<br />
				<br />
				<strong>未处理的消息</strong>
		</p>
		<p>迄今为止，我们展示的 dynamicDispach模板函数的代码假定处理的类是从适当的SpecificMessageHandler是派生的；如是不是这样， dynamic_cast将抛出std::bad_cast异常。有时这就足够了，但是有的时候，有更适当的行为——也许更好的做法是抛弃消息，这不能被接受消息的代理处理或调用catch-all处理器。举例来说，dynamicDispatch 函数能被调整，用基于指针的转换代替基于引用的转换，所以结果值可以与NULL进行测试。</p>
		<p>
				<br />
				<strong>缺点(Trade-Off)在哪里？</strong>
				<br />有如此多的优点，一定存在它的缺点，那它的缺点在哪里呢？在这里，有两个缺点。第一个是：额外的动态转换，两个虚函数调用会影响性能。如果性能上是一个问题，这就是一个疑问，但是，在很多情况下，花销在这里的额外的时间是不值得关注的。可以使用相应的工具来签定到底哪里才是真正的性能瓶颈所在。</p>
		<p>第二个缺点是:需要为每个消息处理从指定的基类派生消息处理器。因为处理新的消息类型需要修改两个地方——适当的基类列表入口和处理函数，所以这可能成为错误的来源，遗失处理函数容易被发现，因为这是全局点，但是遗失基类在代码运行时只产生不易查觉的缺陷。因为没有处理函数的时候仅仅是不调用它。这些错误在单元测试的时候是很容易被抓出来的，所以所实话，这些不便之处都成不了大问题。</p>
		<p> </p><img src ="http://www.cppblog.com/ace/aggbug/6629.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-05-04 20:52 <a href="http://www.cppblog.com/ace/archive/2006/05/04/6629.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket编程：SO_REUSEADDR例解 (转)</title><link>http://www.cppblog.com/ace/archive/2006/04/29/6446.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Sat, 29 Apr 2006 01:40:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/29/6446.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6446.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/29/6446.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6446.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6446.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: socket编程：SO_REUSEADDR例解                                             kevintz 2000-6-19     网友vmstat多次提出了这个问题：SO_REUSEADDR有什么用处和怎么使用。而且很多网友在编写网络程序时也会遇到这个问题。所以特意写了这么一篇文章，希望能够解答一些人的疑难。     其实这个问题在Richard ...&nbsp;&nbsp;<a href='http://www.cppblog.com/ace/archive/2006/04/29/6446.html'>阅读全文</a><img src ="http://www.cppblog.com/ace/aggbug/6446.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-04-29 09:40 <a href="http://www.cppblog.com/ace/archive/2006/04/29/6446.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>谈谈C++继承中的重载，覆盖和隐藏 (转)</title><link>http://www.cppblog.com/ace/archive/2006/04/25/6243.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Tue, 25 Apr 2006 05:29:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/25/6243.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6243.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/25/6243.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6243.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6243.html</trackback:ping><description><![CDATA[<script><![CDATA[unction StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}]]&gt;</script>
 
<div class="post"><div class="postTitle"><a href="http://blog.csdn.net/Kendiv/archive/2006/04/25/675940.aspx"> 谈谈C++继承中的重载，覆盖和隐藏</a><script language="javascript"><![CDATA[ocument.title="谈谈C++继承中的重载，覆盖和隐藏 - "+document.title]]&gt;</script></div><div class="postText"><div class="postTitle"> </div><div class="postText"><p>      写正题之前，先给出几个关键字的中英文对照，重载(overload)，覆盖(override),隐藏(hide)。在早期的C++书籍中，可能翻译的人不熟悉专业用语（也不能怪他们，他们不是搞计算机编程的，他们是英语专业的），常常把重载(overload)和覆盖(override)搞错！</p><p>　　我们先来看一些代码及其编译结果。</p><p>　　实例一：<br />　　<br />　　#include "stdafx.h"<br />　　#include &lt;iostream.h&gt;</p><p>　　class CB<br />　　{<br />　　public:<br /> 　　　　<font color="#ff0000">void f(int)<br /></font> 　　　　{<br /> 　　　　　　 cout &lt;&lt; "CB::f(int)" &lt;&lt; endl;<br />　　　　 }</p><p>　　};</p><p><br />　　class CD : public CB<br />　　{<br />　　public:<br />　　　　 <font color="#ff0000">void f(int,int)<br /></font> 　　　　{<br />  　　　　　　cout &lt;&lt; "CD::f(int,int)" &lt;&lt; endl;<br /> 　　　　}</p><p> 　　　　void test()<br /> 　　　　{<br />  　　　　　f(1);<br /> 　　　　}<br />　　};</p><p>　int main(int argc, char* argv[])<br />　{<br />　　　 return 0;<br />　}<br />编译了一下<br />error C2660: 'f' : function does not take 1 parameters</p><p><br />结论：在类CD这个域中，没有f(int)这样的函数，基类中的void f(int)被<font color="#ff0000">隐藏</font></p><p>　　如果把派生CD中成员函数void f(int,int)的声明改成和基类中一样，即f(int)，基类中的void f(int)还是一样被覆盖，此时编译不会出错，在函数中test调用的是CD中的f(int)　</p><p>　　所以，在<font color="#ff0000">基类中</font>的某些函数，如果<font color="#ff0000">没有</font><font color="#ff0000">virtral</font>关键字，函数名是<font color="#ff0000">f(</font>参数是什么我们不管)，那么如果在派生类CD中<font color="#ff0000">也声明了某个f</font>成员函数，那么在类CD域中，<font color="#ff0000">基类中所有的那些f都被隐藏。</font><br />　　如果你比较心急，想知道什么是隐藏，看文章最后的简单说明，不过我建议你还是一步一步看下去。</p><p>　　我们刚才说的是没有virtual的情况，如果有virtual的情况呢？？<br />　　实例二：</p><p>#include "stdafx.h"<br />#include &lt;iostream.h&gt;</p><p>class CB<br />{<br />public:<br /> 　　<font color="#ff0000">virtual void f(int)<br /></font> 　　{<br />  　　　　cout &lt;&lt; "CB::f(int)" &lt;&lt; endl;<br /> 　　}</p><p>};</p><p><br />class CD : public CB<br />{<br />public:<br />　　 <font color="#ff0000">void f(int)<br /></font> 　　{<br />  　　　　cout &lt;&lt; "CD::f(int)" &lt;&lt; endl;<br />　　 }</p><p>};</p><p>int main(int argc, char* argv[])<br />{<br /> 　return 0;<br />}</p><p>　　这么写当然是没问题了，在这里我不多费口舌了，这是很简单的，多态，虚函数，然后什么指向基类的指针指向派生类对象阿，通过引用调用虚函数阿什么的，属性多的很咯，什么？？你不明白？？随便找本C++的书，对会讲多态和虚函数机制的哦！！<br />　　这种情况我们叫<font color="#ff0000">覆盖(override)！</font>覆盖指的是派生类的虚拟函数覆盖了基类的同名且参数相同的函数！<br />　　在这里，我要强调的是，这种覆盖，要满足两个条件<br />　<font size="4">(a)</font><font color="#ff0000">有virtual关键字</font>，在基类中函数声明的时候加上就可以了<br />　<font size="4">(b)</font>基类CB中的函数和派生类CD中的函数<font color="#ff0000">要一模一样</font>，什么叫一模一样，<font color="#ff0000">函数名，参数，返回类型三个条件</font>。<br />　　有人可能会对(b)中的说法质疑，说返回类型也要一样？？<br />　　是，覆盖的话必须一样，我试了试，如果在基类中,把f的声明改成virtual int f(int)，编译出错了<br />　　error C2555: 'CD::f' : overriding virtual function differs from 'CB::f' only by return type or calling convention<br />　　所以，覆盖的话，必须要满足上述的(a)(b)条件</p><p>　　那么如果基类CB中的函数f有关键字virtual　，但是参数和派生类CD中的函数f参数不一样呢，<br />实例三:<br />  #include "stdafx.h"<br />#include &lt;iostream.h&gt;</p><p>class CB<br />{<br />　public:<br /> 　　 virtual  void f(int)<br />　　 {<br /> 　　　　 cout &lt;&lt; "CB::f(int)" &lt;&lt; endl;<br />　　 }</p><p>}<br />;</p><p><br />class CD : public CB<br />{<br />public:<br /> 　　 void f(int，int)<br /> 　　{<br /> 　　　 cout &lt;&lt; "CD::f(int，int)" &lt;&lt; endl;<br /> 　　}</p><p> 　　void test()<br /> 　　{<br /> 　　　　 f(1);<br /> 　　}<br />}<br />;</p><p>int main(int argc, char* argv[])<br />{<br /> return 0;<br />}</p><p>编译出错了，<br /> error C2660: 'f' : function does not take 1 parameters<br />　　咦？？好面熟的错？？对，和实例一中的情况一样哦，结论也是基类中的函数被隐藏了。</p><p>　　通过上面三个例子，得出一个简单的结论<br />如果<font color="#ff0000">基类中的函数和派生类中的两个名字一样的函数f</font><br />满足下面的两个条件<br /><font size="4">(a)在基类中函数声明的时候有virtual关键字<br />(b)基类CB中的函数和派生类CD中的函数一模一样，函数名，参数，返回类型都一样。<br />那么这就是叫做<font color="#ff0000">覆盖(override)，</font>这也就是虚函数，多态的性质</font></p><p><font size="4">那么其他的情况呢？？只要名字一样，不满足上面覆盖的条件，就是<font color="#ff0000">隐藏</font>了。</font></p><p><font size="4">下面我要讲最关键的地方了</font>，好多人认为，基类CB中的f(int)会继承下来和CD中的f(int,int)在派生类CD中构成重载，就像实例一中想像的那样。<br />　　对吗？我们先看重载的定义<br />　　<font color="#ff0000">重载(overload):<br /></font>　　必须在一个域中,函数名称相同但是函数参数不同,重载的作用就是同一个函数有不同的行为,因此不是在一个域中的函数是无法构成重载的,这个是重载的重要特征<br />　　<font color="#ff0000" size="4">必须在一个域中</font>，而继承明显是在两个类中了哦，所以上面的想法是不成立的，我们测试的结构也是这样，派生类中的f(int,int)把基类中的f(int)隐藏了<br />　　所以，<font color="#ff0000">相同的函数名的函数，在基类和派生类中的关系只能是覆盖或者隐藏。</font></p><p>　　在文章中，我把重载和覆盖的定义都给了出来了，但是一直没有给隐藏的定义，在最后，我把他给出来，这段话是网上google来的，比较长，你可以简单的理解成，在派生类域中，看不到基类中的那个同名函数了，或者说，是并没有继承下来给你用，呵呵，如实例一　那样。<br />　　</p><p><font color="#ff0000">隐藏(hide):<br /></font>指的是派生类的成员函数隐藏了基类函数的成员函数.隐藏一词可以这么理解:在调用一个类的成员函数的时候,编译器会沿着类的继承链逐级的向上查找函数的定义,如果找到了那么就停止查找了,所以如果一个派生类和一个基类都有同一个同名(暂且不论参数是否相同)的函数,而编译器最终选择了在派生类中的函数,那么我们就说这个派生类的成员函数"隐藏"了基类的成员函数,也就是说它阻止了编译器继续向上查找函数的定义</p></div></div></div><img src ="http://www.cppblog.com/ace/aggbug/6243.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-04-25 13:29 <a href="http://www.cppblog.com/ace/archive/2006/04/25/6243.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>STL中map与hash_map容器的选择 (转)</title><link>http://www.cppblog.com/ace/archive/2006/04/25/6223.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Tue, 25 Apr 2006 01:25:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/25/6223.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6223.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/25/6223.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6223.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6223.html</trackback:ping><description><![CDATA[<h3 class="storytitle">
				<a href="http://wolf.bloghome.cn/posts/5650">STL中map与hash_map容器的选择</a>
		</h3>
		<div class="meta">
				<ul class="post-categories">
						<li>
								<a title="各种静动态语言的经验谈，已经掌握的，或者将要学习的。" href="http://wolf.bloghome.cn/post_categories/2307">程序语言（c++ / c# / java / perl / python / lua）</a>
						</li>
				</ul>作者 alvin_lee @ 2005-06-21 17:43:38 </div>
		<div class="storycontent">
				<p>　　实际上这个问题不光C++会遇到，其他所有语言的标准容器的实现及选择上都是要考虑的。做应用程序你可能觉得影响不大，但是写算法或者核心代码就要小心了。今天改进代码，顺便又来温习基础功课了。</p>
				<br />
				<p>　　还记得Herb Sutter那极有味道的《C++对话系列》么，在其中《产生真正的hash对象》这个故事里就讲了map的选择。顺便回顾一下，也讲一下我在实用中的理解。</p>
				<p>　　选择map容器，是为了更快的从关键字查找到相关的对象。与使用list这样的线性表容器相比，一可以简化查找的算法，二可以使任意的关键字做索引，并与目标对象配对，优化查找算法。在C++的STL中map是使用树来做查找算法，这种算法差不多相当与list线性容器的折半查找的效率一样，都是O(log2N)，而list就没有map这样易定制和操作了。</p>
				<p>　　相比hash_map，hash_map使用hash表来排列配对，hash表是使用关键字来计算表位置。当这个表的大小合适，并且计算算法合适的情况下，hash表的算法复杂度为O(1)的，但是这是理想的情况下的，如果hash表的关键字计算与表位置存在冲突，那么最坏的复杂度为O(n)。</p>
				<p>　　那么有了这样的认识，我们应该怎么样选用算法呢？前两天看Python文章的时候，不知道哪个小子说Python的map比c++的map快，如何如何的。但是他并不知道Python是默认使用的hash_map，而且这些语言特征本质上是使用c/c++写出来的，问题在与算法和手段，而不是在于语言本身的优劣，你熟悉了各种算法，各种语言的细节、设计思想，还能在这偏激的嚷嚷孰好孰坏(片面与偏激的看待事物只能表明愚昧与无知，任何事物都有存在的价值，包括技术)。显然C++的STL默认使用树结构来实现map，是有考究的。</p>
				<p>　　树查找，在总查找效率上比不上hash表，但是它很稳定，它的算法复杂度不会出现波动。在一次查找中，你可以断定它最坏的情况下其复杂度不会超过O(log2N)。而hash表就不一样，是O(1)，还是O(N)，或者在其之间，你并不能把握。假若你在开发一个供外部调用的接口，其内部有关键字的查找，但是这个接口调用并不频繁，你是会希望其调用速度快、但不稳定呢，还是希望其调用时间平均、且稳定呢。反之假若你的程序需要查找一个关键字，这个操作非常频繁，你希望这些操作在总体上的时间较短，那么hash表查询在总时间上会比其他要短，平均操作时间也会短。这里就需要权衡了。</p>
				<p>　　这里总结一下，选用map还是hash_map，关键是看关键字查询操作次数，以及你所需要保证的是查询总体时间还是单个查询的时间。如果是要很多次操作，要求其整体效率，那么使用hash_map，平均处理时间短。如果是少数次的操作，使用hash_map可能造成不确定的O(N)，那么使用平均处理时间相对较慢、单次处理时间恒定的map，考虑整体稳定性应该要高于整体效率，因为前提在操作次数较少。如果在一次流程中，使用hash_map的少数操作产生一个最坏情况O(N)，那么hash_map的优势也因此丧尽了。 </p>
		</div><img src ="http://www.cppblog.com/ace/aggbug/6223.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-04-25 09:25 <a href="http://www.cppblog.com/ace/archive/2006/04/25/6223.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 简单讲解ACE_SOCK Wrapper Class的使用(原创)</title><link>http://www.cppblog.com/ace/archive/2006/04/20/5987.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Thu, 20 Apr 2006 15:50:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/20/5987.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/5987.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/20/5987.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/5987.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/5987.html</trackback:ping><description><![CDATA[<h1> 简单讲解ACE_SOCK Wrapper Class的使用</h1>
Stone Jiang<br /><a target="" class="" title="" href="/ace">http://www.cppblog.com/ace</a><br /><br /><br />
我们先来看一个场景:<br />
您去一家餐馆吃饭,这家餐馆位置就在水木清华街23号；您得事先知道餐馆的位置，从门进入，如果你想破墙而入那是不允可的。当你进门后，餐馆会有一位领位员招呼你，领位员会安排一个服务员为你提供服务的，你可以向服务员点菜，或听取服务员的推荐。用餐后你离开餐馆。<br /><br />
利用ACE SOCK编程，与上馆子极其相似。我们来作一个对比。<br />
餐馆的位置，嗯，计算机上，我们是IP地址，水木清华我们对应的是 smth.org,它的门牌号呢，对应的是我们的端口地址，在ACE中，我们用ACE_INET_Addr来表示。<br />
即，<br />
ACE_INET_Addr peer_addr;<br />
peer_addr;.set(23,"smth.org");<br />
我们也可以直接通过它的带参数的构造函数来声明和初始化，<br />
ACE_INET_Addr peer_addr(23,"smth.org")<br /><br />
餐馆的领位员相当于 ACE_SOCK_Acceptor,它被动的站在站口等着客户的到来，您作为客户，是主动端，ACE_SOCK_Connector则是您将在代码中看到的。<br /><br />
ACE面向连接的网络编程，有三个主要的角色<br />
主动端,被动端和数据交流的通道，即<br />
ACE_SOCK_Acceptor, ACE_SOCK_Connector和ACE_SOCK_Stream<br /><br />
接收和发送数据，则通过 ACE_SOCK_Stream::recv(...)和send(...)完成，本例演示了接收时的调用。<br /><br />
完成数据交互之后，ACE_SOCK_Stream::close()完成断开连接操作。 这相当于买单走人。<br /><br />
注：smth.org:23是水木清华Telnet服务，您还可以通过<br />
telnet smth.org来访问。<br /><br />
下面是完整代码示例 VC 7.1下调试通过<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">@file: mybrowser.cpp<br /></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">       Main function<br /></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">@auth: Stone Jiang &lt;2005119@gmail.com&gt;<br /></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">@date: 2006-4-20</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);"><br />#include </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><a title="ac" href="http://www.cs.wustl.edu/%7Eschmidt/ACE.html">ace</a>/Log_Msg.h</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br />#include </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><a title="ac" href="http://www.cs.wustl.edu/%7Eschmidt/ACE.html">ace</a>/SOCK_Connector.h</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br />#include </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><a title="ac" href="http://www.cs.wustl.edu/%7Eschmidt/ACE.html">ace</a>/SOCK_Stream.h</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br />#include </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><a title="ac" href="http://www.cs.wustl.edu/%7Eschmidt/ACE.html">ace</a>/INET_Addr.h</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br /><br /><br /></span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> ACE_TMAIN(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> argc, ACE_TCHAR</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> argv[])<br />{<br />  ACE_DEBUG((LM_DEBUG,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">start here\n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">));<br /><br />  </span><span style="color: rgb(0, 0, 255);">const</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> server_hostname </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">smth.org</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br /><br />  ACE_SOCK_Connector connector;<br />  ACE_SOCK_Stream peer;<br />  ACE_INET_Addr peer_addr;<br />  </span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"> buf[</span><span style="color: rgb(0, 0, 0);">64</span><span style="color: rgb(0, 0, 0);">]</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">};<br /><br />  </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(peer_addr.</span><span style="color: rgb(0, 0, 255);">set</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">23</span><span style="color: rgb(0, 0, 0);">,server_hostname) </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">)<br />  {<br />     ACE_ERROR_RETURN((LM_DEBUG,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">(%P|%t) %p\n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,<br />                 </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Set server host</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">),</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">);<br /><br />  }<br />  </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(connector.connect(peer,peer_addr) </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">)<br />  {<br />    ACE_ERROR_RETURN((LM_DEBUG,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">(%P|%t) %p\n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,<br />      </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Connection</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">),</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">);<br /><br />  }<br />  ACE_DEBUG((LM_DEBUG,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">建立连接成功 \n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">));<br />  </span><span style="color: rgb(0, 0, 255);">const</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> s </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">64</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">10</span><span style="color: rgb(0, 0, 0);">;<br />  </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> m </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br />  </span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);">(ssize_t n; (n </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> peer.recv(buf,</span><span style="color: rgb(0, 0, 255);">sizeof</span><span style="color: rgb(0, 0, 0);"> buf))</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;)<br />  {<br />    <br />    <a title="ac" href="http://www.cs.wustl.edu/%7Eschmidt/ACE.html">ace</a>::write_n(ACE_STDOUT,buf,n);<br />    m </span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);"> n;<br />    </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">( m </span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"> s)<br />    {<br />      </span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br />    }<br />  }<br />  peer.close();<br /><br />  </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br />}</span></div><br /><br /><br /><br /><img src ="http://www.cppblog.com/ace/aggbug/5987.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-04-20 23:50 <a href="http://www.cppblog.com/ace/archive/2006/04/20/5987.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>巧用虚友元函数(原创)</title><link>http://www.cppblog.com/ace/archive/2006/04/17/5796.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Mon, 17 Apr 2006 14:12:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/17/5796.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/5796.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/17/5796.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/5796.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/5796.html</trackback:ping><description><![CDATA[<p>父类的友元不会自动成为子类的友元；而且友元会破坏封装；C++的语方不允许（非成员）友元函数为虚函数。<br />但是，某些时候，必须通过友元才能实现一些操作符重载，如operator&lt;&lt;()；如果为每个子类都实现operator&lt;&lt;()倒是一个可行的方法，但是显得很啰嗦。<br /><br />如果能把友元定义为虚函数，则子类可以继承该友元的接口而无需重复声明友好那该多好啊？<br />本文则通过一种变通的方法巧妙达到虚函数的效果。<br /><br />//基类 Base.</p>
		<br />
		<br />
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">#pragma once<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">iostream</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">using</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">namespace</span>
				<span style="COLOR: #000000"> std;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Base<br /><img id="Codehighlighter1_65_249_Open_Image" onclick="this.style.display='none'; Codehighlighter1_65_249_Open_Text.style.display='none'; Codehighlighter1_65_249_Closed_Image.style.display='inline'; Codehighlighter1_65_249_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_65_249_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_65_249_Closed_Text.style.display='none'; Codehighlighter1_65_249_Open_Image.style.display='inline'; Codehighlighter1_65_249_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_65_249_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_65_249_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  Base(</span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span>
						<span style="COLOR: #000000">~</span>
						<span style="COLOR: #000000">Base(</span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">virtual</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> print(ostream</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000"> output) </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  friend ostream</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">operator</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">&lt;&lt;</span>
						<span style="COLOR: #000000">(ostream</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000"> output,Base</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000"> obj);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span>
						<span style="COLOR: #0000ff">private</span>
						<span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">char</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> name_;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> age_;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">;</span>
		</div>
		<br />基类的实现 base.cpp<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">StdAfx.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">.\base.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />Base::Base(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_59_101_Open_Image" onclick="this.style.display='none'; Codehighlighter1_59_101_Open_Text.style.display='none'; Codehighlighter1_59_101_Closed_Image.style.display='inline'; Codehighlighter1_59_101_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_59_101_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_59_101_Closed_Text.style.display='none'; Codehighlighter1_59_101_Open_Image.style.display='inline'; Codehighlighter1_59_101_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_59_101_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_59_101_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  name_ </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">This is data1</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  age_ </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">18</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />Base::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Base(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_122_124_Open_Image" onclick="this.style.display='none'; Codehighlighter1_122_124_Open_Text.style.display='none'; Codehighlighter1_122_124_Closed_Image.style.display='inline'; Codehighlighter1_122_124_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_122_124_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_122_124_Closed_Text.style.display='none'; Codehighlighter1_122_124_Open_Image.style.display='inline'; Codehighlighter1_122_124_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_122_124_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_122_124_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> Base::print(ostream</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> output)<br /><img id="Codehighlighter1_161_230_Open_Image" onclick="this.style.display='none'; Codehighlighter1_161_230_Open_Text.style.display='none'; Codehighlighter1_161_230_Closed_Image.style.display='inline'; Codehighlighter1_161_230_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_161_230_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_161_230_Closed_Text.style.display='none'; Codehighlighter1_161_230_Open_Image.style.display='inline'; Codehighlighter1_161_230_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_161_230_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_161_230_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  output</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">name = </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">name_</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  output</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">age = </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">age_</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />ostream</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">(ostream</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> output,Base</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> obj)<br /><img id="Codehighlighter1_280_320_Open_Image" onclick="this.style.display='none'; Codehighlighter1_280_320_Open_Text.style.display='none'; Codehighlighter1_280_320_Closed_Image.style.display='inline'; Codehighlighter1_280_320_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_280_320_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_280_320_Closed_Text.style.display='none'; Codehighlighter1_280_320_Open_Image.style.display='inline'; Codehighlighter1_280_320_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_280_320_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_280_320_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  obj.print(output);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> output;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div><br /><br />派生类的 Derived.h<br /><br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">#pragma once<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Base.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> Derived :</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> Base<br /><img id="Codehighlighter1_58_175_Open_Image" onclick="this.style.display='none'; Codehighlighter1_58_175_Open_Text.style.display='none'; Codehighlighter1_58_175_Closed_Image.style.display='inline'; Codehighlighter1_58_175_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_58_175_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_58_175_Closed_Text.style.display='none'; Codehighlighter1_58_175_Open_Image.style.display='inline'; Codehighlighter1_58_175_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_58_175_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_58_175_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  Derived(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> score </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">80</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Derived(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> print(ostream</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> output);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> score_;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div><br />派生类的实现 Derived.cpp<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">StdAfx.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">.\derived.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />Derived::Derived(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> score):score_(score)<br /><img id="Codehighlighter1_87_92_Open_Image" onclick="this.style.display='none'; Codehighlighter1_87_92_Open_Text.style.display='none'; Codehighlighter1_87_92_Closed_Image.style.display='inline'; Codehighlighter1_87_92_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_87_92_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_87_92_Closed_Text.style.display='none'; Codehighlighter1_87_92_Open_Image.style.display='inline'; Codehighlighter1_87_92_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_87_92_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_87_92_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  <br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />Derived::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Derived(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_119_121_Open_Image" onclick="this.style.display='none'; Codehighlighter1_119_121_Open_Text.style.display='none'; Codehighlighter1_119_121_Closed_Image.style.display='inline'; Codehighlighter1_119_121_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_119_121_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_119_121_Closed_Text.style.display='none'; Codehighlighter1_119_121_Open_Image.style.display='inline'; Codehighlighter1_119_121_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_119_121_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_119_121_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> Derived::print(ostream</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> output)<br /><img id="Codehighlighter1_161_222_Open_Image" onclick="this.style.display='none'; Codehighlighter1_161_222_Open_Text.style.display='none'; Codehighlighter1_161_222_Closed_Image.style.display='inline'; Codehighlighter1_161_222_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_161_222_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_161_222_Closed_Text.style.display='none'; Codehighlighter1_161_222_Open_Image.style.display='inline'; Codehighlighter1_161_222_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_161_222_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_161_222_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  Base::print(output);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  output</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">score = </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">score_</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div><br /><br />主程序main.cpp<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Test_VirtualFirendFunction.cpp : Defines the entry point for the console application.<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdafx.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Derived.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000"> std;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> _tmain(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, _TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br /><img id="Codehighlighter1_212_286_Open_Image" onclick="this.style.display='none'; Codehighlighter1_212_286_Open_Text.style.display='none'; Codehighlighter1_212_286_Closed_Image.style.display='inline'; Codehighlighter1_212_286_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_212_286_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_212_286_Closed_Text.style.display='none'; Codehighlighter1_212_286_Open_Image.style.display='inline'; Codehighlighter1_212_286_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_212_286_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_212_286_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  Derived  d;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  Derived  d2(</span><span style="COLOR: #000000">90</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">d</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">d2</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div><br />屏幕输入结果<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">name = This is data1<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />age = 18<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />score = 80<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />name = This is data1<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />age = 18<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />score = 90<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div><p>结果：<br />任何从Base派生类的，都可以利用cout&lt;&lt;obj的机制通过流进行输出。<br /><br />同样道理，也可以利用此方法实现ACE_InputCDR  / ACE_OutputCDR对网络操作序列化操作。<br />(本文也是回答某网友关于派生类不能重载的问题的回复)</p><img src ="http://www.cppblog.com/ace/aggbug/5796.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-04-17 22:12 <a href="http://www.cppblog.com/ace/archive/2006/04/17/5796.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++风格的类型转换的用法 (转)</title><link>http://www.cppblog.com/ace/archive/2006/04/16/5641.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Sun, 16 Apr 2006 06:21:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/16/5641.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/5641.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/16/5641.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/5641.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/5641.html</trackback:ping><description><![CDATA[<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;">
				<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->
				<span style="color: rgb(0, 0, 0);">C++风格的类型转换的用法<br />这是More Effecitve C++里的第二条对类型转换讲的很好，也很基础好懂。<br />Item M2：尽量使用C++风格的类型转换<br />仔细想想地位卑贱的类型转换功能（cast），其在程序设计中的地位就象goto语句一样令人鄙视。但是它还不是无法令人忍受，因为当在某些紧要的关头，类型转换还是必需的，这时它是一个必需品。<br />不过C风格的类型转换并不代表所有的类型转换功能。<br />一
来它们过于粗鲁，能允许你在任何类型之间进行转换。不过如果要进行更精确的类型转换，这会是一个优点。在这些类型转换中存在着巨大的不同，例如把一个指向
 const对象的指针（pointer-to-const-object）转换成指向非const对象的指针（pointer-to-non
-const -object）(即一个仅仅去除const的类型转换)，把一个指向基类的指针转换成指向子类的指针（即完全改变对象类型）。
传统的C风格的类型转换不对上述两种转换进行区分。（这一点也不令人惊讶，因为C风格的类型转换是为C语言设计的，而不是为C++语言设计的）。<br />二
来C风格的类型转换在程序语句中难以识别。在语法上，类型转换由圆括号和标识符组成，而这些可以用在C＋＋中的任何地方。这使得回答象这样一个最基本的有
关类型转换的问题变得很困难：“在这个程序中是否使用了类型转换？”。这是因为人工阅读很可能忽略了类型转换的语句，而利用象grep的工具程序也不能从
语句构成上区分出它们来。<br />C++通过引进四个新的类型转换操作符克服了C风格类型转换的缺点，这四个操作符是, 
static_cast, const_cast, dynamic_cast, 和reinterpret_cast。
在大多数情况下，对于这些操作符你只需要知道原来你习惯于这样写，<br />(type) expression<br />而现在你总应该这样写：<br />static_cast</span>
				<span style="color: rgb(0, 0, 255);">&lt;</span>
				<span style="color: rgb(128, 0, 0);">type</span>
				<span style="color: rgb(0, 0, 255);">&gt;</span>
				<span style="color: rgb(0, 0, 0);">(expression)<br />例如，假设你想把一个int转换成double，以便让包含int类型变量的表达式产生出浮点数值的结果。如果用C风格的类型转换，你能这样写：<br />int firstNumber, secondNumber;<br /><img src="http://www.cppblog.com/images/dot.gif" /><br />double result = ((double)firstNumber)/secondNumber；<br />如果用上述新的类型转换方法，你应该这样写：<br />double result = static_cast</span>
				<span style="color: rgb(0, 0, 255);">&lt;</span>
				<span style="color: rgb(128, 0, 0);">double</span>
				<span style="color: rgb(0, 0, 255);">&gt;</span>
				<span style="color: rgb(0, 0, 0);">(firstNumber)/secondNumber;<br />这样的类型转换不论是对人工还是对程序都很容易识别。<br />static_cast 
在功能上基本上与C风格的类型转换一样强大，含义也一样。它也有功能上限制。例如，你不能用static_cast象用C风格的类型转换一样把
 struct转换成int类型或者把double类型转换成指针类型，另外，static_cast不能从表达式中去除const属性，因为
另一个新的类型转换操作符const_cast有这样的功能。<br />其它新的C++类型转换操作符被用在需要更多限制的地方。const_cast用于
类型转换掉表达式的const或volatileness属性。通过使用const_cast，你向人们和编译器强调你通过类型转换想做的只是改变一些东
西的 constness或者volatileness属性。这个含义被编译器所约束。如果你试图使用const_cast来完成修改
constness 或者volatileness属性之外的事情，你的类型转换将被拒绝。下面是一些例子：<br />class Widget { <img src="http://www.cppblog.com/images/dot.gif" /> };<br />class SpecialWidget: public Widget { <img src="http://www.cppblog.com/images/dot.gif" /> };<br />void update(SpecialWidget *psw);<br />SpecialWidget sw; // sw 是一个非const 对象。<br />const SpecialWidget&amp; csw = sw; // csw 是sw的一个引用<br />// 它是一个const 对象<br />update(</span>
				<span style="color: rgb(255, 0, 0);">&amp;csw</span>
				<span style="color: rgb(0, 0, 0);">); // 错误!不能传递一个const SpecialWidget* 变量<br />// 给一个处理SpecialWidget*类型变量的函数<br />update(const_cast</span>
				<span style="color: rgb(0, 0, 255);">&lt;</span>
				<span style="color: rgb(128, 0, 0);">SpecialWidget</span>
				<span style="color: rgb(255, 0, 0);">*</span>
				<span style="color: rgb(0, 0, 255);">&gt;</span>
				<span style="color: rgb(0, 0, 0);">(</span>
				<span style="color: rgb(255, 0, 0);">&amp;csw</span>
				<span style="color: rgb(0, 0, 0);">));<br />// 正确，csw的const被显示地转换掉（<br />// csw和sw两个变量值在update<br />//函数中能被更新）<br />update((SpecialWidget*)</span>
				<span style="color: rgb(255, 0, 0);">&amp;csw</span>
				<span style="color: rgb(0, 0, 0);">);<br />// 同上，但用了一个更难识别<br />//的C风格的类型转换<br />Widget *pw = new SpecialWidget;<br />update(pw); // 错误！pw的类型是Widget*，但是<br />// update函数处理的是SpecialWidget*类型<br />update(const_cast</span>
				<span style="color: rgb(0, 0, 255);">&lt;</span>
				<span style="color: rgb(128, 0, 0);">SpecialWidget</span>
				<span style="color: rgb(255, 0, 0);">*</span>
				<span style="color: rgb(0, 0, 255);">&gt;</span>
				<span style="color: rgb(0, 0, 0);">(pw));<br />// 错误！const_cast仅能被用在影响<br />// constness or volatileness的地方上。,<br />// 不能用在向继承子类进行类型转换。<br />到目前为止，const_cast最普通的用途就是转换掉对象的const属性。<br />第
二种特殊的类型转换符是dynamic_cast，它被用于安全地沿着类的继承关系向下进行类型转换。这就是说，你能用dynamic_cast把指向基
类的指针或引用转换成指向其派生类或其兄弟类的指针或引用，而且你能知道转换是否成功。失败的转换将返回空指针（当对指针进行类型转换时）或者抛出异常
（当对引用进行类型转换时）：<br />Widget *pw;<br /><img src="http://www.cppblog.com/images/dot.gif" /><br />update(dynamic_cast</span>
				<span style="color: rgb(0, 0, 255);">&lt;</span>
				<span style="color: rgb(128, 0, 0);">SpecialWidget</span>
				<span style="color: rgb(255, 0, 0);">*</span>
				<span style="color: rgb(0, 0, 255);">&gt;</span>
				<span style="color: rgb(0, 0, 0);">(pw));<br />// 正确，传递给update函数一个指针<br />// 是指向变量类型为SpecialWidget的pw的指针<br />// 如果pw确实指向一个对象,<br />// 否则传递过去的将使空指针。<br />void updateViaRef(SpecialWidget&amp; rsw);<br />updateViaRef(dynamic_cast</span>
				<span style="color: rgb(0, 0, 255);">&lt;</span>
				<span style="color: rgb(128, 0, 0);">SpecialWidget</span>
				<span style="color: rgb(255, 0, 0);">&amp;</span>
				<span style="color: rgb(0, 0, 255);">&gt;</span>
				<span style="color: rgb(0, 0, 0);">(*pw));<br />//正确。传递给updateViaRef函数<br />// SpecialWidget pw 指针，如果pw<br />// 确实指向了某个对象<br />// 否则将抛出异常<br />dynamic_casts在帮助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上（参见条款M24），也不能用它来转换掉constness：<br />int firstNumber, secondNumber;<br /><img src="http://www.cppblog.com/images/dot.gif" /><br />double result = dynamic_cast</span>
				<span style="color: rgb(0, 0, 255);">&lt;</span>
				<span style="color: rgb(128, 0, 0);">double</span>
				<span style="color: rgb(0, 0, 255);">&gt;</span>
				<span style="color: rgb(0, 0, 0);">(firstNumber)/secondNumber;<br />// 错误！没有继承关系<br />const SpecialWidget sw;<br /><img src="http://www.cppblog.com/images/dot.gif" /><br />update(dynamic_cast</span>
				<span style="color: rgb(0, 0, 255);">&lt;</span>
				<span style="color: rgb(128, 0, 0);">SpecialWidget</span>
				<span style="color: rgb(255, 0, 0);">*</span>
				<span style="color: rgb(0, 0, 255);">&gt;</span>
				<span style="color: rgb(0, 0, 0);">(</span>
				<span style="color: rgb(255, 0, 0);">&amp;sw</span>
				<span style="color: rgb(0, 0, 0);">));<br />// 错误! dynamic_cast不能转换<br />// 掉const。<br />如你想在没有继承关系的类型中进行转换，你可能想到static_cast。如果是为了去除const，你总得用const_cast。<br />这四个类型转换符中的最后一个是reinterpret_cast。使用这个操作符的类型转换，其的转换结果几乎都是执行期定义（implementation-defined）。因此，使用reinterpret_casts的代码很难移植。<br />reinterpret_casts的最普通的用途就是在函数指针类型之间进行转换。例如，假设你有一个函数指针数组：<br />typedef void (*FuncPtr)(); // FuncPtr is 一个指向函数<br />// 的指针，该函数没有参数<br />// 返回值类型为void<br />FuncPtr funcPtrArray[10]; // funcPtrArray 是一个能容纳<br />// 10个FuncPtrs指针的数组<br />让我们假设你希望（因为某些莫名其妙的原因）把一个指向下面函数的指针存入funcPtrArray数组：<br />int doSomething();<br />你不能不经过类型转换而直接去做，因为doSomething函数对于funcPtrArray数组来说有一个错误的类型。在FuncPtrArray数组里的函数返回值是void类型，而doSomething函数返回值是int类型。<br />funcPtrArray[0] = </span>
				<span style="color: rgb(255, 0, 0);">&amp;doSomething;</span>
				<span style="color: rgb(0, 0, 0);"> // 错误！类型不匹配<br />reinterpret_cast可以让你迫使编译� </span>
		</div>
		<br /><img src ="http://www.cppblog.com/ace/aggbug/5641.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-04-16 14:21 <a href="http://www.cppblog.com/ace/archive/2006/04/16/5641.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>今天喜得两本书,需要的请留言</title><link>http://www.cppblog.com/ace/archive/2006/04/14/5514.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Fri, 14 Apr 2006 02:14:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/14/5514.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/5514.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/14/5514.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/5514.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/5514.html</trackback:ping><description><![CDATA[1.   
<table cellspacing="0" cellpadding="0" width="469" border="0"><tbody><tr valign="top"><td class="v2" colspan="3" height="20"><b>C++ Coding Standards: 101 Rules, Guidelines, and Best Practices</b></td></tr><tr><td class="v2" colspan="3" height="18">By <a class="v1" target="_new">Herb Sutter</a>, <a class="v1" target="_new">Andrei Alexandrescu</a></td></tr></tbody></table><br />这本书得到2005 Jolt大奖<br /><br />2. The Art or Unix Programming<br />这是继xxx和yyyy以来的最优秀的Unix读物.<br /><br /><img src ="http://www.cppblog.com/ace/aggbug/5514.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-04-14 10:14 <a href="http://www.cppblog.com/ace/archive/2006/04/14/5514.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>通过模板实现"多态性",避开继承带来的性能开销之讨论2</title><link>http://www.cppblog.com/ace/archive/2006/04/14/5506.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Fri, 14 Apr 2006 01:29:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/14/5506.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/5506.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/14/5506.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/5506.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/5506.html</trackback:ping><description><![CDATA[<div>多态生其实还可以通过类的聚合或组合的方式来达到<wbr>,从而还可以避免继承或多继承,</wbr></div>
		<div>代码如下 (未在开发环境中调试)
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> <br /><br />template </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> <br /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> A  <br />{ <br /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br />  </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> print() <br />  { <br />    base_.b(); <br />  }   <br />  typename T base_;<br />}; <br /><br /><br /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> B <br />{ <br /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br />  </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> b() <br />  { <br />    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> Class B---------------------\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); <br />  }   <br />}; <br /><br /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> C <br />{ <br /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br />  </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> b() <br />  { <br />    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> Class C---------------------\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); <br />  }   <br />}; <br /><br /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> []) <br />{ <br />  A</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">B</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> c; <br />  c.print(); <br />  A</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">C</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> c2;<br />  c2.print();<br />  </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;   <br />} <br /><br /></span></div></div><img src ="http://www.cppblog.com/ace/aggbug/5506.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-04-14 09:29 <a href="http://www.cppblog.com/ace/archive/2006/04/14/5506.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>通过模板实现"多态性",避开继承带来的性能开销之讨论</title><link>http://www.cppblog.com/ace/archive/2006/04/13/5478.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Thu, 13 Apr 2006 10:21:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/13/5478.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/5478.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/13/5478.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/5478.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/5478.html</trackback:ping><description><![CDATA[今天在看到一位 网友关于泛型编程的一个问题,源代码我稍整理变成这个样子 
<div>这里是＂多态性＂的一种实现方式</div><div> </div><div><table style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" border="1"><tbody><tr><td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent" valign="top" width="568"><p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align="left"><font face="Times New Roman"><span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: blue"></span></font><script><!--
D(["mb","class\n</span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\"> </span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:blue\">A</span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\">\n : </span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:blue\">public</span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\"> </span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:blue\">\nBASE</span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\"> </span></font></p>\n<p style\u003d\"margin:0cm 0cm 0pt;text-align:left\" align\u003d\"left\"><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\"><font face\u003d\"Times New Roman\">{ \n</font></span></p>\n<p style\u003d\"margin:0cm 0cm 0pt;text-align:left\" align\u003d\"left\"><font face\u003d\"Times New Roman\"><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:blue\">public\n</span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\">: </span></font></p>\n<p style\u003d\"margin:0cm 0cm 0pt;text-align:left\" align\u003d\"left\"><font face\u003d\"Times New Roman\"><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\"><span>\n  </span></span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:blue\">void</span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\"> </span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:#880000\">\nprint</span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\">() </span></font></p>\n<p style\u003d\"margin:0cm 0cm 0pt;text-align:left\" align\u003d\"left\"><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\"><font face\u003d\"Times New Roman\"><span>\n  </span>{ </font></span></p>\n<p style\u003d\"margin:0cm 0cm 0pt;text-align:left\" align\u003d\"left\"><font face\u003d\"Times New Roman\"><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\"><span>\n    </span></span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:blue\">BASE</span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\">::</span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:#880000\">\nb</span><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\">(); </span></font></p>\n<p style\u003d\"margin:0cm 0cm 0pt;text-align:left\" align\u003d\"left\"><span lang\u003d\"EN-US\" style\u003d\"font-size:12pt;color:black\"><font face\u003d\"Times New Roman\">",1]
);

//--></script></p></td></tr></tbody></table><br /></div><div><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> <br /><br />template </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> BASE</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> <br /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> A : </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> BASE <br />{ <br /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br />  </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> print() <br />  { <br />    BASE::b(); <br />  }   <br />}; <br /><br /><br /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> B <br />{ <br /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br />  </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> b() <br />  { <br />    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> Class B---------------------\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); <br />  }   <br />}; <br /><br /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> C <br />{ <br /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br />  </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> b() <br />  { <br />    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> Class C---------------------\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); <br />  }   <br />}; <br /><br /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> []) <br />{ <br />  A</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">B</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> c; <br />  c.print(); <br />  A</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">C</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"> c2;<br />  c2.print();<br />  </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;   <br />} <br /><br /></span></div></div><div>尽管General Programming 与Object-Oriend Programming没有什么优劣之分,如做乘法和做加法没有好<wbr>坏之分一样．</wbr></div><div>但这里，我还是想问一下，这里有模板有什么具体的好处？</div><div> </div><div>与之等效的我可以通过从基类派生的方式，实现同样的效果<wbr>，但众所周知，继承伴随着是virtual table和性能下降．这里，用这种方法显然可以避开上述问题．</wbr></div><div> </div><div>这只是我的认知能力，出于抛砖引玉的目的，希望大家能多发表点意见<wbr>．这还有什么益处呢？</wbr></div><img src ="http://www.cppblog.com/ace/aggbug/5478.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-04-13 18:21 <a href="http://www.cppblog.com/ace/archive/2006/04/13/5478.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++编码不规范出现的错误一例的解析</title><link>http://www.cppblog.com/ace/archive/2006/04/11/5292.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Tue, 11 Apr 2006 07:29:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/11/5292.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/5292.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/11/5292.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/5292.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/5292.html</trackback:ping><description><![CDATA[<p>
				<br />在Huihoo的ACE论坛中，有一网友问到为什么ACE_Time_Value的秒数在Debug版本少一秒，而<br />在Release版本上“正常”。经过对其代码的复读以及对ACE的跟踪，发现原来是编码不规范犯<br />下的一个很严重的错误造成的。本文就讨论这一例子。<br /><br />以下引用<br /> </p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span> <span style="COLOR: #008000">/*</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #008080"> 2</span> <span style="COLOR: #008000">我写了个从年月日时分秒数值得到ACE_Time_Value结果的函数:<br /></span><span style="COLOR: #008080"> 3</span> <span style="COLOR: #008000"></span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 4</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000"> s_get_ace_datetime(ACE_Time_Value </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> ace_datetime,<br /></span><span style="COLOR: #008080"> 5</span> <span style="COLOR: #000000">      </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> year,<br /></span><span style="COLOR: #008080"> 6</span> <span style="COLOR: #000000">      </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> month,<br /></span><span style="COLOR: #008080"> 7</span> <span style="COLOR: #000000">      </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> day,<br /></span><span style="COLOR: #008080"> 8</span> <span style="COLOR: #000000">      </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> hour,<br /></span><span style="COLOR: #008080"> 9</span> <span style="COLOR: #000000">      </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> min,<br /></span><span style="COLOR: #008080">10</span> <span style="COLOR: #000000">      </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> sec)<br /></span><span style="COLOR: #008080">11</span> <span style="COLOR: #000000">{<br /></span><span style="COLOR: #008080">12</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(year</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">1970</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> year</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">2038</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> month</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> month</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">12</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> day</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> day</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">31</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">13</span> <span style="COLOR: #000000">        hour</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> hour</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">23</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> min</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> min</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">59</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> sec</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> sec</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">59</span><span style="COLOR: #000000">)<br /></span><span style="COLOR: #008080">14</span> <span style="COLOR: #000000">          ACE_ERROR_RETURN((LM_ERROR,<br /></span><span style="COLOR: #008080">15</span> <span style="COLOR: #000000">                         ACE_TEXT(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%I(日期时间参数溢出合理的习惯日期时间范围1970.1.2-2038.1.18)n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)),</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">16</span> <span style="COLOR: #000000">    timespec_t spec_t;<br /></span><span style="COLOR: #008080">17</span> <span style="COLOR: #000000">    tm time_tm; <br /></span><span style="COLOR: #008080">18</span> <span style="COLOR: #000000">  time_tm.tm_year</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">year</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1900</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">19</span> <span style="COLOR: #000000">  time_tm.tm_mon</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">month</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">20</span> <span style="COLOR: #000000">  time_tm.tm_mday</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">day;<br /></span><span style="COLOR: #008080">21</span> <span style="COLOR: #000000">  time_tm.tm_hour</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">hour;<br /></span><span style="COLOR: #008080">22</span> <span style="COLOR: #000000">  time_tm.tm_min</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">min;<br /></span><span style="COLOR: #008080">23</span> <span style="COLOR: #000000">  </span><span style="COLOR: #0000ff">#if</span><span style="COLOR: #000000"> defined (ACE_NDEBUG)</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">24</span> <span style="COLOR: #000000">    time_tm.tm_sec</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">sec;<br /></span><span style="COLOR: #008080">25</span> <span style="COLOR: #000000">  </span><span style="COLOR: #0000ff">#else</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">26</span> <span style="COLOR: #000000">    time_tm.tm_sec</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">sec</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">奇怪,当由各部分数量构造ACE_Time_Value时,debug编译时,秒的数量总是自动减1,在此要补上1</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #008080">27</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">  </span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">28</span> <span style="COLOR: #000000">   spec_t.tv_sec</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">mktime(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">time_tm); <br /></span><span style="COLOR: #008080">29</span> <span style="COLOR: #000000">   </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(spec_t.tv_sec</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br /></span><span style="COLOR: #008080">30</span> <span style="COLOR: #000000">   ACE_ERROR_RETURN((LM_ERROR,ACE_TEXT(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%I(日期时间转化错误,得到&lt;0的time_t,日期范围是1970.1.2-2038.1.18)n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)),</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">31</span> <span style="COLOR: #000000">   ace_datetime.</span><span style="COLOR: #0000ff">set</span><span style="COLOR: #000000">(spec_t);<br /></span><span style="COLOR: #008080">32</span> <span style="COLOR: #000000">   </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">33</span> <span style="COLOR: #000000">}<br /></span><span style="COLOR: #008080">34</span> <span style="COLOR: #000000"></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #008080">35</span> <span style="COLOR: #008000">我在VC++7.1上分别编译了Debug版本和Release版本,time_tm.tm_sec竟然会有一秒的差别,莫名其妙地影响了我的项目.<br /></span><span style="COLOR: #008080">36</span> <span style="COLOR: #008000">哪位高手知道为什么?<br /></span><span style="COLOR: #008080">37</span> <span style="COLOR: #008000">另外ACE_Time_Value的范围太小,ACE中是否有大日期时间范围的其它类封装?<br /></span><span style="COLOR: #008080">38</span> <span style="COLOR: #008000"></span><span style="COLOR: #008000">*/</span></div>
		<p>以下是我的回贴:<br /></p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">你这个问题还真有趣,我跟踪了ACE相关代码后才发现,问题原来出在你写的函数中,病因是,使用未完全初始化的结构体变量<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />timespec_t spec_t;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />后面加上语句<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />memset(</span>
				<span style="COLOR: #ff0000">&amp;spec_t</span>
				<span style="COLOR: #000000">,0,sizeof(timespec_t));<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />即可<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />局部变量 spec_t 在debug时,各字段均被初始化为0xCCCCCCCC,它是一个负数<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />在下面的操作中,只修改了tv_sec,而tv_nsec 仍为一个负数<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />spec_t.tv_sec=mktime(</span>
				<span style="COLOR: #ff0000">&amp;time_tm</span>
				<span style="COLOR: #000000">); <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />ACE_Time_Value::normalize()默默地为你作了规格化处理，就替你减去了一秒钟。<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
		</div>
		<p>
				<br />
				<br />
				<br />
				<br />原代码更严重的错误在于：<br />原以为 Release版本是“正常”的，其实不然，而是Release隐藏了更严重的错误。<br />严重是因为它表现出错误的时候很随机，一旦产品发布，很难发现。<br /><br /></p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">对象(结构体)timespec有两个公有属性</span>
				<span style="COLOR: #008000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000"> typedef </span>
				<span style="COLOR: #0000ff">struct</span>
				<span style="COLOR: #000000"> timespec<br /><img id="Codehighlighter1_55_139_Open_Image" onclick="this.style.display='none'; Codehighlighter1_55_139_Open_Text.style.display='none'; Codehighlighter1_55_139_Closed_Image.style.display='inline'; Codehighlighter1_55_139_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_55_139_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_55_139_Closed_Text.style.display='none'; Codehighlighter1_55_139_Open_Image.style.display='inline'; Codehighlighter1_55_139_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />     </span>
				<span id="Codehighlighter1_55_139_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_55_139_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />       time_t tv_sec; </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> Seconds</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #000000">       </span>
						<span style="COLOR: #0000ff">long</span>
						<span style="COLOR: #000000"> tv_nsec; </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> Nanoseconds, 十亿分之一秒</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />
						</span>
						<span style="COLOR: #000000">     }</span>
				</span>
				<span style="COLOR: #000000"> timespec_t;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />     </span>
		</div>
		<p>在原代码16行<br />timespec_t spec_t;<br />构造了一个 timespec_t  临时对象spec_t后,debug版把它各字段初始化为 0xcccccccc,这使得问题一下子得于曝光.而Release版本, spec_t 为一个随机值. 本例程中,不允许 spec_t的tv_nsec为非0的任何数,为正常尽管看上去没有问题,但是这个对应的ACE_Time_Value的值也不可靠.在特定情况下可能产生重大事故.<br /><br /></p>
		<p>C++编码规范：<br />初始化对象时要完全。</p>
		<p>声明一个结构体后，如果要对其初始化，建议先把它设为0之后再作后续操作，养成这样一个习惯，就不会出现这样郁闷的事了。<br /><br /><br />原贴出处:<br /><a href="http://www.huihoo.com/forum/viewthread.php?tid=11016">http://www.huihoo.com/forum/viewthread.php?tid=11016</a><br /><br /><br />mooyee<br /></p><img src ="http://www.cppblog.com/ace/aggbug/5292.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ace/" target="_blank">Stone Jiang</a> 2006-04-11 15:29 <a href="http://www.cppblog.com/ace/archive/2006/04/11/5292.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>