﻿<?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-随笔分类-Miscellaneous</title><link>http://www.cppblog.com/ace/category/1419.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>Thu, 22 May 2008 05:18:47 GMT</lastBuildDate><pubDate>Thu, 22 May 2008 05:18:47 GMT</pubDate><ttl>60</ttl><item><title>欢迎访问www.ace-tao.org/bbs</title><link>http://www.cppblog.com/ace/archive/2007/12/05/37843.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Wed, 05 Dec 2007 04:59:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2007/12/05/37843.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/37843.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2007/12/05/37843.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/37843.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/37843.html</trackback:ping><description><![CDATA[欢迎访问http://<a href="http://www.ace-tao.org/bbs">www.ace-tao.org/bbs</a><br><br><br><img src ="http://www.cppblog.com/ace/aggbug/37843.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> 2007-12-05 12:59 <a href="http://www.cppblog.com/ace/archive/2007/12/05/37843.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用vs2005(vc8)编译log4cpp-0.3.5rc3</title><link>http://www.cppblog.com/ace/archive/2007/01/27/18050.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Sat, 27 Jan 2007 08:38:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2007/01/27/18050.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/18050.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2007/01/27/18050.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/18050.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/18050.html</trackback:ping><description><![CDATA[<div align="center">
				<h1>使用vs2005(vc8)编译log4cpp-0.3.5rc3</h1>
		</div>
		<div style="PADDING-RIGHT: 10px; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; BACKGROUND-COLOR: #ffffff">
				<div style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; Z-INDEX: 100; FLOAT: right; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px">
				</div>
				<div>
						<p>问题：由于log4cpp-0.3.5rc3仅提供了vc6的工程文件，因此，使用vs2005打开后，需要进行转换。但是转换后，不能正确编译，提示Custom Build Step时出现了错误。</p>
						<p>分析：因为log4cpp在生成NTEventLogAppender.dll时，需要连接NTEventLogCategories.mc文件。所以，项目设置了自定义的生成步骤去生成NTEventLogAppender.dll。但从vc6的工程文件转换时，这些步骤却没有正确的转换过来。从而出现上述问题。</p>
						<p>解决方法：重新填写Custom Build Step项。</p>
						<p>其中，CommandLine填写以下内容：</p>
						<p>if not exist $(OutDir) md $(OutDir)<br />"mc.exe" -h $(OutDir) -r $(OutDir) $(SolutionDir)NTEventLogCategories.mc<br />"RC.exe" -r -fo $(OutDir)\$(InputName).res $(ProjectDir)\$(InputName).rc<br />"link.exe" /MACHINE:IX86 -dll -noentry -out:$(OutDir)\NTEventLogAppender.dll $(OutDir)\$(InputName).res</p>
						<p>Outputs填写：$(OutDir)\NTEventLogAppender.dll</p>
						<p>适用范围：log4cpp项目、log4cppDLL项目的Debug和Release配置。同时，该方法适用于vs2003(vc7.1)。</p>
				</div>
		</div><img src ="http://www.cppblog.com/ace/aggbug/18050.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> 2007-01-27 16:38 <a href="http://www.cppblog.com/ace/archive/2007/01/27/18050.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/07/8242.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Wed, 07 Jun 2006 05:14:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/06/07/8242.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/8242.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/06/07/8242.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/8242.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/8242.html</trackback:ping><description><![CDATA[在网上看到,挺好的,转过来了.<br /><br /><img src="http://www.28star.com/blog/uploads/200512/26_154917_mindmanager.jpg" /><br /><img src ="http://www.cppblog.com/ace/aggbug/8242.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-07 13:14 <a href="http://www.cppblog.com/ace/archive/2006/06/07/8242.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Rational Rose中用UML建模时的元素重载</title><link>http://www.cppblog.com/ace/archive/2006/05/23/7535.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Tue, 23 May 2006 07:26:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/05/23/7535.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/7535.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/05/23/7535.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/7535.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/7535.html</trackback:ping><description><![CDATA[<p>在Rational Rose中用UML建模时的元素重载<br /><br />在利用Rational Rose对系统建模时，可能会遇到同一个被建模的对象在不同包中具有不同职责的问题。<br />比如，“用户”这个对象，在业务领域模型中，它是一个业务工人或业务主角(business actor)，在系统用例模型中，我们需要创建另一个代表系统执行者（Actor)的元素。Rational Rose以名称标识不同的模型元素，似图再创建一个叫"用户"的Actor则会超成重名。<br />这各重名，可以称为元素“重载”。<br /><br />下面介绍如何进行“元素重载”<br /><br /></p>
		<p>不在同一个包内的参与者、用例、类、构件和包，名称可以相同。不同的模型元素拥有相同的名称时，这些元素被称为“重载”<br />重载允许你进行基于多语言构件的开发。<br />重载允许用例视图中的参与者和逻辑视图中的类拥有相同的名称 </p>
		<p>
				<br />创建一个重载元素<br />1）从工具箱中创建一个新的元素<br />2）双击新元素，或者单击Browse&gt;Specification，打开规范窗口<br />3）在名称字段中输入名称<br />4）单击OK按钮  </p>
		<p>如果在其它包中存在具有相同名称的设计元素，系统会提示你，此时点“确定”即可<br /><br /></p><img src ="http://www.cppblog.com/ace/aggbug/7535.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-23 15:26 <a href="http://www.cppblog.com/ace/archive/2006/05/23/7535.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>4+1视图简述</title><link>http://www.cppblog.com/ace/archive/2006/05/08/6748.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Mon, 08 May 2006 07:22:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/05/08/6748.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6748.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/05/08/6748.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6748.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6748.html</trackback:ping><description><![CDATA[<p>4+1视图<br />url: http://www.cppblog.com/ace<br /><br />用例视图:对系统功能性需求对模，描述系统的行为，揭示系统“是什么”</p>
		<p>逻辑视图:描述系统设计模型，包含与系统结构最重要意义的部分，比如，系统分解成为的子系统，子系统分解成多个类，以及这些元素的职责，关系，操作和属性</p>
		<p>进程视图：描述系统分解成线程及进程的过程，描述线程（进程）通讯模试等</p>
		<p>部署视图：描述运行系统的物理硬件（包含网络）配置，说明每个节点的计算机，CPU，操作系统以及它们互联的情况，还要包括进程到节点之间的映射关系。</p>
		<p>实施视图：描述系统在构建时的分解后的子系统（包）的情况，特别是包括哪些组成部分由哪些团队开发，以及购入，外包，开发进度等内容。项目经理应该对这个视图最感兴趣。<br /></p><img src ="http://www.cppblog.com/ace/aggbug/6748.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-08 15:22 <a href="http://www.cppblog.com/ace/archive/2006/05/08/6748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>谁应当对用例有兴趣?</title><link>http://www.cppblog.com/ace/archive/2006/05/08/6742.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Mon, 08 May 2006 05:46:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/05/08/6742.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6742.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/05/08/6742.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6742.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6742.html</trackback:ping><description><![CDATA[<p>Who should be interested in Use case?</p>
		<p>Customers, who need to be sure that the system that is getting built is the one that they want.<br />客户，他们需要确定即将构建的系统是他们需要的系统。</p>
		<p>Managers, who need to have an overall understanding of what the system will do in order to effectively plan and monitor the project.</p>
		<p>经理，他们需要对将着手的系统有一个全局的了解，以便于对项目有效的计划和监控。</p>
		<p>Analysts, who need to describe and document what the system is going to do.<br />分析员，他们需要对将要着手的系统进行描述和文档化。</p>
		<p>Developers, who need to understand what the system needs to do in order to develop it.<br />开发人员，他们需要理解系统以便于开发它。</p>
		<p>Tester， who need to know what the system is supposed to do so that  they can verify that is does it.<br />测试人员，他们需要知道期望系统实现的功能，以便于它们验证系统是执行这些功能。</p>
		<p>Technical writers,who need to know what the system is supposed to so that they can describe it.<br />支持文档撰写者，他们需求要知道期望的系统以例描述它。<br /> <br />User-experience designers, who need to understand the users' goals and how the will use the system to achieve these goals.</p>
		<p>用户体验设计人员，他们需要理解用户的目标和他们将怎样使用系统达到他们的目标。</p><img src ="http://www.cppblog.com/ace/aggbug/6742.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-08 13:46 <a href="http://www.cppblog.com/ace/archive/2006/05/08/6742.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>[转]测试驱动开发全功略</title><link>http://www.cppblog.com/ace/archive/2006/04/28/6415.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Fri, 28 Apr 2006 05:03:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/28/6415.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6415.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/28/6415.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6415.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6415.html</trackback:ping><description><![CDATA[<div class="postTitle">
				<a class="postTitle2" id="viewpost1_TitleUrl" href="http://www.cnitblog.com/martin/archive/2006/04/27/9813.html">[转]测试驱动开发全功略</a>
		</div>
		<p>From: Brian Sun @ 爬树的泡泡[http://www.blogjava.net/briansun]</p>
		<p>
				<font color="#ff0000" size="5">{关键字}</font>
		</p>
		<p>测试驱动开发/Test Driven Development/TDD<br />测试用例/TestCase/TC<br />设计/Design<br />重构/Refactoring</p>
		<p>
				<font color="#ff0000" size="5">{TDD的目标}</font>
		</p>
		<blockquote>
				<p>
						<font style="FONT-WEIGHT: bold; FONT-SIZE: large; BACKGROUND-COLOR: rgb(220,220,220)">Clean Code That Works</font>
				</p>
		</blockquote>
		<p>这句话的含义是，事实上我们只做两件事情：让代码奏效（Work）和让代码洁净（Clean），前者是把事情做对，后者是把事情做好。想想看，其实我们平时所做的所有工作，除去无用的工作和错误的工作以外，真正正确的工作，并且是真正有意义的工作，其实也就只有两大类：增加功能和提升设计，而TDD 正是在这个原则上产生的。如果您的工作并非我们想象的这样，（这意味着您还存在第三类正确有意义的工作，或者您所要做的根本和我们在说的是两回事），那么这告诉我们您并不需要TDD，或者不适用TDD。而如果我们偶然猜对（这对于我来说是偶然，而对于Kent Beck和Martin Fowler这样的大师来说则是辛勤工作的成果），那么恭喜您，TDD有可能成为您显著提升工作效率的一件法宝。请不要将信将疑，若即若离，因为任何一项新的技术——只要是从根本上改变人的行为方式的技术——就必然使得相信它的人越来越相信，不信的人越来越不信。这就好比学游泳，唯一能学会游泳的途径就是亲自下去游，除此之外别无他法。这也好比成功学，即使把卡耐基或希尔博士的书倒背如流也不能拥有积极的心态，可当你以积极的心态去成就了一番事业之后，你就再也离不开它了。相信我，TDD也是这样！想试用TDD的人们，请遵循下面的步骤：</p>
		<blockquote>
				<font style="FONT-WEIGHT: bold; FONT-SIZE: large; BACKGROUND-COLOR: rgb(220,220,220)">
						<table cellspacing="1" cellpadding="1" bgcolor="#dcdcdc" border="0">
								<tbody>
										<tr>
												<td align="middle">编写TestCase</td>
												<td>--&gt;</td>
												<td align="middle">实现TestCase</td>
												<td>--&gt;</td>
												<td align="middle">重构</td>
										</tr>
										<tr>
												<td align="middle">（确定范围和目标）</td>
												<td> </td>
												<td align="middle">（增加功能）</td>
												<td> </td>
												<td align="middle">（提升设计）</td>
										</tr>
								</tbody>
						</table>
				</font>
		</blockquote>
		<p>[友情提示：敏捷建模中的一个相当重要的实践被称为：Prove it With Code，这种想法和TDD不谋而合。]</p>
		<p>
				<font color="#ff0000" size="5">{TDD的优点}</font>
		</p>
		<ol>
				<p>
						<b>『充满吸引力的优点』</b>
				</p>
				<li>完工时完工。表明我可以很清楚的看到自己的这段工作已经结束了，而传统的方式很难知道什么时候编码工作结束了。 
</li>
				<li>全面正确的认识代码和利用代码，而传统的方式没有这个机会。 
</li>
				<li>为利用你成果的人提供Sample，无论它是要利用你的源代码，还是直接重用你提供的组件。 
</li>
				<li>开发小组间降低了交流成本，提高了相互信赖程度。 
</li>
				<li>避免了过渡设计。 
</li>
				<li>系统可以与详尽的测试集一起发布，从而对程序的将来版本的修改和扩展提供方便。 
</li>
				<li>TDD给了我们自信，让我们今天的问题今天解决，明天的问题明天解决，今天不能解决明天的问题，因为明天的问题还没有出现(没有TestCase)，除非有TestCase否则我决不写任何代码；明天也不必担心今天的问题，只要我亮了绿灯。 
<p><b>『不显而易见的优点』</b></p></li>
				<li>逃避了设计角色。对于一个敏捷的开发小组，每个人都在做设计。 
</li>
				<li>大部分时间代码处在高质量状态，100％的时间里成果是可见的。 
</li>
				<li>由于可以保证编写测试和编写代码的是相同的程序员，降低了理解代码所花费的成本。 
</li>
				<li>为减少文档和代码之间存在的细微的差别和由这种差别所引入的Bug作出杰出贡献。 
</li>
				<li>在预先设计和紧急设计之间建立一种平衡点，为你区分哪些设计该事先做、哪些设计该迭代时做提供了一个可靠的判断依据。 
<p><b>『有争议的优点』</b></p></li>
				<li>事实上提高了开发效率。每一个正在使用TDD并相信TDD的人都会相信这一点，但观望者则不同，不相信TDD的人甚至坚决反对这一点，这很正常，世界总是这样。 
</li>
				<li>发现比传统测试方式更多的Bug。 
</li>
				<li>使IDE的调试功能失去意义，或者应该说，避免了令人头痛的调试和节约了调试的时间。 
</li>
				<li>总是处在要么编程要么重构的状态下，不会使人抓狂。（两顶帽子） 
</li>
				<li>单元测试非常有趣。 </li>
		</ol>
		<font color="#ff0000" size="5">{TDD的步骤}</font>
		<blockquote>
				<font style="FONT-WEIGHT: bold; FONT-SIZE: large; BACKGROUND-COLOR: rgb(220,220,220)">
						<table cellspacing="1" cellpadding="1" bgcolor="#dcdcdc" border="0">
								<tbody>
										<tr>
												<td align="middle">编写TestCase</td>
												<td>--&gt;</td>
												<td align="middle">实现TestCase</td>
												<td>--&gt;</td>
												<td align="middle">重构</td>
										</tr>
										<tr>
												<td align="middle">（不可运行）</td>
												<td> </td>
												<td align="middle">（可运行）</td>
												<td> </td>
												<td align="middle">（重构）</td>
										</tr>
								</tbody>
						</table>
				</font>
		</blockquote>
		<table cellspacing="2" cellpadding="2" border="0">
				<tbody>
						<tr>
								<td>步骤</td>
								<td>制品</td>
						</tr>
						<tr>
								<td>（1）快速新增一个测试用例</td>
								<td>新的TestCase</td>
						</tr>
						<tr>
								<td>（2）编译所有代码，刚刚写的那个测试很可能编译不通过 </td>
								<td>原始的TODO List</td>
						</tr>
						<tr>
								<td>（3）做尽可能少的改动，让编译通过</td>
								<td>Interface</td>
						</tr>
						<tr>
								<td>（4）运行所有的测试，发现最新的测试不能编译通过</td>
								<td>－(Red Bar)</td>
						</tr>
						<tr>
								<td>（5）做尽可能少的改动，让测试通过</td>
								<td>Implementation</td>
						</tr>
						<tr>
								<td>（6）运行所有的测试，保证每个都能通过</td>
								<td>－(Green Bar)</td>
						</tr>
						<tr>
								<td>（7）重构代码，以消除重复设计</td>
								<td>Clean Code That Works</td>
						</tr>
				</tbody>
		</table>
		<p>
				<font color="#ff0000" size="5">{FAQ}</font>
		</p>
		<p>
				<b>[什么时候重构？]</b>
				<br />如果您在软件公司工作，就意味着您成天都会和想通过重构改善代码质量的想法打交道，不仅您如此，您的大部分同事也都如此。可是，究竟什么时候该重构，什么情况下应该重构呢？我相信您和您的同事可能有很多不同的看法，最常见的答案是“该重构时重构”，“写不下去的时候重构”，和“下一次迭代开始之前重构”，或者干脆就是“最近没时间，就不重构了，下次有时间的时候重构吧”。正如您已经预见到我想说的——这些想法都是对重构的误解。重构不是一种构建软件的工具，不是一种设计软件的模式，也不是一个软件开发过程中的环节，正确理解重构的人应该把重构看成一种书写代码的方式，或习惯，重构时时刻刻有可能发生。在TDD中，除去编写测试用例和实现测试用例之外的所有工作都是重构，所以，没有重构任何设计都不能实现。至于什么时候重构嘛，还要分开看，有三句话是我的经验：实现测试用例时重构代码，完成某个特性时重构设计，产品的重构完成后还要记得重构一下测试用例哦。</p>
		<p>
				<b>[什么时候设计？]</b>
				<br />这个问题比前面一个要难回答的多，实话实说，本人在依照TDD开发软件的时候也常常被这个问题困扰，总是觉得有些问题应该在写测试用例之前定下来，而有些问题应该在新增一个一个测试用例的过程中自然出现，水到渠成。所以，我的建议是，设计的时机应该由开发者自己把握，不要受到TDD方式的限制，但是，不需要事先确定的事一定不能事先确定，免得捆住了自己的手脚。</p>
		<p>
				<b>[什么时候增加新的TestCase？]</b>
				<br />没事做的时候。通常我们认为，如果你要增加一个新的功能，那么先写一个不能通过的 TestCase；如果你发现了一个bug，那么先写一个不能通过的TestCase；如果你现在什么都没有，从0开始，请先写一个不能通过的 TestCase。所有的工作都是从一个TestCase开始。此外，还要注意的是，一些大师要求我们每次只允许有一个TestCase亮红灯，在这个 TestCase没有Green之前不可以写别的TestCase，这种要求可以适当考虑，但即使有多个TestCase亮红灯也不要紧，并未违反TDD 的主要精神。</p>
		<p>
				<b>[TestCase该怎么写？]</b>
				<br />测试用例的编写实际上就是两个过程：使用尚不存在的代码和定义这些代码的执行结果。所以一个 TestCase也就应该包括两个部分——场景和断言。第一次写TestCase的人会有很大的不适应的感觉，因为你之前所写的所有东西都是在解决问题，现在要你提出问题确实不大习惯，不过不用担心，你正在做正确的事情，而这个世界上最难的事情也不在于如何解决问题，而在于ask the right question！</p>
		<p>
				<b>[TDD能帮助我消除Bug吗？]</b>
				<br />答：不能！千万不要把“测试”和“除虫”混为一谈！“除虫”是指程序员通过自己的努力来减少bug的数量（消除bug这样的字眼我们还是不要讲为好^_^），而“测试”是指程序员书写产品以外的一段代码来确保产品能有效工作。虽然TDD所编写的测试用例在一定程度上为寻找bug提供了依据，但事实上，按照TDD的方式进行的软件开发是不可能通过TDD再找到bug的（想想我们前面说的“完工时完工”），你想啊，当我们的代码完成的时候，所有的测试用例都亮了绿灯，这时隐藏在代码中的bug一个都不会露出马脚来。</p>
		<p>但是，如果要问“测试”和“除虫”之间有什么联系，我相信还是有很多话可以讲的，比如TDD事实上减少了bug的数量，把查找bug战役的关注点从全线战场提升到代码战场以上。还有，bug的最可怕之处不在于隐藏之深，而在于满天遍野。如果你发现了一个用户很不容易才能发现的bug，那么不一定对工作做出了什么杰出贡献，但是如果你发现一段代码中，bug的密度或离散程度过高，那么恭喜你，你应该抛弃并重写这段代码了。TDD避免了这种情况，所以将寻找bug的工作降低到了一个新的低度。</p>
		<p>
				<b>[我该为一个Feature编写TestCase还是为一个类编写TestCase？]</b>
				<br />初学者常问的问题。虽然我们从TDD 的说明书上看到应该为一个特性编写相应的TestCase，但为什么著名的TDD大师所写的TestCase都是和类/方法一一对应的呢？为了解释这个问题，我和我的同事们都做了很多试验，最后我们得到了一个结论，虽然我不知道是否正确，但是如果您没有答案，可以姑且相信我们。</p>
		<p>我们的研究结果表明，通常在一个特性的开发开始时，我们针对特性编写测试用例，如果您发现这个特性无法用TestCase表达，那么请将这个特性细分，直至您可以为手上的特性写出TestCase为止。从这里开始是最安全的，它不会导致任何设计上重大的失误。但是，随着您不断的重构代码，不断的重构 TestCase，不断的依据TDD的思想做下去，最后当产品伴随测试用例集一起发布的时候，您就会不经意的发现经过重构以后的测试用例很可能是和产品中的类/方法一一对应的。</p>
		<p>
				<b>[什么时候应该将全部测试都运行一遍？]</b>
				<br />Good Question！大师们要求我们每次重构之后都要完整的运行一遍测试用例。这个要求可以理解，因为重构很可能会改变整个代码的结构或设计，从而导致不可预见的后果，但是如果我正在开发的是一个ERP怎么办？运行一遍完整的测试用例可能将花费数个小时，况且现在很多重构都是由工具做到的，这个要求的可行性和前提条件都有所动摇。所以我认为原则上你可以挑几个你觉得可能受到本次重构影响的TestCase去run，但是如果运行整个测试包只要花费数秒的时间，那么不介意你按大师的要求去做。</p>
		<p>
				<b>[什么时候改进一个TestCase？]</b>
				<br />增加的测试用例或重构以后的代码导致了原来的TestCase的失去了效果，变得无意义，甚至可能导致错误的结果，这时是改进TestCase的最好时机。但是有时你会发现，这样做仅仅导致了原来的TestCase在设计上是臃肿的，或者是冗余的，这都不要紧，只要它没有失效，你仍然不用去改进它。记住，TestCase不是你的产品，它不要好看，也不要怎么太科学，甚至没有性能要求，它只要能完成它的使命就可以了——这也证明了我们后面所说的“用Ctrl-C/Ctrl-V编写测试用例”的可行性。</p>
		<p>但是，美国人的想法其实跟我们还是不太一样，拿托尼巴赞的MindMap来说吧，其实画MindMap只是为了表现自己的思路，或记忆某些重要的事情，但托尼却建议大家把MindMap画成一件艺术品，甚至还有很多艺术家把自己画的抽象派MindMap拿出来帮助托尼做宣传。同样，大师们也要求我们把TestCase写的跟代码一样质量精良，可我想说的是，现在国内有几个公司能把产品的代码写的精良？？还是一步一步慢慢来吧。</p>
		<p>
				<b>[为什么原来通过的测试用例现在不能通过了？]</b>
				<br />这是一个警报，Red Alert！它可能表达了两层意思——都不是什么好意思——1）你刚刚进行的重构可能失败了，或存在一些错误未被发现，至少重构的结果和原来的代码不等价了。2）你刚刚增加的TestCase所表达的意思跟前面已经有的TestCase相冲突，也就是说，新增的功能违背了已有的设计，这种情况大部分可能是之前的设计错了。但无论哪错了，无论是那层意思，想找到这个问题的根源都比TDD的正常工作要难。</p>
		<p>
				<b>[我怎么知道那里该有一个方法还是该有一个类？]</b>
				<br />这个问题也是常常出现在我的脑海中，无论你是第一次接触TDD或者已经成为 TDD专家，这个问题都会缠绕着你不放。不过问题的答案可以参考前面的“什么时候设计”一节，答案不是唯一的。其实多数时候你不必考虑未来，今天只做今天的事，只要有重构工具，从方法到类和从类到方法都很容易。</p>
		<p>
				<b>[我要写一个TestCase，可是不知道从哪里开始？]</b>
				<br />从最重要的事开始，what matters most？从脚下开始，从手头上的工作开始，从眼前的事开始。从一个没有UI的核心特性开始，从算法开始，或者从最有可能耽误时间的模块开始，从一个最严重的bug开始。这是TDD主义者和鼠目寸光者的一个共同点，不同点是前者早已成竹在胸。</p>
		<p>
				<b>[为什么我的测试总是看起来有点愚蠢？]</b>
				<br />哦？是吗？来，握个手，我的也是！不必担心这一点，事实上，大师们给的例子也相当愚蠢，比如一个极端的例子是要写一个两个int变量相加的方法，大师先断言2+3=5，再断言5+5=10，难道这些代码不是很愚蠢吗？其实这只是一个极端的例子，当你初次接触TDD时，写这样的代码没什么不好，以后当你熟练时就会发现这样写没必要了，要记住，谦虚是通往TDD的必经之路！从经典开发方法转向TDD就像从面向过程转向面向对象一样困难，你可能什么都懂，但你写出来的类没有一个纯OO的！我的同事还告诉我真正的太极拳，其速度是很快的，不比任何一个快拳要慢，但是初学者（通常是指学习太极拳的前10年）太不容易把每个姿势都做对，所以只能慢慢来。</p>
		<p>
				<b>[什么场合不适用TDD？]</b>
				<br />问的好，确实有很多场合不适合使用TDD。比如对软件质量要求极高的军事或科研产品——神州六号，人命关天的软件——医疗设备，等等，再比如设计很重要必须提前做好的软件，这些都不适合TDD，但是不适合TDD不代表不能写TestCase，只是作用不同，地位不同罢了。</p>
		<p>
				<font color="#ff0000" size="5">{Best Practise}</font>
		</p>
		<p>
				<b>[微笑面对编译错误]</b>
				<br />学生时代最害怕的就是编译错误，编译错误可能会被老师视为上课不认真听课的证据，或者同学间相互嘲笑的砝码。甚至离开学校很多年的老程序员依然害怕它就像害怕迟到一样，潜意识里似乎编译错误极有可能和工资挂钩（或者和智商挂钩，反正都不是什么好事）。其实，只要提交到版本管理的代码没有编译错误就可以了，不要担心自己手上的代码的编译错误，通常，编译错误都集中在下面三个方面：<br />（1）你的代码存在低级错误<br />（2）由于某些Interface的实现尚不存在，所以被测试代码无法编译<br />（3）由于某些代码尚不存在，所以测试代码无法编译<br />请注意第二点与第三点完全不同，前者表明设计已存在，而实现不存在导致的编译错误；后者则指仅有TestCase而其它什么都没有的情况，设计和实现都不存在，没有Interface也没有Implementation。</p>
		<p>另外，编译器还有一个优点，那就是以最敏捷的身手告诉你，你的代码中有那些错误。当然如果你拥有Eclipse这样可以及时提示编译错误的IDE，就不需要这样的功能了。</p>
		<p>
				<b>[重视你的计划清单]</b>
				<br />在非TDD的情况下，尤其是传统的瀑布模型的情况下，程序员不会不知道该做什么，事实上，总是有设计或者别的什么制品在引导程序员开发。但是在TDD的情况下，这种优势没有了，所以一个计划清单对你来说十分重要，因为你必须自己发现该做什么。不同性格的人对于这一点会有不同的反应，我相信平时做事没什么计划要依靠别人安排的人（所谓将才）可能略有不适应，不过不要紧，Tasks和Calendar（又称效率手册）早已成为现代上班族的必备工具了；而平时工作生活就很有计划性的人，比如我:)，就会更喜欢这种自己可以掌控Plan的方式了。</p>
		<p>
				<b>[废黜每日代码质量检查]</b>
				<br />如果我没有记错的话，PSP对于个人代码检查的要求是蛮严格的，而同样是在针对个人的问题上， TDD却建议你废黜每日代码质量检查，别起疑心，因为你总是在做TestCase要求你做的事情，并且总是有办法（自动的）检查代码有没有做到这些事情 ——红灯停绿灯行，所以每日代码检查的时间可能被节省，对于一个严格的PSP实践者来说，这个成本还是很可观的！</p>
		<p>此外，对于每日代码质量检查的另一个好处，就是帮助你认识自己的代码，全面的从宏观、微观、各个角度审视自己的成果，现在，当你依照TDD做事时，这个优点也不需要了，还记得前面说的TDD的第二个优点吗，因为你已经全面的使用了一遍你的代码，这完全可以达到目的。</p>
		<p>但是，问题往往也并不那么简单，现在有没有人能告诉我，我如何全面审视我所写的测试用例呢？别忘了，它们也是以代码的形式存在的哦。呵呵，但愿这个问题没有把你吓到，因为我相信到目前为止，它还不是瓶颈问题，况且在编写产品代码的时候你还是会自主的发现很多测试代码上的没考虑到的地方，可以就此修改一下。道理就是如此，世界上没有任何方法能代替你思考的过程，所以也没有任何方法能阻止你犯错误，TDD仅能让你更容易发现这些错误而已。</p>
		<p>
				<b>[如果无法完成一个大的测试，就从最小的开始]</b>
				<br />如果我无法开始怎么办，教科书上有个很好的例子：我要写一个电影列表的类，我不知道如何下手，如何写测试用例，不要紧，首先想象静态的结果，如果我的电影列表刚刚建立呢，那么它应该是空的，OK，就写这个断言吧，断言一个刚刚初始化的电影列表是空的。这不是愚蠢，这是细节，奥运会五项全能的金牌得主玛丽莲·金是这样说的：“成功人士的共同点在于……如果目标不够清晰，他们会首先做通往成功道路上的每一个细小步骤……”。</p>
		<p>
				<b>[尝试编写自己的xUnit]</b>
				<br />Kent Beck建议大家每当接触一个新的语言或开发平台的时候，就自己写这个语言或平台的xUnit，其实几乎所有常用的语言和平台都已经有了自己的 xUnit，而且都是大同小异，但是为什么大师给出了这样的建议呢。其实Kent Beck的意思是说通过这样的方式你可以很快的了解这个语言或平台的特性，而且xUnit确实很简单，只要知道原理很快就能写出来。这对于那些喜欢自己写底层代码的人，或者喜欢控制力的人而言是个好消息。</p>
		<p>
				<b>[善于使用Ctrl-C/Ctrl-V来编写TestCase]</b>
				<br />不必担心TestCase会有代码冗余的问题，让它冗余好了。</p>
		<p>
				<b>[永远都是功能First，改进可以稍后进行]</b>
				<br />上面这个标题还可以改成另外一句话：避免过渡设计！</p>
		<p>
				<b>[淘汰陈旧的用例]</b>
				<br />舍不得孩子套不着狼。不要可惜陈旧的用例，因为它们可能从概念上已经是错误的了，或仅仅会得出错误的结果，或者在某次重构之后失去了意义。当然也不一定非要删除它们，从TestSuite中除去（JUnit）或加上Ignored（NUnit）标签也是一个好办法。</p>
		<p>
				<b>[用TestCase做试验]</b>
				<br />如果你在开始某个特性或产品的开发之前对某个领域不太熟悉或一无所知，或者对自己在该领域里的能力一无所知，那么你一定会选择做试验，在有单元测试作工具的情况下，建议你用TestCase做试验，这看起来就像你在写一个验证功能是否实现的 TestCase一样，而事实上也一样，只不过你所验证的不是代码本身，而是这些代码所依赖的环境。</p>
		<p>
				<b>[TestCase之间应该尽量独立]</b>
				<br />保证单独运行一个TestCase是有意义的。</p>
		<p>
				<b>[不仅测试必须要通过的代码，还要测试必须不能通过的代码]</b>
				<br />这是一个小技巧，也是不同于设计思路的东西。像越界的值或者乱码，或者类型不符的变量，这些输入都可能会导致某个异常的抛出，或者导致一个标示“illegal parameters”的返回值，这两种情况你都应该测试。当然我们无法枚举所有错误的输入或外部环境，这就像我们无法枚举所有正确的输入和外部环境一样，只要TestCase能说明问题就可以了。</p>
		<p>
				<b>[编写代码的第一步，是在TestCase中用Ctrl-C]</b>
				<br />这是一个高级技巧，呃，是的，我是这个意思，我不是说这个技巧难以掌握，而是说这个技巧当且仅当你已经是一个TDD高手时，你才能体会到它的魅力。多次使用TDD的人都有这样的体会，既然我的TestCase已经写的很好了，很能说明问题，为什么我的代码不能从TestCase拷贝一些东西来呢。当然，这要求你的TestCase已经具有很好的表达能力，比如断言f (5)=125的方式显然没有断言f(5)=5^(5-2)表达更多的内容。</p>
		<p>
				<b>[测试用例包应该尽量设计成可以自动运行的]</b>
				<br />如果产品是需要交付源代码的，那我们应该允许用户对代码进行修改或扩充后在自己的环境下run整个测试用例包。既然通常情况下的产品是可以自动运行的，那为什么同样作为交付用户的制品，测试用例包就不是自动运行的呢？即使产品不需要交付源代码，测试用例包也应该设计成可以自动运行的，这为测试部门或下一版本的开发人员提供了极大的便利。</p>
		<p>
				<b>[只亮一盏红灯]</b>
				<br />大师的建议，前面已经提到了，仅仅是建议。</p>
		<p>
				<b>[用TestCase描述你发现的bug]</b>
				<br />如果你在另一个部门的同事使用了你的代码，并且，他发现了一个bug，你猜他会怎么做？他会立即走到你的工位边上，大声斥责说：“你有bug！”吗？如果他胆敢这样对你，对不起，你一定要冷静下来，不要当面回骂他，相反你可以微微一笑，然后心平气和的对他说：“哦，是吗？那么好吧，给我一个TestCase证明一下。”现在局势已经倒向你这一边了，如果他还没有准备好回答你这致命的一击，我猜他会感到非常羞愧，并在内心责怪自己太莽撞。事实上，如果他的TestCase没有过多的要求你的代码（而是按你们事前的契约），并且亮了红灯，那么就可以确定是你的bug，反之，对方则无理了。用TestCase描述bug的另一个好处是，不会因为以后的修改而再次暴露这个bug，它已经成为你发布每一个版本之前所必须检查的内容了。</p>
		<p>
				<font color="#ff0000" size="5">{关于单元测试}</font>
		</p>
		<p>单元测试的目标是</p>
		<blockquote>
				<p>
						<font style="FONT-WEIGHT: bold; FONT-SIZE: large; BACKGROUND-COLOR: rgb(220,220,220)">Keep the bar green to keep the code clean</font>
				</p>
		</blockquote>
		<p>这句话的含义是，事实上我们只做两件事情：让代码奏效（Keep the bar green）和让代码洁净（Keep the code clean），前者是把事情做对，后者是把事情做好，两者既是TDD中的两顶帽子，又是xUnit架构中的因果关系。</p>
		<p>单元测试作为软件测试的一个类别，并非是xUnit架构创造的，而是很早就有了。但是xUnit架构使得单元测试变得直接、简单、高效和规范，这也是单元测试最近几年飞速发展成为衡量一个开发工具和环境的主要指标之一的原因。正如Martin Fowler所说：“软件工程有史以来从没有如此众多的人大大收益于如此简单的代码！”而且多数语言和平台的xUnit架构都是大同小异，有的仅是语言不同，其中最有代表性的是JUnit和NUnit，后者是前者的创新和扩展。一个单元测试框架xUnit应该：1）使每个TestCase独立运行；2）使每个TestCase可以独立检测和报告错误；3）易于在每次运行之前选择TestCase。下面是我枚举出的xUnit框架的概念，这些概念构成了当前业界单元测试理论和工具的核心：</p>
		<p>
				<b>[测试方法/TestMethod]</b>
				<br />测试的最小单位，直接表示为代码。</p>
		<p>
				<b>[测试用例/TestCase]</b>
				<br />由多个测试方法组成，是一个完整的对象，是很多TestRunner执行的最小单位。</p>
		<p>
				<b>[测试容器/TestSuite]</b>
				<br />由多个测试用例构成，意在把相同含义的测试用例手动安排在一起，TestSuite可以呈树状结构因而便于管理。在实现时，TestSuite形式上往往也是一个TestCase或TestFixture。</p>
		<p>
				<b>[断言/Assertion]</b>
				<br />断言一般有三类，分别是比较断言（如assertEquals），条件断言（如isTrue），和断言工具（如fail）。</p>
		<p>
				<b>[测试设备/TestFixture]</b>
				<br />为每个测试用例安排一个SetUp方法和一个TearDown方法，前者用于在执行该测试用例或该用例中的每个测试方法前调用以初始化某些内容，后者在执行该测试用例或该用例中的每个方法之后调用，通常用来消除测试对系统所做的修改。</p>
		<p>
				<b>[期望异常/Expected Exception]</b>
				<br />期望该测试方法抛出某种指定的异常，作为一个“断言”内容，同时也防止因为合情合理的异常而意外的终止了测试过程。</p>
		<p>
				<b>[种类/Category]</b>
				<br />为测试用例分类，实际使用时一般有TestSuite就不再使用Category，有Category就不再使用TestSuite。</p>
		<p>
				<b>[忽略/Ignored]</b>
				<br />设定该测试用例或测试方法被忽略，也就是不执行的意思。有些被抛弃的TestCase不愿删除，可以定为Ignored。</p>
		<p>
				<b>[测试执行器/TestRunner]</b>
				<br />执行测试的工具，表示以何种方式执行测试，别误会，这可不是在代码中规定的，完全是与测试内容无关的行为。比如文本方式，AWT方式，swing方式，或者Eclipse的一个视图等等。</p>
		<p>
				<font color="#ff0000" size="5">{实例：Fibonacci数列}</font>
		</p>
		<p>下面的Sample展示TDDer是如何编写一个旨在产生Fibonacci数列的方法。<br />（1）首先写一个TC，断言fib(1) = 1;fib(2) = 1;这表示该数列的第一个元素和第二个元素都是1。</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,255)">void</span>
						<span style="COLOR: rgb(0,0,0)"> testFab() {<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">));<br />}</span>
				</div>
		</div>
		<p>（2）上面这段代码不能编译通过，Great！——是的，我是说Great！当然，如果你正在用的是Eclipse那你不需要编译，Eclipse 会告诉你不存在fib方法，单击mark会问你要不要新建一个fib方法，Oh，当然！为了让上面那个TC能通过，我们这样写：</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</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)"> fib( </span>
						<span style="COLOR: rgb(0,0,255)">int</span>
						<span style="COLOR: rgb(0,0,0)"> n ) {<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)">1</span>
						<span style="COLOR: rgb(0,0,0)">;<br />}</span>
				</div>
		</div>
		<p>（3）现在那个TC亮了绿灯，wow！应该庆祝一下了。接下来要增加TC的难度了，测第三个元素。</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,255)">void</span>
						<span style="COLOR: rgb(0,0,0)"> testFab() {<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">3</span>
						<span style="COLOR: rgb(0,0,0)">));<br />}</span>
				</div>
		</div>
		<p>不过这样写还不太好看，不如这样写：</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,255)">void</span>
						<span style="COLOR: rgb(0,0,0)"> testFab() {<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(fib(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">)</span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)">fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">), fib(</span>
						<span style="COLOR: rgb(0,0,0)">3</span>
						<span style="COLOR: rgb(0,0,0)">));<br />}</span>
				</div>
		</div>
		<p>（4）新增加的断言导致了红灯，为了扭转这一局势我们这样修改fib方法，其中部分代码是从上面的代码中Ctrl-C/Ctrl-V来的：</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</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)"> fib( </span>
						<span style="COLOR: rgb(0,0,255)">int</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)"> ( n </span>
						<span style="COLOR: rgb(0,0,0)">==</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,0)">3</span>
						<span style="COLOR: rgb(0,0,0)"> ) </span>
						<span style="COLOR: rgb(0,0,255)">return</span>
						<span style="COLOR: rgb(0,0,0)"> fib(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">)</span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)">fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">);<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)">1</span>
						<span style="COLOR: rgb(0,0,0)">;<br />}</span>
				</div>
		</div>
		<p>（5）天哪，这真是个贱人写的代码！是啊，不是吗？因为TC就是产品的蓝本，产品只要恰好满足TC就ok。所以事情发展到这个地步不是fib方法的错，而是TC的错，于是TC还要进一步要求：</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,255)">void</span>
						<span style="COLOR: rgb(0,0,0)"> testFab() {<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(fib(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">)</span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)">fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">), fib(</span>
						<span style="COLOR: rgb(0,0,0)">3</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">)</span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)">fib(</span>
						<span style="COLOR: rgb(0,0,0)">3</span>
						<span style="COLOR: rgb(0,0,0)">), fib(</span>
						<span style="COLOR: rgb(0,0,0)">4</span>
						<span style="COLOR: rgb(0,0,0)">));<br />}</span>
				</div>
		</div>
		<p>（6）上有政策下有对策。</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</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)"> fib( </span>
						<span style="COLOR: rgb(0,0,255)">int</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)"> ( n </span>
						<span style="COLOR: rgb(0,0,0)">==</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,0)">3</span>
						<span style="COLOR: rgb(0,0,0)"> ) </span>
						<span style="COLOR: rgb(0,0,255)">return</span>
						<span style="COLOR: rgb(0,0,0)"> fib(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">)</span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)">fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">);<br />        </span>
						<span style="COLOR: rgb(0,0,255)">if</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)"> </span>
						<span style="COLOR: rgb(0,0,0)">4</span>
						<span style="COLOR: rgb(0,0,0)"> ) </span>
						<span style="COLOR: rgb(0,0,255)">return</span>
						<span style="COLOR: rgb(0,0,0)"> fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">)</span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)">fib(</span>
						<span style="COLOR: rgb(0,0,0)">3</span>
						<span style="COLOR: rgb(0,0,0)">);<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)">1</span>
						<span style="COLOR: rgb(0,0,0)">;<br />}</span>
				</div>
		</div>
		<p>（7）好了，不玩了。现在已经不是贱不贱的问题了，现在的问题是代码出现了冗余，所以我们要做的是——重构：</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</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)"> fib( </span>
						<span style="COLOR: rgb(0,0,255)">int</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)"> ( n </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)"> </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)"> </span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)"> ） </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)">1</span>
						<span style="COLOR: rgb(0,0,0)">;<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)">return</span>
						<span style="COLOR: rgb(0,0,0)"> fib( n </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)"> ) </span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)"> fib( n </span>
						<span style="COLOR: rgb(0,0,0)">-</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)"> );<br />}</span>
				</div>
		</div>
		<p>（8）好，现在你已经fib方法已经写完了吗？错了，一个危险的错误，你忘了错误的输入了。我们令0表示Fibonacci中没有这一项。</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,255)">void</span>
						<span style="COLOR: rgb(0,0,0)"> testFab() {<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(fib(</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">)</span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)">fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">), fib(</span>
						<span style="COLOR: rgb(0,0,0)">3</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(fib(</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">)</span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)">fib(</span>
						<span style="COLOR: rgb(0,0,0)">3</span>
						<span style="COLOR: rgb(0,0,0)">), fib(</span>
						<span style="COLOR: rgb(0,0,0)">4</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">0</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</span>
						<span style="COLOR: rgb(0,0,0)">0</span>
						<span style="COLOR: rgb(0,0,0)">));<br />        assertEquals(</span>
						<span style="COLOR: rgb(0,0,0)">0</span>
						<span style="COLOR: rgb(0,0,0)">, fib(</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 />}</span>
				</div>
		</div>
		<p>then change the method fib to make the bar grean：</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</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)"> fib( </span>
						<span style="COLOR: rgb(0,0,255)">int</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)"> ( n </span>
						<span style="COLOR: rgb(0,0,0)">&lt;=</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)"> ) </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>
						<span style="COLOR: rgb(0,0,255)">if</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)"> </span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)"> </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)"> </span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)"> ） </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)">1</span>
						<span style="COLOR: rgb(0,0,0)">;<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)">return</span>
						<span style="COLOR: rgb(0,0,0)"> fib( n </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)"> ) </span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)"> fib( n </span>
						<span style="COLOR: rgb(0,0,0)">-</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)"> );<br />}</span>
				</div>
		</div>
		<p>（9）下班前最后一件事情，把TC也重构一下：</p>
		<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
				<div>
						<span style="COLOR: rgb(0,0,255)">public</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,255)">void</span>
						<span style="COLOR: rgb(0,0,0)"> testFab() {<br />        </span>
						<span style="COLOR: rgb(0,0,255)">int</span>
						<span style="COLOR: rgb(0,0,0)"> cases[][] </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)">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)">}, {</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)">, </span>
						<span style="COLOR: rgb(0,0,0)">0</span>
						<span style="COLOR: rgb(0,0,0)">},  </span>
						<span style="COLOR: rgb(0,128,0)">//</span>
						<span style="COLOR: rgb(0,128,0)">the wrong parameters</span>
						<span style="COLOR: rgb(0,128,0)">
								<br />
						</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)">, </span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">}, {</span>
						<span style="COLOR: rgb(0,0,0)">2</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)">}};  </span>
						<span style="COLOR: rgb(0,128,0)">//</span>
						<span style="COLOR: rgb(0,128,0)">the first 2 elements</span>
						<span style="COLOR: rgb(0,128,0)">
								<br />
						</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)"> (</span>
						<span style="COLOR: rgb(0,0,255)">int</span>
						<span style="COLOR: rgb(0,0,0)"> i </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)">; i </span>
						<span style="COLOR: rgb(0,0,0)">&lt;</span>
						<span style="COLOR: rgb(0,0,0)"> cases.length; i</span>
						<span style="COLOR: rgb(0,0,0)">++</span>
						<span style="COLOR: rgb(0,0,0)">)<br />                assertEquals( cases[i][</span>
						<span style="COLOR: rgb(0,0,0)">1</span>
						<span style="COLOR: rgb(0,0,0)">], fib(cases[i][</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,128,0)">//</span>
						<span style="COLOR: rgb(0,128,0)">the rest elements</span>
						<span style="COLOR: rgb(0,128,0)">
								<br />
						</span>
						<span style="COLOR: rgb(0,0,0)">        </span>
						<span style="COLOR: rgb(0,0,255)">for</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)"> i </span>
						<span style="COLOR: rgb(0,0,0)">=</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,0)">3</span>
						<span style="COLOR: rgb(0,0,0)">; i </span>
						<span style="COLOR: rgb(0,0,0)">&lt;</span>
						<span style="COLOR: rgb(0,0,0)"> </span>
						<span style="COLOR: rgb(0,0,0)">20</span>
						<span style="COLOR: rgb(0,0,0)">; i</span>
						<span style="COLOR: rgb(0,0,0)">++</span>
						<span style="COLOR: rgb(0,0,0)">)<br />                assertEquals(fib(i</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)">)</span>
						<span style="COLOR: rgb(0,0,0)">+</span>
						<span style="COLOR: rgb(0,0,0)">fib(i</span>
						<span style="COLOR: rgb(0,0,0)">-</span>
						<span style="COLOR: rgb(0,0,0)">2</span>
						<span style="COLOR: rgb(0,0,0)">), fib(i));<br />}</span>
				</div>
		</div>
		<p>（10）打完收工。</p>
		<p>
				<font color="#ff0000" size="5">{关于本文的写作}</font>
		</p>
		<p>在本文的写作过程中，作者也用到了TDD的思维，事实上作者先构思要写一篇什么样的文章，然后写出这篇文章应该满足的几个要求，包括功能的要求（要写些什么）和性能的要求（可读性如何）和质量的要求（文字的要求），这些要求起初是一个也达不到的（因为正文还一个字没有），在这种情况下作者的文章无法编译通过，为了达到这些要求，作者不停的写啊写啊，终于在花尽了两个月的心血之后完成了当初既定的所有要求（make the bar green），随后作者整理了一下文章的结构（重构），在满意的提交给了Blog系统之后，作者穿上了一件绿色的汗衫，趴在地上，学了两声青蛙叫。。。。。。。^_^</p>
		<p>
				<font color="#ff0000" size="5">{后记：Martin Fowler在中国}</font>
		</p>
		<p>从本文正式完成到发表的几个小时里，我偶然读到了Martin Fowler先生北京访谈录，其间提到了很多对测试驱动开发的看法，摘抄在此：</p>
		<blockquote>
				<p>
						<font color="#008000">Martin Fowler：当然（值得花一半的时间来写单元测试）！因为单元测试能够使你更快的完成工作。无数次的实践已经证明这一点。你的时间越是紧张，就越要写单元测试，它看上去慢，但实际上能够帮助你更快、更舒服地达到目的。<br />Martin Fowler：什么叫重要？什么叫不重要？这是需要逐渐认识的，不是想当然的。我为绝大多数的模块写单元测试，是有点烦人，但是当你意识到这工作的价值时，你会欣然的。<br />Martin Fowler：对全世界的程序员我都是那么几条建议：……第二，学习测试驱动开发，这种新的方法会改变你对于软件开发的看法。……</font>
				</p>
				<p align="right">——《程序员》，2005年7月刊</p>
		</blockquote>
		<p>
				<font color="#ff0000" size="5">{鸣谢}</font>
		</p>
		<p>
				<a href="http://www.blogjava.net/fhawk">fhawk</a>
				<br />Dennis Chen<br /><a href="http://xdingding.cnblogs.com/">般若菩提</a><br /><a href="http://c2.com/ppr/about/author/kent.html">Kent Beck</a><br /><a href="http://www.martinfowler.com/">Martin Fowler</a><br /><a href="http://c2.com/">c2.com</a></p><img src ="http://www.cppblog.com/ace/aggbug/6415.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-28 13:03 <a href="http://www.cppblog.com/ace/archive/2006/04/28/6415.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>李开复《给中国学生的第五封信》 </title><link>http://www.cppblog.com/ace/archive/2006/04/28/6414.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Fri, 28 Apr 2006 04:43:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/28/6414.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6414.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/28/6414.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6414.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6414.html</trackback:ping><description><![CDATA[<div class="postTitle">
				<a class="postTitle2" id="viewpost1_TitleUrl" href="http://blog.hjenglish.com/cityhunter/archive/2006/04/28/295671.html">李开复《给中国学生的第五封信》</a>
		</div>
		<p>
				<strong>阅读笔记：积极主动，充满热情，是这封信的核心。最近自己也经历了一些事情，在面临未来发展前景的分岔道路，需要做出选择时，明知道某一条具有更大的发展前景，但是却由于未知的待遇问题放弃了选择它，并非不积极主动，不充满热情，但是某些时候有很多的外在因素可以影响决定。</strong>
		</p>
		<p>李开复《给中国学生的第五封信》，继续传授关于积极行动、把握自己命运的人生经验，这是“一封有关积极主动的信”。 </p>
		<p>    “今天大多数优秀的企业对人才的期望是：积极主动、充满热情、灵活自信的人”，学会“自己的事，自己负责，自己解决”，“我不能，别的任何人也不能代替你走过那条路；你必须自己去走。”</p>
		<p>一个人被击败，不是因为外界环境的阻碍，而是取决于他对环境如何反应。“有勇气改变可以改变的事情，有胸怀接受不可改变的事情，有智慧来分辨两者的不同。”</p>
		<p>    “如果你想知道什么，就自己到网上去找，不要急着去问别人；如果你听到了什么，不要盲目信从，应当自己主动去网上求证。”</p>
		<p>    被动就是弃权，不做决定也是一种决定。下定决心，每一件小事都要表达出自己的意见，就算你不是很在乎。例如，自己决定在餐馆点什么菜，自己决定自己的衣着打扮，周末时自己决定要去哪里玩，等等。设法让自己潜意识里的“我感觉，我想要”体现出来，不要被动，不要从众，避免盲目听从父母、老师、名人……</p>
		<p>    积极主动的人总是在言语中赋予自己决定的权利，他们喜欢说的话包括：“试试看有没有其他的可能性。”“也许我可以换个思路。”“我可以控制自己的情绪。”“我可以想出更有效的表达方式。”“我的感觉是……”“我选择……”“我要……”“我情愿……”“我打算……”“我决定……”等等。积极主动地抓住命运中你可以选择、可以改变、可以最大化你的影响力的部分。</p>
		<p>    美国人很喜欢尝试不同的工作，他们一生中平均要换四次工作。经常给自己设立一些极具挑战性、但绝非遥不可及的目标。</p>
		<p>    “等待的方法有两种，一种是什么事也不做地空等，另一种是一边等，一边把事情向前推动。”在机遇还没有来临时，就应事事用心，事事尽力。一旦机遇到来，一定要全力以赴，把握机遇。</p>
		<p>    在公司里，经常得到晋升机会的人，大多是能够积极推销和表达自己的、有进取心的人。当他们还是公司的一名普通员工时，只要和公司利益或者团队利益相关的事情，他们就会不遗余力地发表自己的见解、贡献自己的主张，帮助公司制定和安排工作计划；在完成本职工作后，他们总能协助其他人尽快完成工作；他们常常鼓励自己和同伴，提高整个队伍的士气；这些人总是以事为本、以事为先——他们都是最积极主动的人。</p>
		<p>    在人生的旅途中，你是你自己惟一的司机，千万不要让别人驾驶你的生命之车。你要稳稳地坐在司机的位置上，决定自己何时要停、要倒车、要转弯、要加速、要刹车等等。只有积极主动的人才能在瞬息万变的竞争环境中赢得成功，只有善于展示自己的人才能在工作中获得真正的机会。</p>
		<p>    “你们的时间有限，所以不要浪费时间在别人的生活里。不要被信条所惑 – 盲从信条是活在别人的生活里。不要让任何人的意见淹没了你内在的心声。重要的，拥有跟随内心和直觉的勇气。你的内心与直觉知道你真正想成为什么样的人。任何其他事物都是次要的。”——斯蒂夫 乔布斯 （苹果公司总裁）于2005年斯坦福大学毕业典礼。</p><img src ="http://www.cppblog.com/ace/aggbug/6414.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-28 12:43 <a href="http://www.cppblog.com/ace/archive/2006/04/28/6414.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我对重构的理解 (转)</title><link>http://www.cppblog.com/ace/archive/2006/04/28/6412.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Fri, 28 Apr 2006 04:34:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/28/6412.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6412.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/28/6412.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6412.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6412.html</trackback:ping><description><![CDATA[<strong>From: http://www.cnblogs.com/lane_cn/archive/2006/02/05/325782.html<br /><br />什么是重构<br /><br /></strong>重构，用最简单的一句话说：就是要在不改变系统功能的情况下，对系统的内部结构进行重新调整。重构的最直接目的在于改进软件系统的内部架构。一个好的结构可以更加适应于需求的变化，更好的满足客户的需求，最大限度的延长软件系统的生命周期。<br /><strong><br />为什么要重构<br /></strong><br />在不改变系统功能的情况下，改变系统的实现方式。为什么要这么做？投入精力不用来满足客户关心的需求，而是仅仅改变了软件的实现方式，这是否是在浪费客户的投资呢？<br /><br />重构的重要性要从软件的生命周期说起。软件不同与普通的产品，他是一种智力产品，没有具体的物理形态。一个软件不可能发生物理损耗，界面上的按钮永远不会因为按动次数太多而发生接触不良。那么为什么一个软件制造出来以后，却不能永远使用下去呢？<br /><br />对软件的生命造成威胁的因素只有一个：需求的变更。一个软件总是为解决某种特定的需求而产生，时代在发展，客户的业务也在发生变化。有的需求相对稳定一些，有的需求变化的比较剧烈，还有的需求已经消失了，或者转化成了别的需求。在这种情况下，软件必须相应的改变。<br /><br />考虑到成本和时间等因素，当然不是所有的需求变化都要在软件系统中实现。但是总的说来，软件要适应需求的变化，以保持自己的生命力。<br /><br />这就产生了一种糟糕的现象：软件产品最初制造出来，是经过精心的设计，具有良好架构的。但是随着时间的发展、需求的变化，必须不断的修改原有的功能、追加新的功能，还免不了有一些缺陷需要修改。为了实现变更，不可避免的要违反最初的设计构架。经过一段时间以后，软件的架构就千疮百孔了。bug越来越多，越来越难维护，新的需求越来越难实现，软件的构架对新的需求渐渐的失去支持能力，而是成为一种制约。最后新需求的开发成本会超过开发一个新的软件的成本，这就是这个软件系统的生命走到尽头的时候。<br /><br />重构就能够最大限度的避免这样一种现象。系统发展到一定阶段后，使用重构的方式，不改变系统的外部功能，只对内部的结构进行重新的整理。通过重构，不断的调整系统的结构，使系统对于需求的变更始终具有较强的适应能力。<br /><strong><br />拒绝变化 VS 拥抱变化<br /></strong><br />按照传统的软件设计方式，软件的生产分为需求调查、概要设计、详细设计、编码、单体测试、联合测试、现场部署几个阶段。虽说这几个阶段是可以互相渗透，但是总的来说是有一定次序的，前一个阶段的工作是后一个阶段工作的基础。这就向下面这样一种V形的模式：<br /><br /><img height="245" alt="vdevelope.GIF" src="http://www.cnitblog.com/images/cnitblog_com/martin/vdevelope.GIF" width="368" border="0" /><br /><br />往下的方向将系统进行分解，往上的方向将系统进行整合。这样的开发形式将软件开发分为设计前和设计后两个阶段，开发过程中存在一个重要的“里程碑”——设计说明书的。在设计说明书完成前，工程处于“设计”阶段，而在设计说明书完成之后，工程则进入“实施”阶段。一旦到了实施阶段，任何需求或者设计上的变更都是非常困难的，需要花费大量的成本。通常为了保证工程的顺利实施，开发人员常有这样一种冲动：按住客户的手，在需求说明书上签字。并且告诉客户：“从今天开始，任何需求变更都要停止，直到我们把现在这个东西做完。”这是一种拒绝变化的开发方式。<br /><br />软件系统要保持与企业的目标一致。时代在发展，人们的要求在不断的提高，客户的业务在不断的发展。在这种情况下，传统的先设计、再施工的V形式已经不能适应日益复杂的业务需要。软件工程逐渐演化成下面这样的过程：<br /><br /><img height="160" alt="sdevelope.GIF" src="http://www.cnitblog.com/images/cnitblog_com/martin/sdevelope.GIF" width="163" border="0" /><br /><br />说明一下：<br />1、软件开发的目标要与企业目标保持一致，一个开发周期不宜时间过长，一般控制在半年到一年。系统部署后，并不意味着开发工作结束了，而是进入了下一个周期。<br /><br />2、工程以循环迭代的方式前进，这并不意味轻视了设计，不是要搞边调研、边设计、边施工的“三边”工程，相反，是更加重视设计的地位。软件开发的全过程都需要设计，软件开发是“持续设计”的过程。同时，设计工作也不只是简单过程分解、任务分配，而是概念设计、逻辑设计、物理设计等各个方面互相交织、齐头并进。<br /><br />传统的软件开发方式使用一种非常理想化的流程——先与客户讨论项目的范围，确定哪些需要做，哪些不需要做，然后规划一个完美的设计，不仅可以满足现在的需求，还能很好的适应未来的需求，设计完成后开始编码，然后测试组装，送到现场安装调试运行。这一系列过程就类似与发射一颗炮弹，首先要找到目标，然后根据地形、风力、目标的位置、移动速度等各种因素，计算提前量、炮弹发射的角度，计算出一个抛物线轨道，最后在合适的时间把炮弹发射出去。这一切都符合最正确的物理定律，一切都听起来很理想。如果没有意外条件，当然是可以击中目标的。但是炮弹一旦发射出去，一切就失去了控制，任何环境的变化都会造成偏离目标。尤其是对于一个运动的目标来说，计算过程十分复杂，很多情况下只能靠人估计。对于不规则的运动目标只能碰碰运气。这样的方式，命中率是很低的。<br /><br />新的软件开发过程不追求完美的、长期的、理想的计划，更加重视实际情况，重视需求的变化，提倡采用短期的计划。这是一种拥抱变化的过程。就象是在炮弹上安装了一个反馈装置，锁定目标后，确保大方向的正确，然后就将炮弹发射出去。炮弹在运行过程中不断的将目标位置偏移量输入反馈电路，根据反馈输出调整自己的运行路线，无限的逼近目标。这样，炮弹就拥有了制导能力，命中率大大增加。<br /><br />重构就可以增加工程的调整能力，他可以把产品回复到一个稳定的状态，可以基于这个状态达到下一个目标。如此反复前进，更好的满足客户的需求。<br /><br /><strong>保持兼容性<br /></strong><br />重构的目的在于改变系统的实现方式，而不改变原有的功能。这个过程中，判断兼容性就十分的重要。一个子系统、模块、类、函数是否与升级前保持兼容，如何判断这个兼容性，如何保持这个兼容性，这关系到重构的成本和重构的可能性。<br /><br />程序员学习写程序代码时，会发现随着程序代码愈来愈多，许多的程序代码不断重复出现和被使用，因此很自然的开始使用例程、子程序或是过程、函数等机制帮助我们进行程序代码整理的工作。于是很自然的，字体的分析方式演化成这个样子：将客户的需求过程进行分解，一步一步的分解，直到可以直接的实现他。这就是面向过程的分析方式。<br /><br />面向过程的分析方式对变化的能力是很弱的。为什么呢？因为面向过程的分析方式很容易造成一种倾向——不区分行动的主体。一个过程是没有主体的，他不是在为自己工作，而是在为“别人”工作。当我们修改了一个过程之后，我们很难判断这个过程是否保持向后兼容，其他过程会不会受到影响。因为这个过程对外界有意义的不仅是他的输入和输出，还包括每一步过程，每一步过程都可能含有一个非常隐讳的业务意义，对外界产生影响。<br /><br />因此，修改一个过程是非常困难的，通常升级一个面向过程的系统，可以采用两种方式：<br />1、写新的过程；<br />2、在原有的过程上加开关参数。<br /><br />除此以外的升级办法都很难保证原过程和新过程的兼容性，容易造成错误。<br /><br />为了更好的保证升级后模块的兼容性，应该采用面向对象的分析方式。按照这样的分析方式，一个对象为“自己”工作，他有完整的、独立的业务含义。对象之间通过接口发生联系，一个对象对外界有影响的部分只有接口，至于他做什么、如何做、做的对不对，则不是外界需要关心的事情。<br /><br />判断一个接口升级后是否保持兼容性就是一件比较容易的事情了。我们可以判断接口的输入输出是否符合下面两条规则：<br />1、升级后的输入是升级前的输入的超级；<br />2、升级后的输出是升级前的输出的子集。<br /><br />只要符合这两点，他就仍然可以在系统中运行，不会对其他对象造成危害。在实际的工程中，判断这个兼容性有一个更好的办法：<strong>自动化的单元测试</strong>。<br /><br />在重构的过程中，自动化的单元测试是非常好的保障。采用自动化的单元测试，不断运行测试，可以保证系统的结构改变的过程中，业务行为不发生改变。<img height="1" src="http://www.cnitblog.com/martin/aggbug/9810.html" width="1" /><br /><br /><img src ="http://www.cppblog.com/ace/aggbug/6412.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-28 12:34 <a href="http://www.cppblog.com/ace/archive/2006/04/28/6412.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一封“发飙”邮件的传播路径 (转)</title><link>http://www.cppblog.com/ace/archive/2006/04/27/6359.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Thu, 27 Apr 2006 01:12:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/27/6359.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6359.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/27/6359.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6359.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6359.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Feed: 灿烂的生活 Title: EMC秘书PK总裁及其背后的沟通风格与角色分析																														1 Comment										  																																																																									...&nbsp;&nbsp;<a href='http://www.cppblog.com/ace/archive/2006/04/27/6359.html'>阅读全文</a><img src ="http://www.cppblog.com/ace/aggbug/6359.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-27 09:12 <a href="http://www.cppblog.com/ace/archive/2006/04/27/6359.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>硬盘安装Fedora Core 4 全过程（WinXp+ FC4）(转)</title><link>http://www.cppblog.com/ace/archive/2006/04/25/6248.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Tue, 25 Apr 2006 08:27:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/25/6248.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6248.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/25/6248.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6248.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6248.html</trackback:ping><description><![CDATA[<u>
				<font color="#800080">硬盘安装Fedora Core 4 全过程（WinXp+ FC4）
<script language="javascript"><![CDATA[ocument.title="硬盘安装Fedora Core 4 全过程（WinXp+ FC4） - "+document.title]]&gt;</script></font>
		</u>
		<div class="postText">
				<p> </p>
				<p>1、整理出一个大概10G（最少6G）左右的分区，用PQ8分两个区，一个Swap1.2G，一个ext2/ext3的格式，用于安装Linux系统</p>
				<p>2、下载ISO文件到一个FAT32格式的分区上，约为2.57GB大小，如D:\FC4\</p>
				<p>3、下载：<a href="http://www.bitman.cn/Linux/grub020p.zip">Grub For Dos</a> ，放到C盘（我的WinXP安装在C盘）根目录下</p>
				<p>4、编辑C:\boot.ini 文件，加入一行<br />C:\grldr="GRUB For Dos/Windows " </p>
				<p>5、编辑C:\boot\grub\menu.lst 加入： <br />title Install-Fedora Core 4 <br />kernel (hd0,0)/isolinux/vmlinuz <br />initrd (hd0,0)/isolinux/initrd.img </p>
				<p>5、重新启动电脑，依次选择： GRUB For Dos/Windows &gt; Install-Fedora Core 4；进入安装程序，在安装过程中当进行到选择安装介质时，选硬盘安装，找到自己ISO放置的位置，如dev/sdm2/Fc4</p>
				<p>6、进入正式安装，在选择分区的时候，把ext2/ext3的分区进行挂载即可，其他按照提示操作（挂载简单的操作就是选中ext2/ext3的分区，然后选择下拉菜单中的"/"即可）</p>
				<p>7、安装，根据模块的加载的多少，机器的运行速度，时间由20分钟到1个小时不等</p>
				<p>8、安装好之后设置用户名和密码，注意FC4的用户名是区分大小写的</p>
				<p>9、安装好之后用 用户名root+密码 登陆</p>
				<p>10、打开应用程序下的Terminal，运行如下命令，对系统进行升级<br />#rpm -import /usr/share/rhn/RPM-GPG-KEY-fedora <br />#yum update </p>
				<p>大约10分钟左右，会列出800多兆需要更新的程序包，进行更新即可</p>
				<p>11、美化一下中文字体<br />下载字体：<a href="http://www.bitman.cn/Linux/bkai00mp.ttf">http://www.bitman.cn/Linux/bkai00mp.ttf</a><br />进入文件夹： #cd /usr/share/fonts/chinese/TrueTypa<br />删除下面所有的字体，然后把bkai00mp.ttf放置到如上目录即可</p>
		</div><img src ="http://www.cppblog.com/ace/aggbug/6248.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 16:27 <a href="http://www.cppblog.com/ace/archive/2006/04/25/6248.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>输了这四年你就输了一生  (转)</title><link>http://www.cppblog.com/ace/archive/2006/04/25/6238.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Tue, 25 Apr 2006 05:00:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/25/6238.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/6238.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/25/6238.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/6238.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/6238.html</trackback:ping><description><![CDATA[<div class="postTitle">
				<a href="http://blog.csdn.net/wfdmd/archive/2006/04/24/675563.aspx"> 输了这四年你就输了一生</a>
				<script language="javascript"><![CDATA[ocument.title="输了这四年你就输了一生 - "+document.title]]&gt;</script>
		</div>
		<div class="postText">
				<p>于学计算机或者从事这方面工作的朋友.<br />1、首先，不论你是不是计算机专业的朋友，相信一句话。“想成功不努力是不行的”，只要你努力，无论你是不是学计算机的都会获得成功的。如果你不努力，无论你是不是学计算机的，都很难混的。<br />2、无论学什么专业。一定要先做人，再做事，如果你做人有问题，无论你做什么都是失败的。要提高自己的素质，需要平时有意识的积累。多交比较上进的朋友。别滥交朋友,比如多结交小w之类的朋友:)<br />3、如果你以后的工作意想是软件公司，那么你必须要懂得至少一门开发语言。即使你的志向比较高你也必须从开发开始，否则同事是瞧不起你的。而且较为熟练的使用，如果有相关的项目经验最为合适。程序开发是很辛苦的工作,在你还没准备好这个方向之前,一定要想好这个是不是你想要的.对于it这行当,你必须准备好随时学习新的东西,打算学一两个工具就可以混一生的想法千万别想.如果你是本科生(包括以下),这是你必须要准备的.<br />偶曾经用过的工具(时间顺序):asp（比较熟练），pb（用过1个月,现在全忘记）,delphi（用过一段时间,现在忘的差不多）,exchange（用过1个月,现在全忘记）,Lotus notes(用过2个月，开发过一个论坛，也忘记的差不多)，java（主要是写jsp用。很少用来写java），primeton（构件开发工具，一直在用，比较熟练），plsql（oracle客户端工具，经常用，比较熟练）<br />逐步告别程序开发生活。<br />4、如果你是研究生（包括比较有经验的从业人员），你的目标不应该是程序开发人员，至少是设计人员。这个时候你有两个方向，一个是项目管理，如项目经理,另外一个是技术方向，如架构师.小的公司可能一人兼多个职位.无论哪个方向都需要大量的实践经验.如果在毕业之前就有项目经验是非常有理的,而善于总结的人那就能提升自己的层次.程序开发人员不应该做为职业的发展目标,而是起点.<br />5、在学校里千万不要浪费时间.要合理安排学校生活，让学校生活丰富而收获，“输了这四年你就输了一生”。要提高自己的学习能力,要从思想上理解.工具是次要的.无论什么语言,到工作的 时候都不够用的.所以 我觉得在学校学习的时候要求面广,而不是精通.当然,如果你对某一种语言有兴趣的话,精通也无妨,我说的不要精通,不是说随便学下,我的意思是这个工具应付工程没有问题那就可以了.就是说可以独立开发一个模块.而不要对工程中极少用到的一些知识花大力气研究,我说这话是 基于学校的时间是不够的.其他还要很多需要学习的知识.<br />我觉得大学里必须要学会的东东:<br />学会做人(沟通能力,成熟,组织能力,理解能力):可以多参加各种社团活动,如果没有社团活动,老乡活动也可以.最好自己组织.<br />英语(至少4级):下点功夫.会有回报的.这么说吧,对于四六级证书,多1个证书,相当于一个月多1000rmb,这么说是不是有吸引力一点.<br />专业课程:软件工程,数据结构,数据库知识,网络知识<br />我觉得这四门最为重要,并不是说其他的不重要啊,其他的课上课不缺课,考试中等以上就可以了.这四门一定要学好.<br />6、我觉得现在市场的主流是j2ee和.net两大方向,无论哪个方向,都很有市场,要精通的话都不是件容易的事情:)<br />你可以选择一个方向.千万不要问别人选择什么好啊,这个问题就象问篮球好还是羽毛球好一样难回答,如果你习惯了微软的产品那么就选择.net,如果你喜欢自由,不喜欢垄断,那么你选择j2ee.多利用网络资源.要玩转网络资源,不要被网络资源给玩了:)</p>
				<p> </p>
				<p>起这个名字做标题，是为了让还在读书的朋友要珍惜眼前的时间。其实人生的道路很长，以前欠的债以后也可以还的。我的意思是迟还不如早还，早还不如不欠。不欠不如赚钱</p>
				<br />
				<br />
				<p id="TBPingURL">Trackback: <a href="http://tb.blog.csdn.net/TrackBack.aspx?PostId=675563">http://tb.blog.csdn.net/TrackBack.aspx?PostId=675563</a></p>
		</div><img src ="http://www.cppblog.com/ace/aggbug/6238.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:00 <a href="http://www.cppblog.com/ace/archive/2006/04/25/6238.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>巧用虚友元函数(原创)</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/15/5610.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Sat, 15 Apr 2006 05:09:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/15/5610.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/5610.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/15/5610.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/5610.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/5610.html</trackback:ping><description><![CDATA[面向模式的软件体系结构 卷2：用于并发和网络化对象的模式 59 46.02 1 北京送货 
面向模式的软件体系结构：卷3 29 22.62 1 北京送货 
面向模式的软件体系结构 卷1：模式系统 45 35.1 1 北京送货 
Ajax基础教程（亚马逊计算机榜首图书，国内第1本Ajax图书） 35 27.3 1 北京送货 
中国企业管理的前沿研究 48 42.24 1 北京送货<img src ="http://www.cppblog.com/ace/aggbug/5610.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-15 13:09 <a href="http://www.cppblog.com/ace/archive/2006/04/15/5610.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>转: UDP实现可靠文件传输 (转)</title><link>http://www.cppblog.com/ace/archive/2006/04/13/5465.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Thu, 13 Apr 2006 05:56:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/13/5465.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/5465.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/13/5465.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/5465.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/5465.html</trackback:ping><description><![CDATA[<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">                                     <br /><br />用UDP实现可靠文件传输<br /><br /><br />大家都清楚，如果用TCP传输文件的话，是很简单的，根本都不用操心会丢包，除非是网络坏了，就得重来。用UDP的话，因为UDP是不可靠的，所以用它传输文件，要保证不丢包，就得我们自己写额外的代码来保障了。本文就说说如果保证可靠传输。<br /><br /><br />   要实现无差错的传输数据，我们可以采用重发请求（ARQ）协议，它又可分为连续ARQ协议、选择重发ARQ协议、滑动窗口协议。本文重点介绍滑动窗口协议，其它的两种有兴趣的可参考相关的网络通信之类的书。<br /><br /><br />    采用滑动窗口协议，限制已发送出去但未被确认的数据帧的数目。循环重复使用已收到的那些数据帧的序号。具体实现是在发送端和接收端分别设定发送窗口和接收窗口。<br /><br /><br /> （1）发送窗口<br /><br /><br />  发送窗口用来对发送端进行流量控制。发送窗口的大小Wt代表在还没有收到对方确认的条件下，发送端最多可以发送的数据帧的个数。具体意思请参考下图：<br /><br /><br /> （2）接收窗口<br /><br /><br />  接收窗口用来控制接收数据帧。只有当接收到的数据帧的发送序号落在接收窗口内，才允许将该数据帧收下，否则一律丢弃。接收窗口的大小用Wr来表示，在连续ARQ协议中，Wr = 1。接收窗口的意义可参考下图：<br /><br /><br />  在接收窗口和发送窗口间存在着这样的关系：接收窗口发生旋转后，发送窗口才可能向前旋转，接收窗口保持不动时，发送窗口是不会旋转的。这种收发窗口按如此规律顺时钟方向不断旋转的协议就犯法为滑动窗口协议。<br /><br /><br />   好了，在上面对滑动窗口协议有大致了解后，我们还是进入正题吧：）<br /><br /><br />   发送端的发送线程：<br /><br /><br />   int  ret;<br /><br /><br />   int  nPacketCount = 0;<br /><br /><br />   DWORD dwRet;<br /><br /><br />   SendBuf sendbuf;<br /><br /><br />   DWORD dwRead;<br /><br /><br />   DWORD dwReadSize;<br /><br /><br /><br /><br />   SendBuf* pushbuf;<br /><br /><br /><br /><br />   //计算一共要读的文件次数，若文件已读完，但客户端没有接收完，<br /><br /><br />   //则要发送的内容不再从文件里读取，而从m_bufqueue里提取<br /><br /><br />   nPacketCount = m_dwFileSize / sizeof(sendbuf.buf);<br /><br /><br /><br /><br />  //若不能整除，则应加1<br /><br /><br />  if(m_dwFileSize % sizeof(sendbuf.buf) != 0)<br /><br /><br />     ++nPacketCount;<br /><br /><br /> SetEvent(m_hEvent);<br /><br /> <br /><br /><br /><br /><br />  CHtime htime;<br /><br /><br /><br /><br />  //若已发送大小小于文件大小并且发送窗口前沿等于后沿，则继续发送<br /><br /><br />  //否则退出循环<br /><br /><br /><br /><br /> if(m_dwSend </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000"> m_dwFileSize</span>
				<span style="COLOR: #ff0000">)  // 文件没有传输完时才继续传输<br /><br /><br /> {<br /><br /><br />  while(1)<br /><br /><br />  {<br /><br /><br />   dwRet </span>
				<span style="COLOR: #0000ff">= WaitForSingleObject(m_hEvent, </span>
				<span style="COLOR: #ff0000">1000);<br /><br /><br />   if(dwRet </span>
				<span style="COLOR: #0000ff">== </span>
				<span style="COLOR: #ff0000">WAIT_FAILED)<br /><br /><br />   {<br /><br /><br />    return false;<br /><br /><br />   }<br /><br /><br />   else if(dwRet </span>
				<span style="COLOR: #0000ff">== </span>
				<span style="COLOR: #ff0000">WAIT_TIMEOUT)<br /><br /><br />   {<br /><br /><br />    //重发<br /><br /><br />    ::EnterCriticalSection(&amp;m_csQueue);  // 进入m_bufqueue的排斥区<br /><br /><br />    ret </span>
				<span style="COLOR: #0000ff">= m_hsocket.hsendto((char*)m_bufqueue.front(), </span>
				<span style="COLOR: #ff0000">sizeof(sendbuf));<br /><br /><br />    ::LeaveCriticalSection(&amp;m_csQueue);  // 退出m_bufqueue的排斥区<br /><br /><br />    if(ret </span>
				<span style="COLOR: #0000ff">== </span>
				<span style="COLOR: #ff0000">SOCKET_ERROR)<br /><br /><br />    {<br /><br /><br />     cout &lt;&lt; "重发失败，继续重发" &lt;&lt; endl;<br /><br /><br />     continue;<br /><br /><br />    }<br /><br /><br />   ResetEvent(m_hEvent);<br /><br /> <br /><br /><br />    continue;<br /><br /><br />   }<br /><br /><br />  //若发送窗口大小 &lt; 预定大小 &amp;&amp; 已读文件次数(nReadIndex) &lt; 需要读文件的次数(nReadCount)，则继续读取发送<br /><br /> <br /><br /><br />   //否则，要发送的内容从m_bufqueue里提取<br /><br /><br />   if(m_dwSend &lt; m_dwFileSize)<br /><br /><br />   {<br /><br /><br />    dwReadSize </span>
				<span style="COLOR: #0000ff">= m_dwFileSize </span>
				<span style="COLOR: #ff0000">- m_dwSend;<br /><br /><br />    dwReadSize </span>
				<span style="COLOR: #0000ff">= dwReadSize </span>
				<span style="COLOR: #ff0000">&lt; MAXBUF_SIZE ?   dwReadSize :MAXBUF_SIZE;<br /><br /><br /><br /><br />    memset(sendbuf.buf, 0, sizeof(sendbuf.buf));<br /><br /><br />    if(!ReadFile(m_hFile, sendbuf.buf, dwReadSize, &amp;dwRead, NULL))<br /><br /><br />    {<br /><br /><br />     //AfxMessageBox("读取文件失败,请确认文件存在或有读取权限.");<br /><br /><br />     cout &lt;&lt; "读取文件失败,请确认文件存在或有读取权限." &lt;&lt; endl;<br /><br /><br />     return false;<br /><br /><br />    }<br /><br /><br /><br /><br />    m_dwSend +</span>
				<span style="COLOR: #0000ff">= dwRead;<br /><br /><br /><br /><br />    </span>
				<span style="COLOR: #ff0000">sendbuf.index </span>
				<span style="COLOR: #0000ff">= m_nSendIndexHead;<br /><br /><br />    </span>
				<span style="COLOR: #ff0000">// 发送窗口前沿向前移一格     m_nSendIndexHead </span>
				<span style="COLOR: #0000ff">= (m_nSendIndexHead </span>
				<span style="COLOR: #ff0000">+ 1) %   Sliding_Window_Size; <br /><br /><br /><br /><br />  sendbuf.dwLen </span>
				<span style="COLOR: #0000ff">= dwRead;<br /><br /> <br /><br /><br />  </span>
				<span style="COLOR: #ff0000">//保存发送过的数据，以便重发<br /><br /> <br /><br /><br />   ::EnterCriticalSection(&amp;m_csQueue);   // 进入m_bufqueue的排斥区<br /><br /><br />   pushbuf </span>
				<span style="COLOR: #0000ff">= GetBufFromLookaside();<br /><br /><br />   </span>
				<span style="COLOR: #ff0000">memcpy(pushbuf, &amp;sendbuf, sizeof(sendbuf));<br /><br /><br /><br />   m_bufqueue.push(pushbuf);<br /><br /><br /><br />   // 文件已读完，在队列中加一File_End标志，以便判断是否需要继续发送    if(m_dwSend </span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">= m_dwFileSize)    <br /><br /><br /><br />   {<br /><br /><br />     pushbuf = GetBufFromLookaside();<br /><br /><br />    pushbuf-&gt;index = File_End;<br /><br /> <br /><br /><br />     pushbuf-&gt;dwLen = File_End;<br /><br /><br />     memset(pushbuf-&gt;buf, 0, sizeof(pushbuf-&gt;buf));<br /><br /><br />     m_bufqueue.push(pushbuf);<br /><br /><br /><br />    }<br /><br /><br />    ::LeaveCriticalSection(</span>
				<span style="COLOR: #ff0000">&amp;m_csQueue</span>
				<span style="COLOR: #000000">);   // 退出m_bufqueue的排斥区<br /><br /><br />   }<br /><br /><br />   ::EnterCriticalSection(</span>
				<span style="COLOR: #ff0000">&amp;m_csQueue</span>
				<span style="COLOR: #000000">);    // 进入m_bufqueue的排斥区<br /><br /> <br /><br /><br />   // 所有数据包已发送完毕,退出循环    if(m_bufqueue.front()-&gt;index == File_End)  <br /><br /><br /><br />   {<br /><br /><br />     ::LeaveCriticalSection(</span>
				<span style="COLOR: #ff0000">&amp;m_csQueue</span>
				<span style="COLOR: #000000">);   // 退出m_bufqueue的排斥区<br /><br /><br />     break;<br /><br /><br />   }<br /><br /><br />   // 发送窗口小于指定值，继续发送    else if(m_bufqueue.size() </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">= Send_Window_Size</span>
				<span style="COLOR: #ff0000">) <br /><br /><br /><br />   {<br /><br /><br />    ret </span>
				<span style="COLOR: #0000ff">= m_hsocket.hsendto((char*)m_bufqueue.front(), </span>
				<span style="COLOR: #ff0000">sizeof(sendbuf));<br /><br /><br />    if(ret </span>
				<span style="COLOR: #0000ff">== </span>
				<span style="COLOR: #ff0000">SOCKET_ERROR)<br /><br /><br />    {<br /><br /><br />     ::LeaveCriticalSection(&amp;m_csQueue);  // 退出m_bufqueue的排斥区<br /><br /><br />     cout &lt;&lt; "发送失败，重发" &lt;&lt; endl;<br /><br /><br />     continue;<br /><br /><br />    }<br /><br /><br /><br /><br />    //延时，防止丢包<br /><br /><br />    Sleep(50);  <br /><br /><br />   }<br /><br /><br />   else           // 发送窗口大于指定值，等持接收线程接收确认消息<br /><br /><br />   {<br /><br /><br />    ResetEvent(m_hEvent);<br /><br /><br />   }<br /><br /><br />   ::LeaveCriticalSection(&amp;m_csQueue);    // 退出m_bufqueue的排斥区<br /><br /><br />  }<br /><br /><br /> }<br /><br /><br />  发送端的接收线程：<br /><br /><br /><br />  int ret;<br /><br /><br />  RecvBuf recvbuf;<br /><br /><br /><br /><br />  while(m_hFile !</span>
				<span style="COLOR: #0000ff">= NULL)<br /><br /><br />  </span>
				<span style="COLOR: #ff0000">{<br /><br /><br />    ret </span>
				<span style="COLOR: #0000ff">= m_hsocket.hrecvfrom((char*)&amp;recvbuf, </span>
				<span style="COLOR: #ff0000">sizeof(recvbuf));  <br /><br /><br />    if(ret </span>
				<span style="COLOR: #0000ff">== </span>
				<span style="COLOR: #ff0000">SOCKET_ERROR)<br /><br /><br />    {<br /><br /><br />      //AfxMessageBox("接收确认消息出错");<br /><br /><br />      ::EnterCriticalSection(&amp;m_csQueue);<br /><br /><br />      if(m_bufqueue.front()-</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">index == File_End) // 文件传输完毕<br /><br /><br />      {<br /><br /><br />         ::LeaveCriticalSection(</span>
				<span style="COLOR: #ff0000">&amp;m_csQueue</span>
				<span style="COLOR: #000000">);<br /><br /><br />         break;<br /><br /><br />       }<br /><br /><br />       ::LeaveCriticalSection(</span>
				<span style="COLOR: #ff0000">&amp;m_csQueue</span>
				<span style="COLOR: #000000">);<br /><br /><br />       cout </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">&lt; "接收确认消息出错: </span>
				<span style="COLOR: #ff0000">" &lt;&lt; GetLastError() &lt;&lt; endl;<br /><br /><br /><br />       return false;<br /><br /><br />     }<br /><br /><br />  if(recvbuf.flag </span>
				<span style="COLOR: #0000ff">== </span>
				<span style="COLOR: #ff0000">Flag_Ack &amp;&amp; recvbuf.index </span>
				<span style="COLOR: #0000ff">==    </span>
				<span style="COLOR: #ff0000">m_nSendIndexTail)<br /><br />  <br /><br /><br />   {<br /><br /><br />      m_nSendIndexTail </span>
				<span style="COLOR: #0000ff">= (m_nSendIndexTail </span>
				<span style="COLOR: #ff0000">+ 1) % Sliding_Window_Size;<br /><br /><br />      //该结点已得到确认，将其加入旁视列表，以备再用<br /><br /><br />      ::EnterCriticalSection(&amp;m_csQueue);<br /><br /><br />      m_bufLookaside.push(m_bufqueue.front());<br /><br /><br />      m_bufqueue.pop();<br /><br /><br />     ::LeaveCriticalSection(&amp;m_csQueue);<br /><br /><br />     SetEvent(m_hEvent);<br /><br /><br /><br />   }<br /><br /><br /> }<br /><br /><br /><br /><br />接收端的接收线程：<br /><br /><br /> int  ret;<br /><br /><br /> DWORD dwWritten;<br /><br /><br /> SendBuf recvbuf;<br /><br /><br /> RecvBuf sendbuf;<br /><br /><br /> int nerror </span>
				<span style="COLOR: #0000ff">= 0;<br /><br /><br /> </span>
				<span style="COLOR: #ff0000">// 设置文件指针位置，指向上次已发送的大小<br /><br /><br /><br /> SetFilePointer(m_hFile, 0, NULL, FILE_END);<br /><br /><br /> //若已接收文件大小小于需要接收的大小，则继续<br /><br /><br /><br /> while(m_dwSend &lt; m_dwFileSize)<br /><br /><br /> {<br /><br /><br />  //接收<br /><br /><br />  memset(&amp;recvbuf, 0, sizeof(recvbuf));<br /><br /><br />  ret </span>
				<span style="COLOR: #0000ff">= m_hsocket.hrecvfrom((char*)&amp;recvbuf, </span>
				<span style="COLOR: #ff0000">sizeof(recvbuf));<br /><br /><br />  if(ret </span>
				<span style="COLOR: #0000ff">== </span>
				<span style="COLOR: #ff0000">SOCKET_ERROR)<br /><br /><br />  {<br /><br /><br />   return false;<br /><br /><br />  }<br /><br /><br />  //不是希望接收的，丢弃，继续接收<br /><br /><br /><br />  if(recvbuf.index !</span>
				<span style="COLOR: #0000ff">= (m_nRecvIndex) </span>
				<span style="COLOR: #ff0000">% Sliding_Window_Size)<br /><br /><br />  {<br /><br /><br />   nerror++;<br /><br /><br />   cout &lt;&lt; recvbuf.index &lt;&lt; "error?" &lt;&lt; m_nRecvIndex &lt;&lt; endl;<br /><br /><br />   continue;<br /><br /><br />  }<br /><br /><br />  if(!WriteFile(m_hFile, recvbuf.buf, recvbuf.dwLen, &amp;dwWritten, NULL))<br /><br /><br /><br />  {<br /><br /><br />   //AfxMessageBox("写入文件失败");<br /><br /><br />   cout &lt;&lt; "写入文件失败" &lt;&lt; endl;<br /><br /><br />   return false;<br /><br /><br />  }<br /><br /><br /><br /><br />  //已接收文件大小<br /><br /><br />  m_dwSend +</span>
				<span style="COLOR: #0000ff">= dwWritten;<br /><br /><br />  </span>
				<span style="COLOR: #ff0000">//发送确认消息<br /><br /><br /><br />  sendbuf.flag </span>
				<span style="COLOR: #0000ff">= Flag_Ack;<br /><br /><br />  </span>
				<span style="COLOR: #ff0000">sendbuf.index </span>
				<span style="COLOR: #0000ff">= m_nRecvIndex;<br /><br /><br /><br /><br />  </span>
				<span style="COLOR: #ff0000">ret </span>
				<span style="COLOR: #0000ff">= m_hsocket.hsendto((char*)&amp;sendbuf, </span>
				<span style="COLOR: #ff0000">sizeof(sendbuf));<br /><br /><br />  if(ret </span>
				<span style="COLOR: #0000ff">== </span>
				<span style="COLOR: #ff0000">SOCKET_ERROR)<br /><br /><br />  {<br /><br /><br />   return false;<br /><br /><br />  }<br /><br /><br />  //接收窗口前移一格<br /><br /><br /><br />  m_nRecvIndex </span>
				<span style="COLOR: #0000ff">= (m_nRecvIndex </span>
				<span style="COLOR: #ff0000">+ 1) % Sliding_Window_Size;<br /><br /><br /> }<br /><br /><br /><br /> <br /><br /><br /> <br /></span>
		</div><img src ="http://www.cppblog.com/ace/aggbug/5465.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 13:56 <a href="http://www.cppblog.com/ace/archive/2006/04/13/5465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UML培训提纲初步</title><link>http://www.cppblog.com/ace/archive/2006/04/13/5461.html</link><dc:creator>Stone Jiang</dc:creator><author>Stone Jiang</author><pubDate>Thu, 13 Apr 2006 05:27:00 GMT</pubDate><guid>http://www.cppblog.com/ace/archive/2006/04/13/5461.html</guid><wfw:comment>http://www.cppblog.com/ace/comments/5461.html</wfw:comment><comments>http://www.cppblog.com/ace/archive/2006/04/13/5461.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ace/comments/commentRss/5461.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ace/services/trackbacks/5461.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" />
				<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" />    为什么要用UML<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" />        业界共同的问题<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" />      UML产生的背景<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />      UML的积极意义<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />      使用UML的时机<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        UML图一览<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />      不仅仅是UML<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        UP(统一过程)<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />          RUP<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />          XP<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />          FDD<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />          etc..<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" />        OO技术<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" />          基于OO的重构<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" />      第二节<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" />        分析和设计<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" />    用UML需求分析基础<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" />        文档化需求<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" />      用例技术基础<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" />        识别系统边界<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" />        撰写用例规约<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" />        用用例描述需求<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" />    用UML进行简单系统设计<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" />      顺序图基础<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" />    UML进阶<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" />  学会用基本的UML撰写和阅读设计文档<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" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
		</div>
		<br />思维导图<br /><br /><img height="1044" alt="UML培训 2.0.jpg" src="http://www.cppblog.com/images/cppblog_com/ace/UML培训%202.0.jpg" width="1053" border="0" /><img src ="http://www.cppblog.com/ace/aggbug/5461.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 13:27 <a href="http://www.cppblog.com/ace/archive/2006/04/13/5461.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>