﻿<?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++博客-swo2006-文章分类-c++</title><link>http://www.cppblog.com/swo2006/category/3198.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 23 May 2008 05:09:26 GMT</lastBuildDate><pubDate>Fri, 23 May 2008 05:09:26 GMT</pubDate><ttl>60</ttl><item><title>做一个dll时，不用def文件不行吗</title><link>http://www.cppblog.com/swo2006/articles/16292.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Mon, 11 Dec 2006 14:37:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/16292.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/16292.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/16292.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/16292.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/16292.html</trackback:ping><description><![CDATA[
		<font size="-1"> 在VC++中，如果生成DLL可以不使用.def文件。你只需要在VC++的函数定义前要加__declspec
(dllexport)修饰就可以了。但是使用__declspec(dllexport)和使用.def文件是有区别的。如果你的DLL是提供给VC+
+用户使用的，你只需要把编译DLL时产生的.lib提供给用户，它可以很轻松地调用你的DLL。但是如果你的DLL是供VB、PB、Delphi用户使
用的，那么会产生一个小麻烦。因为VC++对于__declspec(dllexport)声明的函数会进行名称转换，如下面的函数：
<br />    __declspec(dllexport) int __stdcall IsWinNT()
<br />    会转换为IsWinNT@0，这样你在VB中必须这样声明：
<br />    Declare Function IsWinNT Lib "my.dll" Alias "IsWinNT@0" () As Long
<br />    @的后面的数由于参数类型不同而可能不同。这显然不太方便。所以如果要想避免这种转换，就要使用.def文件方式。
<br />    EXPORTS后面的数可以不给，系统会自动分配一个数。对于VB、PB、Delphi用户，通常使用按名称进行调用的方式，这个数关系不大，但是对于使用.lib链接的VC程序来说，不是按名称进行调用，而是按照这个数进行调用的，所以最好给出。</font>
<img src ="http://www.cppblog.com/swo2006/aggbug/16292.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-12-11 22:37 <a href="http://www.cppblog.com/swo2006/articles/16292.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>__declspec,_stdcall,_cdecl的区别</title><link>http://www.cppblog.com/swo2006/articles/16291.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Mon, 11 Dec 2006 14:28:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/16291.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/16291.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/16291.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/16291.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/16291.html</trackback:ping><description><![CDATA[
		<br />
		<b>__declspec一般是ms对标准c++语言的扩充指令.经典的象dllexport,property(get=...)等等.不想跨平台用用不错.</b>
		<br />
		<br />
		<div id="topictb" style="margin-left: 28px;">
				<font size="2">__cdecl,__stdcall是声明的函数调用协议.主要是传参和弹栈方面的不同.一般c++用的是__cdecl,windows里大都用的是__stdcall(API)<br /><br /><br /></font>
				<h2 class="diaryTitle">函数调用规范__cdecl和__stdcall的区别一目了然（表格形式） 转载- -</h2>
				<b>Tag</b>：			    <a href="http://tag.bokee.com/tag/__cdecl" target="_blank">__cdecl</a>   			    <a href="http://tag.bokee.com/tag/__stdcall" target="_blank">__stdcall</a>   			    <a href="http://tag.bokee.com/tag/%C7%F8%B1%F0" target="_blank">区别</a>    				                                       
				 
				 <table class="MsoTableGrid" style="border: medium none ; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0"><tbody><tr style=""><td style="border: 1pt solid windowtext; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt; text-align: center;" align="center"><b style=""><span style="font-size: 10pt; font-family: SimSun;" lang="EN"></span></b> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt; text-align: center;" align="center"><b style=""><span style="font-size: 10pt; font-family: SimSun;" lang="EN">__cdecl</span></b></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt; text-align: center;" align="center"><b style=""><span style="font-size: 10pt; font-family: SimSun;" lang="EN"></span></b> </p></td><td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext rgb(212, 208, 200); border-width: 1pt 1pt 1pt medium; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt; text-align: center;" align="center"><b style=""><span style="font-size: 10pt; font-family: SimSun;" lang="EN"></span></b> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt; text-align: center;" align="center"><b style=""><span style="font-size: 10pt; font-family: SimSun;" lang="EN">__stdcall</span></b></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: rgb(212, 208, 200) windowtext windowtext; border-width: medium 1pt 1pt; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="EN">C</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">和</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">C++</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">程序的缺省调用规范</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p></td><td style="border-style: none solid solid none; border-color: rgb(212, 208, 200) windowtext windowtext rgb(212, 208, 200); border-width: medium 1pt 1pt medium; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">为了使用这种调用规范，需要你明确的加上</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">__stdcall</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">（或</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">WINAPI</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">）文字。即</span><i><span style="font-size: 9pt; font-family: SimSun;" lang="EN">return-type</span></i><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><b>__stdcall</b><i>function-name</i>[(<i>argument-list</i>)]</span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span> </p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: rgb(212, 208, 200) windowtext windowtext; border-width: medium 1pt 1pt; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">在<b style="">被</b>调用函数</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">(Callee)</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">返回<b style="">后</b>，由调用者</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">(Caller)</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">调整堆栈。</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><p> </p></span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">调用者</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p><pre><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><span style="">    </span>// call function</span></pre><pre><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><span style="">    </span>// adjust stack</span></pre><pre><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><p> </p></span></pre><pre><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">被调用函数</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></pre><pre><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><span style="">    </span>// do work</span></pre><pre><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><span style="">    </span>// return</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></pre></td><td style="border-style: none solid solid none; border-color: rgb(212, 208, 200) windowtext windowtext rgb(212, 208, 200); border-width: medium 1pt 1pt medium; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">在<b style="">被</b>调用函数</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">(Callee)</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">返回<b style="">前</b>，由<b style="">被</b>调用函数</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">(Callee)</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">调整堆栈。图示：</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><p> </p></span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">调用者</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p><pre><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><span style="">    </span></span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">// call function</span></pre><pre><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><p> </p></span></pre><pre><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">被调用函数</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></pre><pre><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><span style="">    </span>// do work</span></pre><pre><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><span style="">    </span>// adjust stack</span></pre><pre><span style="font-size: 9pt; font-family: SimSun;" lang="EN"><span style="">    </span>// return</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></pre></td></tr><tr style=""><td style="border-style: none solid solid; border-color: rgb(212, 208, 200) windowtext windowtext; border-width: medium 1pt 1pt; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">因为每个调用的地方都需要生成一段调整堆栈的代码，所以最后生成的文件较大。</span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span> </p></td><td style="border-style: none solid solid none; border-color: rgb(212, 208, 200) windowtext windowtext rgb(212, 208, 200); border-width: medium 1pt 1pt medium; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">因为调整堆栈的代码只存在在一个地方（被调用函数的代码内），所以最后生成的文件较小。</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: rgb(212, 208, 200) windowtext windowtext; border-width: medium 1pt 1pt; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">函数的参数个数可变（就像</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">printf</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">函数一样），因为只有调用者才知道它传给被调用函数几个参数，才能在调用结束时适当地调整堆栈。</span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span> </p></td><td style="border-style: none solid solid none; border-color: rgb(212, 208, 200) windowtext windowtext rgb(212, 208, 200); border-width: medium 1pt 1pt medium; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">函数的参数个数不能是可变的。</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: rgb(212, 208, 200) windowtext windowtext; border-width: medium 1pt 1pt; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">对于定义在</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">C</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">程序文件中的输出函数，函数名会保持原样，不会被修饰。</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">对于定义在</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">C++</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">程序文件中的输出函数，函数名会被修饰， </span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">MSDN</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">说</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">Underscore character (_) is prefixed to names</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">. </span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">我实际测试（</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">VC4</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">和</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">VC6</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">）下来发现好像不是那么简单。</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><b style=""><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">可通过在前面加上</span></b><b style=""><span style="font-size: 9pt; font-family: SimSun;" lang="EN">extern “C”</span></b><b style=""><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">以去除函数名修饰。也可通过</span></b><b style=""><span style="font-size: 9pt; font-family: SimSun;" lang="EN">.def</span></b><b style=""><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">文件去除函数名修饰。</span></b><b style=""><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></b></p></td><td style="border-style: none solid solid none; border-color: rgb(212, 208, 200) windowtext windowtext rgb(212, 208, 200); border-width: medium 1pt 1pt medium; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">不论是</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">C</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">程序文件中的输出函数还是</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">C++</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">程序文件中的输出函数，函数名都会被修饰。</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">对于定义在</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">C</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">程序文件中的输出函数，</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">An
underscore (_) is prefixed to the name. The name is followed by the at
sign (@) followed by the number of bytes (in decimal) in the argument
list.</span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">对于定义在</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">C++</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">程序文件中的输出函数，好像更复杂，和</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">__cdecl</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">的情况类似。</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><b style=""><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">好像只能通过</span></b><b style=""><span style="font-size: 9pt; font-family: SimSun;" lang="EN">.def</span></b><b style=""><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">文件去除函数名修饰。</span></b></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><b style=""><span style="font-size: 9pt; font-family: SimSun;" lang="ZH"></span></b><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span> </p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: rgb(212, 208, 200) windowtext windowtext; border-width: medium 1pt 1pt; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="EN">_beginthread</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">需要</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">__cdecl的线程函数地址</span></p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span> </p></td><td style="border-style: none solid solid none; border-color: rgb(212, 208, 200) windowtext windowtext rgb(212, 208, 200); border-width: medium 1pt 1pt medium; padding: 0mm 5.4pt; width: 217.55pt; background-color: transparent;" valign="top" width="290"><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="EN"></span> </p><p class="MsoNormal" style="margin: 0mm 0mm 0pt;"><span style="font-size: 9pt; font-family: SimSun;" lang="EN">_beginthreadex</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">和</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">CreateThread</span><span style="font-size: 9pt; font-family: SimSun;" lang="ZH">需要</span><span style="font-size: 9pt; font-family: SimSun;" lang="EN">__stdcall的线程函数地址</span></p></td></tr></tbody></table><br /></div>
<img src ="http://www.cppblog.com/swo2006/aggbug/16291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-12-11 22:28 <a href="http://www.cppblog.com/swo2006/articles/16291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用C写的邮件发送程序</title><link>http://www.cppblog.com/swo2006/articles/16071.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Wed, 06 Dec 2006 14:54:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/16071.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/16071.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/16071.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/16071.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/16071.html</trackback:ping><description><![CDATA[
		<p>编程环境：WinXP SP2，Visual Studio 2005 Pro</p>
		<p>参考资料：《HowTo.SMTP》，《SendMail》(NextFly写的)，《MSDN 2005》</p>
		<p>好了，废话就不说了。下面是源代码：</p>
		<div class="HtmlCode" title="点击运行该代码！" style="cursor: pointer;" onclick="preWin=window.open('','','');preWin.document.open();preWin.document.write(this.innerText);preWin.document.close();">
				<p>// SendMail.cpp : 定义控制台应用程序的入口点。<br />//</p>
				<p>＃i nclude "stdafx.h"</p>
				<p>＃i nclude &lt;stdio.h&gt; <br />＃i nclude &lt;stdlib.h&gt;<br />＃i nclude &lt;winsock2.h&gt; </p>
				<p>#pragma comment(lib, "ws2_32.lib") </p>
				<p>const char *MailData = "From: \"88250\"&lt;<a href="mailto:dl88250@126.com%3E%5Cr%5Cn">dl88250@126.com&gt;\r\n</a>" <br />      "Subject: This is only a test mail! ^^\r\n.\r\n"; </p>
				<p>
						<br />int main(int argc, char *argv[]) <br />{ <br />   <br />    WSADATA wsaData;<br /> WORD wVersionRequested = MAKEWORD(2, 2);<br />    struct hostent *pHostent = NULL; <br />    SOCKET server = INVALID_SOCKET; <br />    struct sockaddr_in service; <br />    int retConnect = 0; <br />    char Buffer[1024] = {0}; <br />     <br /> if(WSAStartup(wVersionRequested, &amp;wsaData) != 0){ <br />  printf("Error at WSAStartup()\n"); <br />  goto WSACleanup; <br />    } <br />     <br />    server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);        //Create a Socket</p>
				<p>    if(server == INVALID_SOCKET){ <br />  printf("Error at socket(): %ld\n", WSAGetLastError()); <br />        goto WSACleanup; <br />    } <br />     <br />    pHostent = gethostbyname("smtp.126.com");              //Get the Mail Server Name <br />    if(pHostent == NULL){ <br />  printf("The Host Name is Invalid...\n"); <br />        goto WSACleanup; <br />    } <br />     <br />    service.sin_family = AF_INET; <br />    memcpy(&amp;service.sin_addr.s_addr, pHostent-&gt;h_addr_list[0], pHostent-&gt;h_length);<br />    service.sin_port = htons(25);<br /> <br />    //Connect to the remote Mail Server <br />    retConnect = connect(server, (struct sockaddr*)&amp;service, sizeof(service)); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Failed to connect.\n"); <br />        goto WSACleanup; <br />    } <br />     <br />    printf("Connect to %s....\n", inet_ntoa(service.sin_addr)); <br />     <br />    //Receive Data From the Mail Server <br /> ZeroMemory(Buffer, sizeof(Buffer)); <br />    retConnect = recv(server, Buffer, sizeof(Buffer), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Failed to connect.\n");     <br />        goto WSACleanup;      <br />    }else{ <br />        printf("%s\n", Buffer); <br />    } <br />     <br />    //Send "HELO Server....\r\n" to the Mail Server <br />    retConnect = send(server, "HELO Server....\r\n", strlen("HELO Server....\r\n"), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Send HELO to the Mail Failure.\n"); <br />        goto WSACleanup; <br />    }else{ <br />    printf("HELO Server....\n");    <br />    }   <br />     <br />    //Receive Data From the Mail Server <br />    ZeroMemory(Buffer, sizeof(Buffer)); <br />    retConnect = recv(server, Buffer, sizeof(Buffer), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Failed to connect.\n");     <br />        goto WSACleanup;      <br />    }else{ <br />        printf("%s\n", Buffer); <br />    } </p>
				<p>    //Send "AUTH LOGIN\r\n" to the Mail Server <br />    retConnect = send(server, "AUTH LOGIN\r\n", strlen("AUTH LOGIN\r\n"), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Send \"AUTH LOGIN\" to Mail Failure.\n"); <br />        goto WSACleanup; <br />    }else{ <br />  printf("AUTH LOGIN\n");    <br />    }       </p>
				<p>    //Receive Data From the Mail Server <br />    ZeroMemory(Buffer, sizeof(Buffer)); <br />    retConnect = recv(server, Buffer, sizeof(Buffer), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Receive Data From Mail Server Failure.\n");     <br />        goto WSACleanup;      <br />    }else{  <br />  printf("%s\n", Buffer); <br />    } <br />   <br />    //Send UserName to the Mail Server. The UserName is Encoded by Base64. <br />    retConnect = send(server, "bGJleW9uZDRrb21h==\r\n", strlen("bGJleW9uZDRrb21h==\r\n"), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Send UserName to the Mail Failure.\n"); <br />        goto WSACleanup; <br />    }else{ <br />  printf("UserName\n");    <br />    }       <br />         <br />    //Receive Data From the Mail Server <br />    ZeroMemory(Buffer, sizeof(Buffer)); <br />    retConnect = recv(server, Buffer, sizeof(Buffer), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Receive Data From the Mail Server Failure.\n");     <br />        goto WSACleanup;      <br />    }else{<br />        printf("%s\n", Buffer); <br />    } </p>
				<p>    //Send Password to the Mail Server The Password is Encoded by Base64. <br />    retConnect = send(server, "bGJleW9uZDRrb21h=\r\n", strlen("bGJleW9uZDRrb21h=\r\n"), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Send Password to Mail Failure.\n"); <br />        goto WSACleanup; <br />    }else{ <br />  printf("Password\n");    <br />    }   <br />     <br />    //Receive Data From the Mail Server <br />    ZeroMemory(Buffer, sizeof(Buffer)); <br />    retConnect = recv(server, Buffer, sizeof(Buffer), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Receive Data From the Mail Server Failure.\n");     <br />        goto WSACleanup;      <br />    }else{<br />        printf("%s\n", Buffer); <br />    } </p>
				<p>    //Send "Mail From: " File to the Mail Server, sender's Mail Address <br />    retConnect = send(server, "MAIL FROM: &lt;<a href="mailto:lbeyond4koma@126.com%3E%5Cr%5Cn">lbeyond4koma@126.com&gt;\r\n</a>", strlen("MAIL FROM: &lt;<a href="mailto:lbeyond4koma@126.com%3E%5Cr%5Cn">lbeyond4koma@126.com&gt;\r\n</a>"), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Send \"Mail From: \" to Mail Failure.\n"); <br />        goto WSACleanup; <br />    }else{ <br />  printf("MAIL FROM: &lt;<a href="mailto:lbeyond4koma@126.com%3E%5Cn">lbeyond4koma@126.com&gt;\n</a>");    <br />    }   <br />     <br />    //Receive Data From the Mail Server <br />    ZeroMemory(Buffer, sizeof(Buffer)); <br />    retConnect = recv(server, Buffer, sizeof(Buffer), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Receive Data From Mail Server Failure.\n");     <br />        goto WSACleanup;      <br />    }else{ <br />  Buffer[retConnect] = ' '; <br />        printf("%s\n", Buffer); <br />    } </p>
				<p>    //Send "RCPT TO: " File to the Mail Server, receiver 's Mail Address <br />    retConnect = send(server, "RCPT TO: &lt;<a href="mailto:dl88250@gmail.com%3E%5Cr%5Cn">dl88250@gmail.com&gt;\r\n</a>", strlen("RCPT TO: &lt;<a href="mailto:dl88250@gmail.com%3E%5Cr%5Cn">dl88250@gmail.com&gt;\r\n</a>"), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Send \"RCPT TO: \" to Mail Failure.\n"); <br />        goto WSACleanup; <br />    }else{ <br />  printf("RCPT TO: &lt;<a href="mailto:dl88250@gmail.com%3E%5Cn">dl88250@gmail.com&gt;\n</a>");    <br />    }   <br />     <br />    //Receive Data From the Mail Server <br />    ZeroMemory(Buffer, sizeof(Buffer)); <br />    retConnect = recv(server, Buffer, sizeof(Buffer), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Receive Data From the Mail Server Failure.\n");     <br />        goto WSACleanup;      <br />    }else{ <br />        printf("%s\n", Buffer); <br />    } </p>
				<p>    //Send "Data" Fiele to the Mail Server, start to Send mail <br />    retConnect = send(server, "Data\r\n", strlen("Data\r\n"), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Send \"Data\" Field to Mail Failure...\n"); <br />        goto WSACleanup; <br />    }else{ <br />  printf("Data\n");    <br />    }   </p>
				<p>    //Receive Data From the Mail Server <br />    ZeroMemory(Buffer, sizeof(Buffer)); <br />    retConnect = recv(server, Buffer, sizeof(Buffer), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Receive Data From Mail Server Failure...\n");     <br />        goto WSACleanup;      <br />    }else{<br />        printf("%s\n", Buffer); <br />    } </p>
				<p>    //Send Mail data to the the Mail Server <br />    retConnect = send(server, MailData, strlen(MailData), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Send Context Of Mail to Mail Failure...\n"); <br />        goto WSACleanup; <br />    }else{ <br />  printf("%s\n", MailData); <br />    } </p>
				<p>    //Receive Data From the Mail Server <br />    ZeroMemory(Buffer, sizeof(Buffer)); <br />    retConnect = recv(server, Buffer, sizeof(Buffer), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Receive Data From Mail Server Failure...\n");     <br />        goto WSACleanup;      <br />    }else{ <br />        printf("%s\n", Buffer); <br />    } </p>
				<p>    //Send "QUIT" Context to the Mail Server <br />    retConnect = send(server, "QUIT\r\n", strlen("QUIT\r\n"), 0); <br />    if(retConnect == SOCKET_ERROR){ <br />  printf("Send \"Quit\" to Mail Failure...\n"); <br />        goto WSACleanup; <br />    }else{ <br />  printf("Quit\n");    <br />    }   <br />    <br />    printf("Send Mail Successful!\n"); <br />               <br /> WSACleanup:{ <br />  if(server != INVALID_SOCKET){<br />   closesocket(server);<br />        } <br />        WSACleanup();         <br /> }<br />    system("pause");<br /> return 0; <br />} </p>
		</div>
		<p>其中需要注意的是寄件人地址与邮件内容里的邮件地址的关系：</p>
		<p>寄件人的地址必须和你用的连接帐号一致。帐号和密码是使用Base64编码的（关于什么是Base64编码请到<a href="http://www.ynutx.net/blog/user1/Myth/archives/2006/1682.html">http://www.ynutx.net/blog/user1/Myth/archives/2006/1682.html</a>下面看看，它的C实现代码在下面）。。。。</p>
		<p>而在邮件内容里的地址只是一个告诉邮件服务器这封信是谁发的。可以和你所使用的发送帐号不一致！也就是说你可以伪造别人的地址进行邮件发送。。。。</p>
		<p>哎，不要干什么干事哟^_^!</p>
		<p>好了，下面就是Base64编码与解码的实现代码了：</p>
		<div class="HtmlCode" title="点击运行该代码！" style="cursor: pointer;" onclick="preWin=window.open('','','');preWin.document.open();preWin.document.write(this.innerText);preWin.document.close();">
				<p>＃i nclude &lt;stdio.h&gt;<br />＃i nclude &lt;string.h&gt;</p>
				<p>char *ch64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; </p>
				<p>unsigned char *encode(unsigned char *src, int srclen)<br />{<br /> int n, buflen, i, j;<br /> int pading = 0;<br /> unsigned char *buf;<br /> static unsigned char *dst; </p>
				<p> buf = src;<br /> buflen = n = srclen;<br /> if(n % 3 != 0){  /* pad with '=' by using a temp buffer */<br />  pading = 1;<br />  buflen = n + 3 - n % 3;<br />  buf = malloc(buflen + 1);<br />  memset(buf, 0, buflen + 1);<br />  memcpy(buf, src, n);<br />  for(i=0;i&lt;3-n%3;i++){<br />   buf[n+i] = '=';<br />  }<br /> }<br /> dst = malloc(buflen * 4 / 3 + 1);<br /> memset(dst, 0, buflen * 4 / 3 + 1);<br /> for(i = 0, j = 0; i &lt; buflen; i += 3, j += 4){<br />  dst[j] = (buf[i] &amp; 0xFC) &gt;&gt; 2;<br />  dst[j+1] = ((buf[i] &amp; 0x03) &lt;&lt; 4) + ((buf[i+1] &amp; 0xF0) &gt;&gt; 4);<br />  dst[j+2] = ((buf[i+1] &amp; 0x0F) &lt;&lt; 2) + ((buf[i+2] &amp; 0xC0) &gt;&gt; 6);<br />  dst[j+3] = buf[i+2] &amp; 0x3F; <br /> }<br /> for(i = 0; i &lt; buflen * 4 / 3; i++){ /* map 6 bit value to base64 ASCII character */<br />  dst[i] = ch64[dst[i]];<br /> }<br /> if(pading){<br />  free(buf);<br /> }<br /> return dst;<br />}</p>
				<p>unsigned char *decode(unsigned char *src)<br />{<br /> int n, i, j;<br /> unsigned char *p;<br /> static unsigned char *dst; </p>
				<p> n = strlen(src);<br /> for(i=0;i&lt;n;i++){ /* map base64 ASCII character to 6 bit value */<br />  p = strchr(ch64, src[i]);<br /> if(!p){<br />  break;<br /> }<br /> src[i] = p - ch64;<br /> }<br /> dst = malloc(n * 3 / 4 + 1);<br /> memset(dst, 0, n * 3 / 4 + 1);<br /> for(i = 0, j = 0; i &lt; n; i += 4, j += 3){<br />  dst[j] = (src[i] &lt;&lt; 2) + ((src[i+1] &amp; 0x30) &gt;&gt; 4);<br />  dst[j+1] = ((src[i+1] &amp; 0x0F) &lt;&lt; 4) + ((src[i+2] &amp; 0x3C) &gt;&gt; 2);<br />  dst[j+2] = ((src[i+2] &amp; 0x03) &lt;&lt; 6) + src[i+3];<br /> }<br /> return dst;<br />}</p>
				<p>int main()<br />{<br /> char *src = "lbeyond4koma";<br /> unsigned char *dst1;<br /> unsigned char *dst2;<br /> unsigned int i;</p>
				<p> dst1 = encode(src, strlen(src)); /* the second parameter must accord with the first one */<br /> printf("%s\n", dst1);<br /> dst2 = decode(dst1); <br /> for(i = 0; i &lt; _msize(dst2); i++){<br />  printf("%c",dst2[i]);<br /> }<br /> free(dst1);<br /> free(dst2);<br /> return 0;<br />}<br /></p>
		</div>
		<p>呵呵，终于完了。有兴趣的可以试试哦，发不了的话加我QQ：845765,或者发邮件给我：<a href="mailto:DL88250@gmail.com">DL88250@gmail.com</a> 大家一起研究学习一下！</p>
<img src ="http://www.cppblog.com/swo2006/aggbug/16071.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-12-06 22:54 <a href="http://www.cppblog.com/swo2006/articles/16071.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>memset,memcpy,等字符处理函数</title><link>http://www.cppblog.com/swo2006/articles/16061.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Wed, 06 Dec 2006 11:25:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/16061.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/16061.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/16061.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/16061.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/16061.html</trackback:ping><description><![CDATA[
		<pre>  原型：extern void *memset(void *buffer, int c, int count);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：把buffer所指内存区域的前count个字节设置成字符c。<br /><br />  说明：返回指向buffer的指针。<br /><br /><br />  原型：extern int memcmp(void *buf1, void *buf2, unsigned int count);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：比较内存区域buf1和buf2的前count个字节。<br /><br />  说明：<br />        当buf1&lt;buf2时，返回值&lt;0<br />        当buf1=buf2时，返回值=0<br />        当buf1&gt;buf2时，返回值&gt;0<br /><br />  原型：extern void *memmove(void *dest, const void *src, unsigned int count);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：由src所指内存区域复制count个字节到dest所指内存区域。<br /><br />  说明：src和dest所指内存区域可以重叠，但复制后src内容会被更改。函数返回指向dest的指针。<br /><br />  原型：extern void *memcpy(void *dest, void *src, unsigned int count);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：由src所指内存区域复制count个字节到dest所指内存区域。<br /><br />  说明：src和dest所指内存区域不能重叠，函数返回指向dest的指针。<br /><br />  原型：extern void *memchr(void *buf, char ch, unsigned count);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：从buf所指内存区域的前count个字节查找字符ch。<br /><br />  说明：当第一次遇到字符ch时停止查找。如果成功，返回指向字符ch的指针；否则返回NULL。<br /><br /><br />  原型：extern char *stpcpy(char *dest,char *src);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：把src所指由NULL结束的字符串复制到dest所指的数组中。<br /><br />  说明：src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。<br />        返回指向dest结尾处字符(NULL)的指针。<br /><br /><br />  原型：extern char *strcat(char *dest,char *src);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。<br /><br />  说明：src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。<br />        返回指向dest的指针。<br /><br /><br />  原型：extern char *strchr(char *s,char c);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：查找字符串s中首次出现字符c的位置<br /><br /><br />  原型：extern int strcmp(char *s1,char * s2);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：比较字符串s1和s2。<br /><br />  说明：<br />        当s1&lt;s2时，返回值&lt;0<br />        当s1=s2时，返回值=0<br /><br /><br />  原型：extern char *strcpy(char *dest,char *src);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：把src所指由NULL结束的字符串复制到dest所指的数组中。<br /><br />  说明：src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。<br /><br /><br />  原型：extern char *strset(char *s, char c);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：把字符串s中的所有字符都设置成字符c。<br /><br /><br />  原型：extern char *strcat(char *dest,char *src);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。<br /><br />  说明：src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。<br />        返回指向dest的指针。<br />  说明：返回指向s的指针。<br />        返回指向dest的指针。<br />        当s1&gt;s2时，返回值&gt;0<br />  说明：返回首次出现c的位置的指针，如果s中不存在c则返回NULL。<br /><br /><br />  原型：extern int strlen(char *s);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：计算字符串s的长度<br /><br />  原型：extern char *strlwr(char *s);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：将字符串s转换为小写形式<br /><br /><br /><br />  原型：extern int strnicmp(char *s1,char * s2，int n);<br /><br />  用法：#include &lt;string.h&gt;<br /><br />  功能：比较字符串s1和s2的前n个字符但不区分大小写。<br /><br />  说明：strncmpi是到strnicmp的宏定义<br />        当s1&lt;s2时，返回值&lt;0<br />        当s1=s2时，返回值=0<br />        当s1&gt;s2时，返回值&gt;0<br /><br />  说明：只转换s中出现的大写字母，不改变其它字符。返回指向s的指针。<br /><br />  说明：返回s的长度，不包括结束符NULL。<br /></pre>
<img src ="http://www.cppblog.com/swo2006/aggbug/16061.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-12-06 19:25 <a href="http://www.cppblog.com/swo2006/articles/16061.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言高效编程的四大绝招</title><link>http://www.cppblog.com/swo2006/articles/15750.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 28 Nov 2006 13:29:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/15750.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/15750.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/15750.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/15750.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/15750.html</trackback:ping><description><![CDATA[http://www.itzhe.cn/Programme/HTML/81354.html<img src ="http://www.cppblog.com/swo2006/aggbug/15750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-28 21:29 <a href="http://www.cppblog.com/swo2006/articles/15750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Modern C++ Design》Loki库源码读解随想</title><link>http://www.cppblog.com/swo2006/articles/15277.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Fri, 17 Nov 2006 01:16:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/15277.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/15277.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/15277.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/15277.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/15277.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: center;" align="center">
				<font face="Courier New" size="3">
						<span style="font-family: 宋体;">《</span>
						<span lang="EN-US">Modern C++ Design</span>
						<span style="font-family: 宋体;">》</span>
						<span lang="EN-US">Loki</span>
						<span style="font-family: 宋体;">库源码读解随想</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New" size="3">
						<span style="font-family: 宋体;">大牛</span>
						<span lang="EN-US">Andrei Alexandrescu</span>
						<span style="font-family: 宋体;">的《</span>
						<span lang="EN-US">Modern C++ Design</span>
						<span style="font-family: 宋体;">》讨论的是</span>
						<span lang="EN-US">C++</span>
						<span style="font-family: 宋体;">语言的最前沿研究：</span>
				</font>
				<font face="Courier New">
						<b>
								<span style="font-size: 11pt; font-family: 宋体;" lang="EN-US">generative programming</span>
						</b>
						<span style="font-size: 11pt; font-family: 宋体;">。本书中译版估计得要半年以后才能出来，所以只能靠其所附源码来窥测<b><span lang="EN-US">generative programming</span></b>了。<span lang="EN-US"><o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span style="font-size: 11pt; font-family: 宋体;">目前，我刚将源码读解了约一半，等全部读完，我会将我的读解注释放出来的。现在，现谈一下我的感想。<span lang="EN-US"><o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: 12pt; text-align: left;" align="left">
				<font face="Courier New">
						<span style="font-size: 10pt; font-family: 宋体;" lang="EN-US">
								<span style="">    </span>先扯得远一点。C++有两个巨大优点：和C兼容，自由；有两个巨大缺点：和C兼容，复杂。C++极其复杂，很难掌握，而这正是“自由”的代价。C++语言是个多编程风格的语言，它同时支持</span>
						<b>
								<span style="font-size: 11pt; font-family: 宋体;">过程化、基于对象、面向对象、泛型、生成性</span>
						</b>
						<span style="font-size: 11pt; font-family: 宋体;">这<span lang="EN-US">5种编程思想，具有极其强大的表达能力，可以方便地将各种设计转化为实现。</span></span>
						<span style="font-size: 10pt; font-family: 宋体;" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<b>
								<span style="font-size: 11pt; font-family: 宋体;" lang="EN-US">generic Programming</span>
						</b>
						<span style="font-size: 11pt; font-family: 宋体;">的思想精髓是<b>基于接口编程</b>（相对于<span lang="EN-US">OOP，连<b>多态</b>所需的基类都不要了），它的技术出发点是<b>选择子</b>，核心技术是：<b>类型推导、类型萃取、特化/偏特化</b>，其成果是STL库：一组通用容器和一组操作于通用容器上的通用算法。<o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<b>
								<span style="font-size: 11pt; font-family: 宋体;" lang="EN-US">generative programming</span>
						</b>
						<span style="font-size: 11pt; font-family: 宋体;">的思想精髓是<b>基于策略编程</b>（编译器根据策略自动生成所需代码，由于具有更高的抽象性，所以代码复用度也更高），在<span lang="EN-US">Loki库的实现中，目前只使用了<b>递归</b>策略，它的技术出发点是<b>Typelist</b>，核心技术是：<b>类型推导、类型萃取、特化/偏特化、多重继承、类型间去耦合</b>，其成果是Loki库：对<b>设计模式</b>的封装。<o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<b>
								<span style="font-size: 11pt; font-family: 宋体;" lang="EN-US">Typelist</span>
						</b>
						<span style="font-size: 11pt; font-family: 宋体;">是一种对类型本身进行存储和管理的技巧，它的源码已经贴过了，我也作了注解，此处不再谈论。<span lang="EN-US"><o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span style="font-size: 11pt; font-family: 宋体;">这是<b>多重继承</b>在<b><span lang="EN-US">COM</span></b>之后的又一大型运用。<b>多重继承</b>极易发生<b>菱型缺陷</b>，所以<span lang="EN-US">Loki库使用了<b>类型间去耦合</b>技术来避免：<o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span lang="EN-US">
								<font size="3">
										<span style="">    </span>template &lt;typename T&gt;</font>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span lang="EN-US">
								<font size="3">
										<span style="">    </span>struct Type2Type</font>
						</span>
				</font>
		</p>
		<p class="MsoNormalIndent" style="margin: 0cm 0cm 0pt;">
				<font face="Courier New">
						<span lang="EN-US">
								<font size="3">
										<span style="">    </span>{</font>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span lang="EN-US">
								<font size="3">
										<span style="">        </span>typedef T OriginalType;</font>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span lang="EN-US">
								<font size="3">
										<span style="">    </span>};</font>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New" size="3">
						<span style="font-family: 宋体;">经过这样一层转换后，原类型</span>
						<span lang="EN-US">T</span>
						<span style="font-family: 宋体;">间的各种转换关系（尤其是继承</span>
						<span lang="EN-US">/</span>
						<span style="font-family: 宋体;">派生关系）已不复存在，</span>
				</font>
				<font face="Courier New">
						<b>
								<span style="font-size: 11pt; font-family: 宋体;">菱型缺陷</span>
						</b>
						<span style="font-size: 11pt; font-family: 宋体;">不会再发生了。<span lang="EN-US"><o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span style="font-size: 11pt; font-family: 宋体;" lang="EN-US">Loki库的具体实现相当讲究技巧，设计它非常困难（难度远大于STL库，和Boost库有得一拼啊）。但使用它却非常容易，而且便利显著。由于Loki库提供了对<b>设计模式</b>的封装，所以极大量地丰富了C++语言的表达能力，使的你的设计更容易地转化为实现。<o:p></o:p></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span style="font-size: 11pt; font-family: 宋体;">目前，<span lang="EN-US">Loki库只提供了对厂模式和visitor模式的封装，它还处于发展初期。<o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span style="font-size: 11pt; font-family: 宋体;">我以<span lang="EN-US">visitor模式为例，讲解Loki库提供的便利。<o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span style="font-size: 11pt; font-family: 宋体;" lang="EN-US">Visitor
模式有四种实现方式：1一串RTTI的类型判断；2二次调度（double
dispatch）；3建立类型与处理函数的对应表；4非循环visitor（Acyclic Visitor）。在《More Effective
C++》 Item 31中讨论了前3种实现（虽然它的例子本身不太算visitor模式的）。第四种方式在《使用设计模式改善程序结构》（二）（</span>
						<b>
								<span style="font-size: 14pt; color: black; font-family: 宋体;" lang="EN-US">http://www-900.ibm.com/developerWorks/cn/java/l-dpstruct/part2/index.shtml</span>
						</b>
						<span style="font-size: 11pt; font-family: 宋体;">）中有详细讲解。<span lang="EN-US"><o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<font face="Courier New">
						<span lang="EN-US">
								<v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
										<v:stroke joinstyle="miter">
										</v:stroke>
										<v:formulas>
												<v:f eqn="if lineDrawn pixelLineWidth 0">
												</v:f>
												<v:f eqn="sum @0 1 0">
												</v:f>
												<v:f eqn="sum 0 0 @1">
												</v:f>
												<v:f eqn="prod @2 1 2">
												</v:f>
												<v:f eqn="prod @3 21600 pixelWidth">
												</v:f>
												<v:f eqn="prod @3 21600 pixelHeight">
												</v:f>
												<v:f eqn="sum @0 0 1">
												</v:f>
												<v:f eqn="prod @6 1 2">
												</v:f>
												<v:f eqn="prod @7 21600 pixelWidth">
												</v:f>
												<v:f eqn="sum @8 21600 0">
												</v:f>
												<v:f eqn="prod @7 21600 pixelHeight">
												</v:f>
												<v:f eqn="sum @10 21600 0">
												</v:f>
										</v:formulas>
										<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect">
										</v:path>
										<o:lock v:ext="edit" aspectratio="t">
										</o:lock>
								</v:shapetype>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: center;" align="center">
				<font face="Courier New">
						<span style="font-family: 宋体;">
								<font size="3">
										<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US">
												<v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
														<img alt="" src="http://www.csdn.net/develop/article/images/14522_1.jpg" align="bottom" border="0" hspace="0" /> </v:shapetype>
										</span>
								</font>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: center;" align="center">
				<font face="Courier New">
						<span style="font-family: 宋体;">
								<font size="3">
										<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US">
												<v:shapetype coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
														<v:stroke joinstyle="miter">
														</v:stroke>
														<v:formulas>
																<v:f eqn="if lineDrawn pixelLineWidth 0">
																</v:f>
																<v:f eqn="sum @0 1 0">
																</v:f>
																<v:f eqn="sum 0 0 @1">
																</v:f>
																<v:f eqn="prod @2 1 2">
																</v:f>
																<v:f eqn="prod @3 21600 pixelWidth">
																</v:f>
																<v:f eqn="prod @3 21600 pixelHeight">
																</v:f>
																<v:f eqn="sum @0 0 1">
																</v:f>
																<v:f eqn="prod @6 1 2">
																</v:f>
																<v:f eqn="prod @7 21600 pixelWidth">
																</v:f>
																<v:f eqn="sum @8 21600 0">
																</v:f>
																<v:f eqn="prod @7 21600 pixelHeight">
																</v:f>
																<v:f eqn="sum @10 21600 0">
																</v:f>
														</v:formulas>
														<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect">
														</v:path>
														<o:lock v:ext="edit" aspectratio="t">
														</o:lock>
												</v:shapetype>
										</span>原型图</font>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New" size="3">
						<span style="font-family: 宋体;">以这张原型图而言，用户需要自己实现大量的代码，而且，由于使用多重继承技术，在具体</span>
						<span lang="EN-US">Host</span>
						<span style="font-family: 宋体;">类间有继承关系时，它一定会发生问题。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: center;" align="center">
				<font face="Courier New">
						<span lang="EN-US">
								<font size="3">
										<span style="">
										</span>
								</font>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: center;" align="center">
				<font face="Courier New">
						<span lang="EN-US">
								<font size="3">
										<span style="">
												<img alt="" src="http://www.csdn.net/develop/article/images/14522_2.jpg" align="bottom" border="0" hspace="0" /> </span>Loki</font>
						</span>
						<span style="font-family: 宋体;">
								<font size="3">库实现图</font>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New">
						<span lang="EN-US">
								<font size="3"> <o:p></o:p></font>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font face="Courier New" size="3">
						<span style="font-family: 宋体;">使用</span>
						<span lang="EN-US">Loki</span>
						<span style="font-family: 宋体;">库，用户实现</span>
						<span lang="EN-US">visitor</span>
						<span style="font-family: 宋体;">模式时只需：让</span>
						<span lang="EN-US">Host</span>
						<span style="font-family: 宋体;">类从</span>
						<span lang="EN-US">BaseVisitable</span>
						<span style="font-family: 宋体;">继承，并在所有派生类中加上</span>
						<span lang="EN-US">DEFINE_VISITABLE()</span>
						<span style="font-family: 宋体;">宏，让所有</span>
						<span lang="EN-US">Visitor</span>
						<span style="font-family: 宋体;">类从</span>
						<span lang="EN-US">BaseVisitor</span>
						<span style="font-family: 宋体;">类和</span>
						<span lang="EN-US">VisitorImpl</span>
						<span style="font-family: 宋体;">类进行二重继承（并且可以只提供对自己感兴趣的</span>
						<span lang="EN-US">Host</span>
						<span style="font-family: 宋体;">类的处理函数，不感兴趣的不提供处理函数）。用户的工作量非常小、非常简单，设计人员可以不用为实现而分心了。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<font face="Courier New">
								<span style="font-family: 宋体;">更重要的是，由于采用了<b>类型间去耦合</b>技术，多个</span>
								<span lang="EN-US">Host</span>
								<span style="font-family: 宋体;">之间存在继承关系时，不会发生问题（其具体实现较复杂，于是我在</span>
								<span lang="EN-US">UML</span>
								<span style="font-family: 宋体;">图上作了模糊处理，没有展示出来，留在以后</span>
								<span lang="EN-US">Loki</span>
						</font>
						<span style="font-family: 宋体;">库源码读解时讲述）。</span>
				</font>
		</p>
<img src ="http://www.cppblog.com/swo2006/aggbug/15277.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-17 09:16 <a href="http://www.cppblog.com/swo2006/articles/15277.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>闲谈C++算法封装：穷举法</title><link>http://www.cppblog.com/swo2006/articles/14822.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 07 Nov 2006 14:26:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/14822.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/14822.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/14822.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/14822.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/14822.html</trackback:ping><description><![CDATA[
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt; text-align: center;" align="center">
				<b style="">
						<span style="">
								<font size="3">
										<font face="宋体">闲谈<span lang="EN-US">C++算法封装：穷举法<o:p></o:p></span></font>
								</font>
						</span>
				</b>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>将
算法独立抽象出来，在C++中算不上新鲜：STL中就封装了不少高效、健壮、灵活的泛型组件及对应的基础算法，工艺之高、适用性之强，非寻常我辈所轻易能
及。这里不打算（也暂没有能力打算）以STL这样的工业级要求来谈论算法封装，只因最近尝翻大师名著，阅者水平有限，仅嗅触至皮毛，理智薄弱，感情却蓬勃
发展：也欲尝试“封装”的味道。选择了最简易的穷举算法，抽其骨架，炮制成class，套上一实际例子，观之run之，抽象程度颇低，效率损失弥彰；然却
也自觉有可爱之处，遂作此文以记之。诚惶诚恐，便于名目之前加“闲谈”二字，倘果因技术问题招致痛骂，则试以此二字为护文符，聊且一挡。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>众所周知，穷举法可视为最简单的搜索：即是在一个可能存在可行状态（可行解）的状态全集中依次遍历所有的元素，并判断是否为可行状态。例如，要设计一个“从一堆苹果中找出蓝色的苹果”这样的穷举算法，则定义：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>(1) 状态全集：一堆苹果<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>(2) 可行状态：蓝色的苹果<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>噢，
好，我们现在已经抽取了两个基本概念，迫不及待要开始穷举了，但……怎么做呢？穷举的关键是“依次遍历”，即做到不重、不漏。呃，我们可以让听话的苹果们
排成一行，放在“苹果数组”中，然后呢，我们就可以按照0号苹果、1号苹果、2号苹果、...、n号苹果这样的顺序成功遍历。好，我们解决了遍历苹果的问
题……慢，我们现在是设计一个算法的抽象模型，如果一切待穷举的对象都已经活生生地摆在那里，当然有可能把它们全部收集起来并排队，但如果开始的时候我们
并不知道所有要穷举的对象，比如我们或许要通过一台安装在探测飞船内的计算机在全宇宙范围内穷举出除地球以外有生命的星球，那么我们的计算机可能是随着飞
船的前行方能不断地得到新星球的信息，而不是停在地球的时候就获得全宇宙的星球信息（就算可能，内存或许也装不下如此大的数据量——哪怕宇宙真的是有限
“大”的）。所以我们不应当要求穷举进行之前就能获得状态全集中的所有状态，这样一来，我们的“苹果数组”计划就宣告流产了。现在再看看我们激动人心的星
球搜索计划：它并没有把所有星球收罗排队，那么它成功的关键在哪里？在于飞船能否以适当的路径“光顾”完所有的星球；我们把这个条件加强一下：飞船每次到
达一个星球，都会看到星球上立着一个方向标，标示下一个星球的方位；而假定这样的标示保证飞船能够不重不漏地飞临宇宙中的所有星球。啊喔……你是不是觉得
我这是在异想天开？哦，没关系，大不了我们不搜索星球了，而除此之外的很多现实穷举问题都可以满足这个加强条件。嗯，我承认本文讨论的是满足这个加强条件
的稍稍狭义的穷举：它必须保证在知道一个状态的前提下能获得一个新状态，并且这样的“状态链”刚好能遍历整个状态全集。我们称从当前状态获得并转到下一个
状态的过程为“状态跳转”（我是想用“状态转移”的，嗨，可惜它会与动态规划算法的术语相混淆）：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>(3) 状态跳转：根据当前得到的苹果，按一定的“遍历算法”取得下一个苹果；这个算法保证不重不漏地取遍苹果堆中的所有苹果，只要所取的第一个苹果也是按算法定义给出的<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>很显然，对于不同的穷举任务，都会有不同的遍历算法，所以这样一来我们就得将其实现下放给调用我们“穷举算法库”的用户们了。不过考虑到这的确是由于问题的多样性所决定的，因而这个要求应当是合理的。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>嗯啊，现在我们已经有了苹果源，目标苹果，乃至遍历苹果的方案（用户提供），接下来还差一个判断标准，这个倒简单了：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>(4) 判断标准：当前苹果是否为蓝色的苹果<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>下一步，我们就可以考虑“the class of 穷举算法”的具体实现了。我们把这个class的名字定义为WalkThrough.<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>首
先，让我们注意到，“状态”是一个很重要的概念：不同的穷举问题都有彼此不同的状态，在苹果问题中，“状态”是苹果，它包含了苹果颜色或者更多的信息；而
在星球搜索计划中，“状态”则是星球，它可能包含该星球的体积、平均密度、温度、是否有大气、是否探测到水、星表活动状况等一系列丰富得惊人的信息。因
此，不同状态(state)对应不同的数据类型，要让WalkThrough能处理它们，有必要使用模板，于是我们的最初定义如下：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">template &lt;class State&gt;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">class WalkThrough<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">};<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>万
事开头难，但现在我们显然已经开了一个不错的头，嗯，继续。在考虑具体实现之前，先幻想一下我们的WalkThrough能为用户提供怎样的服务——当
然，它的本职工作是找到并返回可行状态，因此它似乎应该有一个类似于getFilter()的成员函数。问题是，如果可行状态不止一个时，
getFilter()应当返回一个可行状态还是所有的可行状态？不难想象，返回所有可行状态的作法并不太现实，因为：1.有时候用户只需要一个，或者少
数几个可行状态，此时把所有的可行状态都穷举出来显然是低效而不必要的；2.甚至，有些问题的可行状态数量是无限的，如穷举素数，此时返回所有状态当然不
可能。同时考虑到用户要求的仍有可能是不止一个可行解，我们现在知道，应当提供一个getNextFilter()而不是getFilter()的函数：
第一次调用它时，将返回从初始状态开始，依序遍历到的第一个可行状态；而此后的调用都将以上次调用为起点继续向前遍历，返回下一个可行状态。需要注意的
是，如果已经遍历完了状态全集，显然再调用此函数是没有意义的，所以它应当返回一个标志，反馈给用户是否遍历已经完成。我们将这个函数定义为bool，如
果调用有效，则返回true，反之如果已经完成遍历，则返回false.
显然，我们相应需要一个私有的State对象变量curState，它用于存储当前的状态值。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>我
们是否应当给getNextFilter加上一个State引用参数，以向用户返回每次穷举到的可行状态？在这里我们并没有这样做。试想，可能用户会想获
得第5个遍历到的可行状态，那么他当然就要调用5次getNextFilter()，但前4次他并不要求得到所搜索到的可行状态。所以，我们将“找到下一
个可行状态”与“获得当前找到的可行状态”分离开来，新增加一个getState()成员函数，它返回一个State对象，注意到getState()操
作并不影响WalkThrough对象的内部状态，所以它同时应被声明为const成员函数。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>相
应地，我们需要一个setState()成员函数，它用于改变当前的状态值，例如设置初始状态的时候都有可能用到。它带一个const
State&amp;类型的参数，用以指定所要设定的State值，由于State可能是一个较大的类型，所以使用引用传递能保证效率，同时加上
const限制则保证该函数不会更改所传入的引用对象本身的值。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>同
时用户可能需要知道，对于一个穷举对象，是否已经完成穷举，当然他可以调用getNextFilter()并检查返回值，但如果遍历没有完成，则
getNextFilter()除了最后返回true之外还会额外地进行搜索，并将当前状态改为下一个可行状态，这份额外的工作可能并不是用户所期望需要
的。因此我们将增加一个成员函数isOver()，它不带参数，返回一个bool值：如果已经完成遍历，返回true，反之返回false.
相应地，我们需要一个私有bool变量overFlag，它用于存储isOver()所需要的状态值。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>至此，WalkThrough的定义如下：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">template&lt;class State&gt;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">class WalkThrough<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">public:<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>void setState(const State&amp; s) { curState = s; }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>State getState() const { return curState; }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>bool getNextFilter();<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>bool isOver() const { return overFlag; }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">private:<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>State curState;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>bool overFlag;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">};<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>我
们把构造函数与析构函数置后，先考虑起关键作用的getNextFilter()的实现。首先，getNextFileter()由当前的状态跳转为下一
状态，然后判断新状态是否为可行，若可行，则停止跳转并返回true，否则继续跳转，重复上述步骤。另一方面，如果已经完成了遍历而还没有找到可行状态，
则将overFlag设为false并且返回false.<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>我
们将跳转操作、判断是否为可行状态操作下放给用户实现：用户相应提供两个函数，然后向WalkThrough对象传入函数指针，供
getNextFileter()调用。那么这两个函数应该采用什么样的接口形式比较合适呢？先看看跳转函数，一个很直观的实现是传入一个State对象
（或其const引用），然后返回“下一个”State对象，不过至少在返回的时候，值传递会产生State对象的复制操作（诸如NRV优化之类的语言标
准外的特定编译器实现不在讨论之列），当State对象比较大的时候，开销是不值得的。我们应当考虑传入State对象的引用，然后“全权委托”跳转函数
进行直接修改——把它“变”成下一个状态。可能会有人质疑这样做是否违反了封装原则，但即使摒弃效率方面的权衡，这样做也是合情合理的。跳转函数——不妨
视为负责“状态转化”函数，就像一个炼丹炉——有权利、甚至有义务这样做，它的职责是“转化状态”而非“获得状态”。唔……我都觉得自己在语言上过于细究
了。嗯，除了转化状态，跳转函数在发现遍历完成之后也应当及时告知调用它的getNextFilter()，否则下放了大部分权力的
getNextFilter()是无从知晓的。于是我们的跳转函数接口为：接受一个State的引用，返回一个bool值。如果遍历没有完成，那么函数执
行完毕之后State引用将变为它的后继状态，且函数返回true；否则State不变，函数返回false.<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>判断是否为可行状态的函数接口则很好定义了：它接受一个const State型引用作为待判断的状态，返回bool值，其中true表示该状态为可行状态，false表示该状态不是可行状态。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>我们将跳转函数以及判断函数的函数指针类型分别定义为StateJumper及Matcher，由于用户可能也会用到这些函数指针类型，我们将定义加到public域中：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">public:<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>typedef bool (*StateJumper)(State&amp;);<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>typedef bool (*Matcher)(const State&amp;);<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">// others...<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>并且，在private域中相应加上StateJumper和Matcher的函数指针变量，存储用户提供的相应函数的地址：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">private:<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>// others...<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>StateJumper Jumper;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>Matcher IsMatch;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>相应地，内联定义公有成员函数：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>void setJumper(const StateJumper j) { Jumper = j; }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>void setMatcher(const Matcher m) { IsMatch = m; }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>分别用于设置Jumper和IsMatch的函数指针值。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>现在所有的成员变量都已经浮出水面，我们可以定义构造函数和析够函数了，我们不打算对WalkThrough的创建与继承等方面作限制，因此它们都加在public域中。先看构造函数，有必要定义一个默认构造函数：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>WalkThrough(): overFlag(false), Jumper(0), IsMatch(0) { }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>这个构造函数不指定任何初始条件，包括当前状态。可以在需要的时候使用一系列的set成员函数定义。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>接下来定义一个“全功能”的构造函数：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>WalkThrough(const State&amp; s, StateJumper j = 0, Matcher m = 0)<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>: overFlag(false), curState(s), Jumper(j), IsMatch(m) { }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>除了overFlag外，所有的属性都可以在这个构造函数中设定（当然，它允许缺省值）。由于没有进行任何穷举操作，将overFlag强制为false是合理的。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>对
于拷贝构造函数，由于我们这里没有涉及内存分配，没有“深拷贝”的需求，因此不作定义，使用默认的位拷贝可以有不错的效率。类似地，析构函数也没有什么事
务需要处理，不过考虑到这个WalkThrough可能用于继承，且有可能出现delete基类指针来删除派生对象的情况，便定义一个空的虚析构函数，以
免引起错误：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>virtual ~WalkThrough() { }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>最后，我们来实现唯一的一个非内联函数：getNextFilter()，在给出实现之前顺便给出完整的WalkThrough的定义：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">template &lt;class State&gt;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">class WalkThrough<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">public:<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>typedef bool (*StateJumper)(State&amp;);<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>typedef bool (*Matcher)(const State&amp;);<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>WalkThrough(): overFlag(false), Jumper(0), IsMatch(0) { }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>WalkThrough(const State&amp; s, StateJumper j = 0, Matcher m = 0)<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>: overFlag(false), curState(s), Jumper(j), IsMatch(m) { }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>virtual ~WalkThrough() { }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>void setJumper(const StateJumper j) { Jumper = j; }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>void setMatcher(const Matcher m) { IsMatch = m; }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>void setState(const State&amp; s) { curState = s; }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>State getState() const { return curState; }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>bool getNextFilter();<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>bool isOver() const { return overFlag; }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">private:<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>State curState;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>bool overFlag;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>StateJumper Jumper;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>Matcher IsMatch;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">};<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">template &lt;class State&gt;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">bool WalkThrough&lt;State&gt;::getNextFilter()<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>if (overFlag)<span style="">  </span>// 若已完成遍历，则直接返回<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>return false;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>if (!Jumper || !IsMatch)<span style="">  </span>// 若用户未定义Jumper或IsMatch函数，则返回<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>
										<span style="">    </span>overFlag = true;<span style="">  </span>// 这里将没有定义Jumper或IsMatch的穷举视为遍历完成<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>
										<span style="">    </span>return false;<span style="">     </span>// 不过，如果你认为两者绝不能等同，也可以抛出异常<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>}<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>while (!(overFlag = !Jumper(curState)) &amp;&amp; !IsMatch(curState))<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>;<span style="">  </span>// 获取下一状态，直到找到可行状态或者遍历完成<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>if (overFlag)<span style="">   </span>// 根据遍历完成情况决定返回值<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>
										<span style="">    </span>return false;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">   </span>
										<span style=""> </span>else<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>
										<span style="">    </span>return true;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">}<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>呼……小功告成，总算可以小松一口气。不过如果到此就关闭计算机，就像直播球赛进行到高潮时突然停电一样，太令人不爽。——弄了这么久，总该给个example试一试，来点成就感吧？<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>没
问题。苹果问题太简单，于是我们选择的是一个传说中的“和是50”超级难题，什么是“和是50”超级难题？请听好了：所谓“和是50”超级难题，就是在0
到99的整数组成的一个加法算式中，找出和是50的算式，考虑加数顺序，像0+50啊，1+49啊，……，49+1啊，50+0啊……（喂，我知道你可能
想杀人，但请不要让与之匹配的眼光朝着我……）对于这样一个超级难题，我们经过研究，决定采用……穷举法来实现（哪来的这么多西红柿？）。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>首先我们研究这个问题的状态是什么——两个加数，不是么，它们是有顺序的，并且可以取0到99的整数。于是乎，我们定义状态类如下（注：STL中有类似的东西，但作为完整的示例，我们亲自手工打造）：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">class Pair<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">public:<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>Pair(int mx = 0, int my = 0): x(mx), y(my) { }<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>int x, y;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">};<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>Pair虽然属于世界上最深奥的class之一，然而凭各位的智慧，我就不用多解释了。接着我们来看一下跳转函数的实现——当然，它应当符合WalkThrough中定义的StateJumper类型：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">bool counter(Pair&amp; pair)<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>if (pair.y &lt; 99)<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>++pair.y;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>else<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>if (pair.x &lt; 99)<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>
										<span style="">    </span>++pair.x;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>
										<span style="">    </span>pair.y = 0;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>}<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>else<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>
										<span style="">    </span>return false;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>}<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>return true;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">}<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>counter
的作用是试图将pair.y增1，但如果pair.y已经到达上限99，则将pair.x加1，同时pair.y置0继续下一轮；但如果pair.x也到
了99，那么，噢，说明遍历结束了。——嗯，这样的确是一种有效的遍历方式，对吧。它实际上类似于下面的二重循环：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>for (; pair.x &lt;= 99; ++pair.x)<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">        </span>for (pair.y = 0; pair.y &lt;= 99; ++pair.y)<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">             </span>...<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>只不过循环要求在循环体内解决一切问题，而我们“解决一切问题”的重任担在了另一个函数里，counter不能越权，因而不能这样直接使用循环。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>接下来是判断是否为有效状态的函数，它最简单了：<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">bool match(const Pair&amp; pair)<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>return (pair.x + pair.y) == 50;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">}<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>万事俱备，可以写main:<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">int main()<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">{<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>WalkThrough&lt;Pair&gt; sf50(Pair(0, -1), &amp;counter, &amp;match);<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>while (sf50.getNextFilter())<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>cout &lt;&lt; sf50.getState().x &lt;&lt; " + " <o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>
										<span style="">     </span>&lt;&lt; sf50.getState().y &lt;&lt; " = 50" &lt;&lt; endl;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>return 0;<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">}<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="宋体" size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>请
一定要注意，getNextFilter()中有一个"Next"，也就是说，如果把状态全集中的第一个状态作为构造的参数，——本题中就是Pair
(0, 0)——是可行状态的话，getNextFilter()将不会判断到，它直接判断“下一个”状态，就是Pair(0,
1)去了。为了让它能够完整地判断，我们不能让Pair(0,
0)作为第一个状态，而是作为首次运行getNextFilter()后到达的状态。于是，在构造初始状态时我们就要用“前”一个状态Pair(0,
-1)作为构造参数（虽然它根本不在本题的状态全集中），以使得getNextFilter()从Pair(0, 0)开始判断。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>嗯，
好，在运行之前不要忘了#include &lt;iostream&gt;，不要忘了打开std名字空间（using namespace
std;），不要忘了粘上/包含上前面的WalkThrough的完整定义……编译，运行，好，这个超级难题被我们解决了。我的编译平台是Redhat
Linux 9， GNU C++ 3.2.2.<o:p></o:p></font>
						</font>
				</span>
		</p>
		<p class="MsoPlainText" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<font size="3">
								<font face="宋体">
										<span style="">    </span>最
后我们分析小结一下经过封装之后的穷举算法。首先看效率——是啦，我知道这个“和是50”超级难题所用的算法很糟糕——我是指在相同算法的前提下，使用我
们封装好的穷举类进行实现时的效率损失：初始化以及一系列set/get函数基本不影响效率，主开销源自于getNextFilter()本身的调用及
getNextFilter对两个用户提供函数的调用所产生的额外开销。试想如果用相同的算法，但仅用两层for来做穷举，则少了上万次的函数入栈、清栈
操作。穷举法本身就不是一个高效的搜索思想，所以对内层代码的效率变化是最敏感的，这一点是我们所封装的穷举类的最大缺点。<o:p></o:p></font>
						</font>
				</span>
		</p>
		<span style="" lang="EN-US">
				<font size="3">
						<font face="宋体">
								<span style="">    </span>不
过总算还是有一点好处，比如，封装之后，就将设计穷举算法分解成了相对独立的设计状态类、状态跳转函数、状态判断函数三个部分，三者的耦合度相对降低。此
外，这个设计的过程多少让我们又多了解了一点点基于对象编程的抽象能力，嗯，等等。噢……或许这是一个学术价值大于实用价值的设计吧，呵呵。</font>
				</font>
		</span>
<img src ="http://www.cppblog.com/swo2006/aggbug/14822.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-07 22:26 <a href="http://www.cppblog.com/swo2006/articles/14822.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中的文件输入/输出(5)</title><link>http://www.cppblog.com/swo2006/articles/14820.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 07 Nov 2006 14:23:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/14820.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/14820.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/14820.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/14820.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/14820.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: 150%; text-align: center;" align="center">
				<b style="">
						<span style="font-size: 16pt; color: rgb(51, 51, 51); line-height: 150%; font-family: 宋体;" lang="EN-US">C++</span>
				</b>
				<b style="">
						<span style="font-size: 16pt; color: rgb(51, 51, 51); line-height: 150%; font-family: 宋体;">中的文件输入</span>
				</b>
				<b style="">
						<span style="font-size: 16pt; color: rgb(51, 51, 51); line-height: 150%; font-family: 宋体;" lang="EN-US">/</span>
				</b>
				<b style="">
						<span style="font-size: 16pt; color: rgb(51, 51, 51); line-height: 150%; font-family: 宋体;">输出</span>
				</b>
				<b style="">
						<span style="font-size: 16pt; color: rgb(51, 51, 51); line-height: 150%;" lang="EN-US">(5)</span>
				</b>
				<b style="">
						<span style="font-size: 12pt; color: rgb(51, 51, 51); line-height: 150%; font-family: 宋体;" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</b>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: 150%; text-align: center;" align="center">
				<b style="">
						<span style="font-size: 12pt; color: rgb(51, 51, 51); line-height: 150%; font-family: 宋体;">原作：</span>
				</b>
				<b style="">
						<span style="font-size: 12pt; color: rgb(51, 51, 51); line-height: 150%; font-family: 宋体;" lang="EN-US">Ilia Yordanov,<span style="">  </span><a href="mailto:loobian@cpp-home.com">loobian@cpp-home.com</a><o:p></o:p></span>
				</b>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: 150%; text-align: center;" align="center">
				<b style="">
						<span style="font-size: 12pt; color: rgb(51, 51, 51); line-height: 150%; font-family: 宋体;" lang="EN-US">
								<o:p> </o:p>
						</span>
				</b>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: 150%; text-align: left;" align="left">
				<b style="">
						<span style="font-size: 16pt; color: rgb(51, 51, 51); line-height: 150%; font-family: 宋体;">二进制文件的处理</span>
				</b>
				<b style="">
						<span style="font-size: 16pt; color: rgb(51, 51, 51); line-height: 150%;" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</b>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<o:p>
								<font size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">虽然有规则格式（</span>
						<span lang="EN-US">formatted</span>
						<span style="font-family: 宋体;">）的文本（到目前为止我所讨论的所有文件形式）非常有用，但有时候你需要用到无格式（</span>
						<span lang="EN-US">unformatted</span>
						<span style="font-family: 宋体;">）的文件——二进制文件。它们和你的可执行程序看起来一样，而与使用</span>
						<span style="color: purple;" lang="EN-US">&lt;&lt;</span>
						<span style="font-family: 宋体;">及</span>
						<span style="color: purple;" lang="EN-US">&gt;&gt;</span>
						<span style="font-family: 宋体;">操作符创建的文件则大不相同。</span>
						<span style="color: purple;" lang="EN-US">get()</span>
						<span style="font-family: 宋体;">函数与</span>
						<span style="color: purple;" lang="EN-US">put()</span>
						<span style="font-family: 宋体;">函数则赋予你读</span>
						<span lang="EN-US">/</span>
						<span style="font-family: 宋体;">写无规则格式文件的能力：要读取一个字节，你可以使用</span>
						<span style="color: purple;" lang="EN-US">get()</span>
						<span style="font-family: 宋体;">函数；要写入一个字节，则使用</span>
						<span style="color: purple;" lang="EN-US">put()</span>
						<span style="font-family: 宋体;">函数。你应当回想起</span>
						<span style="color: purple;" lang="EN-US">get()</span>
						<span style="font-family: 宋体;">——我曾经使用过它。你可能会疑惑为什么当时我们使用它时，输出到屏幕的文件内容看起来是文本格式的？嗯，我猜这是因为我此前使用了</span>
						<span style="color: purple;" lang="EN-US">&lt;&lt;</span>
						<span style="font-family: 宋体;">及</span>
						<span style="color: purple;" lang="EN-US">&gt;&gt;</span>
						<span style="font-family: 宋体;">操作符。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span lang="EN-US">
						<o:p>
								<font size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 18pt;">
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">译注：作者的所谓“规则格式文本（</span>
				<span style="font-size: 9pt; color: navy;" lang="EN-US">formatted text</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">）”即我们平时所说的文本格式，而与之相对的“无格式文件（</span>
				<span style="font-size: 9pt; color: navy;" lang="EN-US">unformatted files</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">）”即以存储各类数据或可执行代码的非文本格式文件。通常后者需要读入内存，在二进制层次进行解析，而前者则可以直接由预定好的</span>
				<span style="font-size: 9pt; color: purple;" lang="EN-US">&lt;&lt;</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">及</span>
				<span style="font-size: 9pt; color: purple;" lang="EN-US">&gt;&gt;</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">操作符进行读入</span>
				<span style="font-size: 9pt; color: navy;" lang="EN-US">/</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">写出（当然，对后者也可以通过恰当地重载</span>
				<span style="font-size: 9pt; color: purple;" lang="EN-US">&lt;&lt;</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">及</span>
				<span style="font-size: 9pt; color: purple;" lang="EN-US">&gt;&gt;</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">操作符实现同样的功能，但这已经不是本系列的讨论范围了）。</span>
				<span style="font-size: 9pt; color: navy;" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="color: navy;" lang="EN-US">
						<o:p>
								<font size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="color: purple;" lang="EN-US">get()</span>
						<span style="font-family: 宋体;">函数与都各带一个参数：一个</span>
						<span style="color: purple;" lang="EN-US">char</span>
						<span style="font-family: 宋体;">型变量</span>
				</font>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">（译注：指</span>
				<span style="font-size: 9pt; color: purple;" lang="EN-US">get()</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">函数）</span>
				<span style="font-family: 宋体;">
						<font size="3">或一个字符</font>
				</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">（译注：指</span>
				<span style="font-size: 9pt; color: purple;" lang="EN-US">put()</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">函数，当然此字符也可以以</span>
				<span style="font-size: 9pt; color: purple;" lang="EN-US">char</span>
				<span style="font-size: 9pt; color: navy; font-family: 宋体;">型变量提供）</span>
				<span style="font-family: 宋体;">
						<font size="3">。</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">假如你要读</span>
						<span lang="EN-US">/</span>
						<span style="font-family: 宋体;">写一整块的数据，那么你可以使用</span>
						<span style="color: purple;" lang="EN-US">read()</span>
						<span style="font-family: 宋体;">和</span>
						<span style="color: purple;" lang="EN-US">write()</span>
						<span style="font-family: 宋体;">函数。它们的原型如下：</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span lang="EN-US">
						<o:p>
								<font size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">istream &amp;read(char *buf, streamsize num);<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">ostream &amp;write(const char *buf, streamsize num);</span>
						<span style="" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span lang="EN-US">
						<o:p>
								<font size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">对于</span>
						<span style="color: purple;" lang="EN-US">read()</span>
						<span style="font-family: 宋体;">函数，</span>
						<span style="color: purple;" lang="EN-US">buf</span>
						<span style="font-family: 宋体;">应当是一个字符数组，由文件读出的数据将被保存在这儿。对于</span>
						<span style="color: purple;" lang="EN-US">write()</span>
						<span style="font-family: 宋体;">函数，</span>
						<span style="color: purple;" lang="EN-US">buf</span>
						<span style="font-family: 宋体;">是一个字符数组，它用以存放你要写入文件的数据。对于这两个函数，</span>
						<span lang="EN-US">num</span>
						<span style="font-family: 宋体;">是一个数字，它指定你要从文件中读取</span>
						<span lang="EN-US">/</span>
						<span style="font-family: 宋体;">写入的字节数。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">假如在读取数据时，在你读取“</span>
						<span style="color: purple;" lang="EN-US">num</span>
						<span style="font-family: 宋体;">”个字节之前就已经到达了文件的末尾，那么你可以通过调用</span>
						<span style="color: purple;" lang="EN-US">gcount()</span>
						<span style="font-family: 宋体;">函数来了解实际所读出的字节数。此函数会返回最后一次进行的对无格式文件的读入操作所实际读取的字节数。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">在给出示例代码之前，我要补充的是，如果你要以二进制方式对文件进行读</span>
						<span lang="EN-US">/</span>
						<span style="font-family: 宋体;">写，那么你应当将</span>
						<span style="color: purple;" lang="EN-US">ios::binary</span>
						<span style="font-family: 宋体;">作为打开模式加入到文件打开的参数表中。</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">
						<font size="3">现在就让我向你展示示例代码，你会看到它是如何运作的。</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span lang="EN-US">
						<o:p>
								<font size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<font size="3">
						<span style="font-family: 宋体;">示例</span>
						<span lang="EN-US">1</span>
						<span style="font-family: 宋体;">：使用</span>
						<span lang="EN-US">get( )</span>
						<span style="font-family: 宋体;">和</span>
						<span lang="EN-US">put( )</span>
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span lang="EN-US">
						<o:p>
								<font size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">#include &lt;fstream.h&gt;<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">void main()<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">{<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">
								<span style="">    </span>fstream File("test_file.txt",ios::out | ios::in | ios::binary);<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">
								<span style="">    </span>char ch;<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">
								<span style="">    </span>ch='o';<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">    </span>File.put(ch); </span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">
						</span>
						<span style="color: green; font-family: 宋体;">将</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">ch</span>
						<span style="color: green; font-family: 宋体;">的内容写入文件</span>
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">    </span>File.seekg(ios::beg); </span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">
						</span>
						<span style="color: green; font-family: 宋体;">定位至文件首部</span>
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">    </span>File.get(ch); </span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">
						</span>
						<span style="color: green; font-family: 宋体;">读出一个字符</span>
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">    </span>cout &lt;&lt; ch &lt;&lt; endl; </span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">
						</span>
						<span style="color: green; font-family: 宋体;">将其显示在屏幕上</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: green; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">
								<span style="">    </span>File.close();<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">}<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="Verdana" size="2"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt; text-indent: 20pt;">
				<font size="2">
						<span style="font-family: 宋体;">示例</span>
						<span style="" lang="EN-US">
								<font face="Verdana">2</font>
						</span>
						<span style="font-family: 宋体;">：使用</span>
						<span style="" lang="EN-US">
								<font face="Verdana">read( )</font>
						</span>
						<span style="font-family: 宋体;">和</span>
						<span style="" lang="EN-US">
								<font face="Verdana">write( )<o:p></o:p></font>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt; text-indent: 20pt;">
				<span style="" lang="EN-US">
						<o:p>
								<font face="Verdana" size="2"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">#include &lt;fstream.h&gt;<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">#include &lt;string.h&gt;<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">void main()<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">{<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">
								<span style="">    </span>fstream File("test_file.txt",ios::out | ios::in | ios::binary);<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">
								<span style="">    </span>char arr[13];<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">    </span>strcpy(arr,"Hello World!"); </span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
						<span style="color: green; font-family: 宋体;">将</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">Hello World!</span>
						<span style="color: green; font-family: 宋体;">存入数组</span>
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">    </span>File.write(arr,5); </span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">
						</span>
						<span style="color: green; font-family: 宋体;">将前</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">5</span>
						<span style="color: green; font-family: 宋体;">个字符——</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">"Hello"</span>
						<span style="color: green; font-family: 宋体;">写入文件</span>
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">    </span>File.seekg(ios::beg); </span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">
						</span>
						<span style="color: green; font-family: 宋体;">定位至文件首部</span>
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">    </span>static char read_array[10]; </span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">
						</span>
						<span style="color: green; font-family: 宋体;">在此我将打算读出些数据</span>
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">    </span>File.read(read_array,3); </span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">
						</span>
						<span style="color: green; font-family: 宋体;">读出前三个字符——</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">"Hel"</span>
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<font size="2">
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">    </span>cout &lt;&lt; read_array &lt;&lt; endl; </span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
						<span style="color: green; font-family: 'Courier New';" lang="EN-US">
						</span>
						<span style="color: green; font-family: 宋体;">将它们输出</span>
						<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
								<span style="">   </span>
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2"> <o:p></o:p></font>
				</span>
		</p>
		<p class="MsoBodyText2" style="margin: 0cm 0cm 0pt;">
				<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
						<font size="2">
								<span style="">    </span>File.close();<o:p></o:p></font>
				</span>
		</p>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<font size="2">}</font>
		</span>
<img src ="http://www.cppblog.com/swo2006/aggbug/14820.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-07 22:23 <a href="http://www.cppblog.com/swo2006/articles/14820.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中的文件输入/输出(6):一些有用的函数  Kusk（翻译）</title><link>http://www.cppblog.com/swo2006/articles/14819.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 07 Nov 2006 14:20:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/14819.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/14819.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/14819.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/14819.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/14819.html</trackback:ping><description><![CDATA[
		<p align="center"> <span><strong>C++中的文件输入/输出(6):<font size="3"><span style="font-family: 宋体;">一些有用的函数</span><o:p></o:p></font></strong></span></p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: 150%; text-align: center;" align="center">
				<span>
						<strong>原作：Ilia Yordanov,<span style="">  </span></strong>
						<a href="mailto:loobian@cpp-home.com">
								<strong>loobian@cpp-home.com</strong>
						</a>
						<o:p>
						</o:p>
				</span>
		</p>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<br />
				<span style="">    </span>
				<b>tellg() </b>——</span>
		<span style="font-family: 宋体;">返回一个</span>
		<span style="color: purple;" lang="EN-US">int</span>
		<span style="font-family: 宋体;">型数值，它表示“内置指针”的当前位置。此函数仅当你在读取一个文件时有效。例如：</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">#include &lt;fstream.h&gt;<br /><span style="">    </span> <br /><span style="">    </span>void main()<br /><span style="">    </span>{<br /><span style="">    </span><span style="">    </span></span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">假如我们已经在</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">test_file.txt</span>
		<span style="color: green; font-family: 宋体;">中存有了“</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">Hello</span>
		<span style="color: green; font-family: 宋体;">”的内容</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>ifstream File("test_file.txt");<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>char arr[10];<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>File.read(arr,10);<br /><span style="">    </span><span style="">    </span><br /><span style="">    </span><span style="">    </span></span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">由于</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">Hello</span>
		<span style="color: green; font-family: 宋体;">占</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">5</span>
		<span style="color: green; font-family: 宋体;">个字符，因此这里将返回</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">5<br /><span style="">    </span></span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>cout &lt;&lt; File.tellg() &lt;&lt; endl; <br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>File.close();<br /><span style="">    </span>}<br /><span style="">    </span><br /><span style="">    </span></span>
		<b>
				<span lang="EN-US">tellp()</span>
		</b>
		<span lang="EN-US"> —— </span>
		<span style="font-family: 宋体;">与</span>
		<span style="color: purple;" lang="EN-US">tellg()</span>
		<span style="font-family: 宋体;">有同样的功能，但它用于写文件时。总而言之：当我们读取一个文件，并要知道内置指针的当前位置时，应该使用</span>
		<span style="color: purple;" lang="EN-US">tellg()</span>
		<span style="font-family: 宋体;">；当我们写入一个文件，并要知道内置指针的当前位置时，应该使用</span>
		<span style="color: purple;" lang="EN-US">tellp()</span>
		<span lang="EN-US">. </span>
		<span style="font-family: 宋体;">由于此函数的用法与</span>
		<span style="color: purple;" lang="EN-US">tellg()</span>
		<span style="font-family: 宋体;">完全一样，我就不给出示例代码了。</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<br />
				<span style="">    </span>
				<b>seekp() </b>—— </span>
		<span style="font-family: 宋体;">还记得</span>
		<span style="color: purple;" lang="EN-US">seekg()</span>
		<span style="font-family: 宋体;">么？当我在读取一个文件，并想到达文件中某个特定位置时，就曾使用过它。</span>
		<span style="color: purple;" lang="EN-US">seekp()</span>
		<span style="font-family: 宋体;">亦如此，只不过它用于写入一个文件的时候。例如，假如我在进行文件读写，而要定位到当前位置的三个字符之前，则需调用</span>
		<span style="color: purple;" lang="EN-US">FileHandle.seekg(-3)</span>
		<span lang="EN-US">. </span>
		<span style="font-family: 宋体;">但如果我是在写入一个文件，并且比如我要重写后</span>
		<span lang="EN-US">5</span>
		<span style="font-family: 宋体;">个字符的内容，我就必须往回跳转</span>
		<span lang="EN-US">5</span>
		<span style="font-family: 宋体;">个字符，因而，我应该使用</span>
		<span style="color: purple;" lang="EN-US">FileHandle.seekp(-5)</span>
		<span lang="EN-US"> .<br /><span style="">    </span><br /><span style="">    </span><b>ignore() </b>—— </span>
		<span style="font-family: 宋体;">使用于读取文件之时。如果你想略过一定数量的字符，只需使用此函数。实际上，你也可以使用</span>
		<span style="color: purple;" lang="EN-US">seekg()</span>
		<span style="font-family: 宋体;">来代替，然而使用</span>
		<span style="color: purple;" lang="EN-US">ignore()</span>
		<span style="font-family: 宋体;">有一个优点</span>
		<span lang="EN-US">——</span>
		<span style="font-family: 宋体;">你可以指定一个特定“界限规则（</span>
		<span lang="EN-US">delimiter rule</span>
		<span style="font-family: 宋体;">）”，同样使得</span>
		<span style="color: purple;" lang="EN-US">ignore()</span>
		<span style="font-family: 宋体;">在指定的位置停下。函数原型如下：</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">istream&amp; ignore( int <i>nCount</i>, delimiter );<br /><span style="">    </span><br /><span style="">    </span></span>
		<span style="color: purple;" lang="EN-US">nCount</span>
		<span style="font-family: 宋体;">表示要略过的字符数量，而</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">delimiter </span>
		<span lang="EN-US">—— </span>
		<span style="font-family: 宋体;">与它的名称有着同样的含义：假如你想在文件末尾停下，则可使用</span>
		<span lang="EN-US">EOF</span>
		<span style="font-family: 宋体;">值传入，这样一来此函数就等同于</span>
		<span style="color: purple;" lang="EN-US">seekg()</span>
		<span style="font-family: 宋体;">；但该参数还可以使用其他值，例如</span>
		<span style="color: purple;" lang="EN-US">‘\n’</span>
		<span style="font-family: 宋体;">这样可以在换行的同时定位在新行处。下面是示例：</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">#include &lt;fstream.h&gt;<br /><span style="">    </span> <br /><span style="">    </span>void main()<br /><span style="">    </span>{<br /><span style="">    </span><span style="">    </span></span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">假设</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">test_file.txt</span>
		<span style="color: green; font-family: 宋体;">中已经存有</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"Hello World"</span>
		<span style="color: green; font-family: 宋体;">这一内容</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>ifstream File("test_file.txt");<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>static char arr[10];<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span></span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">假如一直没有遇到字符</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"l"</span>
		<span style="color: green; font-family: 宋体;">，则向前定位直到跳过</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">6</span>
		<span style="color: green; font-family: 宋体;">个字符</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">而如果期间遇到</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"l"</span>
		<span style="color: green; font-family: 宋体;">，则停止向前，定位在该处</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>File.ignore(6,'l'); <br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>File.read(arr,10);<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>cout &lt;&lt; arr &lt;&lt; endl; </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">它将显示</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"lo World!"<br /><span style="">    </span> <br /><span style="">    </span></span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>File.close();<br /><span style="">    </span> <br /><span style="">    </span>}<br /><span style="">    </span></span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<b>getline() </b>—— </span>
		<span style="font-family: 宋体;">虽然前面的章节中我曾提到过这个函数，但还有一些内容我们未曾涉及：此函数不但可用于逐行读取，而且它还可以设为遇到某个特定字符后停止读取。下面给出传递这一参数的方法：</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">getline(array,array_size,delim);<br /><span style="">    </span><br /><span style="">    </span></span>
		<span style="font-family: 宋体;">以下为示例代码：</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">#include &lt;fstream.h&gt;<br /><span style="">    </span> <br /><span style="">    </span>void main()<br /><span style="">    </span>{<br /><span style="">    </span><span style="">    </span></span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">假设</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">test_file.txt</span>
		<span style="color: green; font-family: 宋体;">中已经存有</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"Hello World"</span>
		<span style="color: green; font-family: 宋体;">这一内容</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>ifstream File("test_file.txt");<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>static char arr[10];<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span></span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">/*</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">读取，直到满足下面的条件之一：</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>1</span>
		<span style="color: green; font-family: 宋体;">）已经读取</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">10</span>
		<span style="color: green; font-family: 宋体;">个字符</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>2</span>
		<span style="color: green; font-family: 宋体;">）遇到字母</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"o"</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>3</span>
		<span style="color: green; font-family: 宋体;">）出现新一行</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>*/</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
				<span style="">    </span>File.getline(arr,10,'o');<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>cout &lt;&lt; arr &lt;&lt; endl; </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">将显示</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"Hell"<br /><span style="">    </span></span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>File.close();<br /><span style="">    </span>}<br /><span style="">    </span></span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<b>peek() </b>—— </span>
		<span style="font-family: 宋体;">此函数将返回输入流文件的下一个字符，但它不移动内置指针。我想你该记得，像</span>
		<span style="color: purple;" lang="EN-US">get()</span>
		<span style="font-family: 宋体;">这样的函数也返回输入流文件的下一个字符，而与此同时它将移动内置指针。所以当你再次调用</span>
		<span style="color: purple;" lang="EN-US">get()</span>
		<span style="font-family: 宋体;">函数的时候，它会返回再下一个字符，而非前面那个。哦，使用</span>
		<span style="color: purple;" lang="EN-US">peek()</span>
		<span style="font-family: 宋体;">也会返回字符，但它不会移动“光标”。所以，假如你连续两次调用</span>
		<span style="color: purple;" lang="EN-US">peek()</span>
		<span style="font-family: 宋体;">函数，它会返回同一个字符。考虑以下代码：</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">#include &lt;fstream.h&gt;<br /><span style="">    </span> <br /><span style="">    </span>void main()<br /><span style="">    </span>{<br /><span style="">    </span><span style="">    </span></span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">假设</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">test_file.txt</span>
		<span style="color: green; font-family: 宋体;">中已经存有</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"Hello World"</span>
		<span style="color: green; font-family: 宋体;">这一内容</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>ifstream File("test_file.txt");<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>char ch;<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>File.get(ch);<br /><span style="">    </span><span style="">    </span>cout &lt;&lt; ch &lt;&lt; endl; </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">将显示</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"H"</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span> <br /><span style="">    </span><span style="">    </span>cout &lt;&lt;<span style="">    </span>char(File.peek()) &lt;&lt; endl; </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 宋体;">将显示</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"e"</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
				<span style="">    </span>cout &lt;&lt;<span style="">    </span>char(File.peek()) &lt;&lt; endl; </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 宋体;">将再次显示</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"e"</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span> <br /><span style="">    </span><span style="">    </span>File.get(ch);<br /><span style="">    </span><span style="">    </span>cout &lt;&lt; ch &lt;&lt; endl; </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">还是显示</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"e"</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>File.close();<br /><span style="">    </span><span style="">    </span><br /><span style="">    </span>}<br /><span style="">    </span></span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="font-family: 宋体;">顺便说一下，我忘了讲</span>
		<span lang="EN-US">——<span style="color: purple;">peek()</span></span>
		<span style="font-family: 宋体;">函数实质上返回的是字符的</span>
		<span lang="EN-US">ASCII</span>
		<span style="font-family: 宋体;">码，而非字符本身。因此，假如你想看到字符本身，你得像我在示例中做的那样进行调用<span style="color: navy;">（译注：即要转为</span></span>
		<span style="color: navy;" lang="EN-US">char</span>
		<span style="color: navy; font-family: 宋体;">类型）</span>
		<span style="font-family: 宋体;">。</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<br />
				<span style="">    </span>
				<b>_unlink() </b>—— </span>
		<span style="font-family: 宋体;">删除一个文件。假如你要使用此函数，需要在你的程序中包含</span>
		<span style="color: purple;" lang="EN-US">io.h</span>
		<span style="font-family: 宋体;">头文件。下面是示例代码：</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">#include &lt;fstream.h&gt;<br /><span style="">    </span>#include &lt;io.h&gt;<br /><span style="">    </span> <br /><span style="">    </span>void main()<br /><span style="">    </span>{<br /><span style="">    </span><span style="">    </span>ofstream File;<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>File.open("delete_test.txt"); </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 宋体;">创建一个文件</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>File.close();<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>_unlink("delete_test.txt"); </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">删除这个文件</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US"> <br /><span style="">    </span><span style="">    </span></span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">试图打开此文件，但假如它已不存在</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">函数将返回一个</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">ios::failbit</span>
		<span style="color: green; font-family: 宋体;">错误值</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>File.open("delete_test.txt",ios::nocreate);<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span></span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">验证它是否返回该值</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>if(File.rdstate() == ios::failbit)<br /><span style="">    </span><span style="">    </span><span style="">    </span>cout &lt;&lt; "Error...!\n"; </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">耶，成功了</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">File.close();<br /><span style="">    </span> <br /><span style="">    </span>}<br /><span style="">    </span></span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<b>putback() </b>—— </span>
		<span style="font-family: 宋体;">此函数将返回最后一个所读取字符，同时将内置指针移动</span>
		<span lang="EN-US">-1</span>
		<span style="font-family: 宋体;">个字符。换言之，如果你使用</span>
		<span style="color: purple;" lang="EN-US">get()</span>
		<span style="font-family: 宋体;">来读取一个字符后再使用</span>
		<span style="color: purple;" lang="EN-US">putback()</span>
		<span style="font-family: 宋体;">，它将为你返回同一个字符，然而同时会将内置指针移动</span>
		<span lang="EN-US">-1</span>
		<span style="font-family: 宋体;">个字符，所以你再次使用</span>
		<span style="color: purple;" lang="EN-US">get()</span>
		<span style="font-family: 宋体;">时，它还是会为你返回同样的字符。下面是示例代码：</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
				<br />
				<span style="">    </span>
		</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">#include &lt;fstream.h&gt;<br /><span style="">    </span> <br /><span style="">    </span>void main()<br /><span style="">    </span>{<br /><span style="">    </span><span style="">    </span></span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">test_file.txt</span>
		<span style="color: green; font-family: 宋体;">应包含内容</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"Hello World"<br /><span style="">    </span></span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<span style="">    </span>ifstream File("test_file.txt");<br /><span style="">    </span><span style="">    </span><br /><span style="">    </span><span style="">    </span>char ch;<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>File.get(ch);<br /><span style="">    </span> <br /><span style="">    </span><span style="">    </span>cout &lt;&lt; ch &lt;&lt; endl; </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">将显示</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"H"</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span> <br /><span style="">    </span><span style="">    </span>File.putback(ch);<br /><span style="">    </span><span style="">    </span>cout &lt;&lt; ch &lt;&lt; endl; </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">仍将显示</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"H"</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span>
				<span style="">    </span>
				<br />
				<span style="">    </span>
				<span style="">    </span>File.get(ch);<br /><span style="">    </span><span style="">    </span>cout &lt;&lt; ch &lt;&lt; endl; </span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">//</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">
		</span>
		<span style="color: green; font-family: 宋体;">再一次显示</span>
		<span style="color: green; font-family: 'Courier New';" lang="EN-US">"H"</span>
		<span style="color: blue; font-family: 'Courier New';" lang="EN-US">
				<br />
				<span style="">    </span> <br /><span style="">    </span><span style="">    </span>File.close();<br /><span style="">    </span>}<br /><span style="">    </span><br /><span style="">    </span></span>
		<b>
				<span lang="EN-US">flush()</span>
		</b>
		<span lang="EN-US"> —— </span>
		<span style="font-family: 宋体;">在处理输出流文件的时候，你所存入的数据实际上并非立刻写入文件，而是先放入一个缓冲区中，直到该缓冲区放满数据之后，这些数据才被存入真正的文件中（在你的磁盘上）。旋即缓冲区会被清空，再重新进行下一轮写入。</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="font-family: 宋体;">但假如你想在缓冲区写满之前就将其中的数据写入磁盘，则使用</span>
		<span style="color: purple;" lang="EN-US">flush()</span>
		<span style="font-family: 宋体;">函数。只须像这样进行调用：</span>
		<span style="color: purple;" lang="EN-US">FileHandle.flush()</span>
		<span style="font-family: 宋体;">，这样缓冲区内的数据将会写入实际的物理文件，而后缓冲区被清空。</span>
		<span lang="EN-US">
				<br />
				<span style="">    </span>
		</span>
		<span style="font-family: 宋体;">再补充一点（高阶的）内容：</span>
		<span style="color: purple;" lang="EN-US">flush()</span>
		<span style="font-family: 宋体;">函数会调用与相应流缓冲（</span>
		<span style="color: purple;" lang="EN-US">streambuf</span>
		<span style="font-family: 宋体;">）相联系的</span>
		<span style="color: purple;" lang="EN-US">sync()</span>
		<span style="font-family: 宋体;">函数（出自</span>
		<span lang="EN-US">MSDN</span>
		<span style="font-family: 宋体;">）。</span>
<img src ="http://www.cppblog.com/swo2006/aggbug/14819.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-07 22:20 <a href="http://www.cppblog.com/swo2006/articles/14819.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>构造函数(中)</title><link>http://www.cppblog.com/swo2006/articles/14818.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 07 Nov 2006 14:15:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/14818.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/14818.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/14818.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/14818.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/14818.html</trackback:ping><description><![CDATA[[转载]http://www.csdn.net/develop/article/22/22033.shtm<br /><p class="MsoPlainText" style="margin: 0cm 0cm 0pt; text-align: center;" align="center"><b style=""><span style="font-size: 14pt;"><font face="宋体">构造函数<span lang="EN-US">(中)<o:p></o:p></span></font></span></b></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt; text-align: center;" align="center"><b style=""><span style=""><font size="3"><font face="宋体">三、复制构造函数<span lang="EN-US"><o:p></o:p></span></font></font></span></b></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><b style=""><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>1.存在的理由<o:p></o:p></font></font></span></b></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>厨
师做烹饪的时候总要往锅里加入各式各样的调料，调料的种类、数量在相当大的程度上就决定了菜肴的口感；经验丰富的厨师总是擅长于根据顾客的品味差异来调节
调料的投入，以迎合顾客的喜好。我们在炮制对象的时候亦如此：通过重载不同具有参数表的构造函数，可以按我们的需要对新创建的对象进行初始化。譬如，对于
复数类Complex，我们可以在创建时指定实部、虚部，它通过“投入”的两个double参数来实现；而对于整型数组类IntArray，我们亦可以在
构造函数中“投入”一个int值作为数组对象的初始大小，如果需要，我们还可以再“撒进”一个内部数组作为数组各元素的初始值，等等。嗯，总之，就是说我
们可以通过向类的构造函数中传入各种参数，从而在对象创建之初便根据需要可对它进行初步的“调制”。假使我们已经做好了一道菜，呃，不，是已经有了一个对
象，比如说，一个复数类Complex的对象c，现在我们想新创建一个复数对象d，使之与c完全相等，应该怎么办？噢，有了上节的经验，我知道你会兴冲冲
地走到电脑，敲出类似于下面的代码：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>Complex d(c.getRe(), c.getIm());<span style="">     </span>// getRe()与getIm()分别返回复数的实、虚部<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>很
好，它可以正确的工作，不是吗？不过，再回过头两欣赏几眼之后，你是否和我一样开始觉得似乎这样有些冗长？而且，应该看到复数类是一个比较简单的抽象数据
类型，它提供的公有接口可以让我们访问到它所有的私有成员变量，所以我们才得以获得c的所有的“隐私”数据来对d进行初始化；但有相当多的类，是不能也不
该访问到它所有的私有对象的，退一步说，就算可以完全访问，我们的构造函数参数表也未必总能精细地、一丝不苟地刻画对象，例如对于IntArray类的某
个对象，例如a，可能它会包含一千个元素，但我们不可能写<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray copy_of_a(a.size(), a[0], a[1], a[2], ..., a[999]);<span style="">  </span>// 足够详细的刻画，同时也足够愚蠢<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>唔，
看来我们错就错在试图用数量有限的辅助参数来刻画我们的对象，而它往往是不合适的。要想以对象a来100%地确定对象b，就必须让对象b掌握对象a的
100%的信息，也就是说，构造函数中所传入的参数应该包含对象a的100%的信息。谁包含了“对象a的100%的信息”呢？看上去似乎是一道难题，哦，
我们似乎被前面各个杂乱的参数表弄得头晕脑胀，但我们不应该忘却从简单的方面考虑问题的法则，包含“对象a的100%的信息”的家伙，不应该是一群数量巨
大的变量，不应该是一组令人恐惧的参数，它应该就是...就是对象a本身。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>啊哈，真是废话。别管这么多，我们现在要让复数d初始化之后立刻等于复数c，就可以写<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>Complex d(c);<span style="">    </span>// 嗯...完美的表示<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>“等等...”你也许会提醒说，“你好像还没有定义与之对应的构造函数。”<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>这
是一个非常好心的提醒，不过我可以带着愉悦的心情告诉你：C++对于“以与自己同类型的对象为作为唯一参数传入的构造函数”已经做了默认的定义，对于这个
默认的构造函数所创建的对象，将与作为参数传入的对象具有完全相同的内容：实际上，这个过程一般是以“位拷贝”的方式进行的，即是将参数对象所占的那一块
内存的内容“一股脑”地拷贝到新创建的对象所处的内存区块中，这样做的结果，便使得新创建的对象与参数对象内有完全相同的成员变量值，无论是公有的还是私
有的，因而，我们也就得以以一个已存在的对象来初始化一个新的对象，当然，两者应该是同一类型的。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>你也许会对“为何C++要默认提供这样一个构造函数”感兴趣。实质上，不仅仅是上面的“声明对象并初始化”的例子要使用到这个特性，在一些更普遍的情况、同时也是我们所不注意的情况中，必须要使用到这个功能，例如：进行值传递的函数调用。考虑下面的代码片断：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>void swap(int a, int b)<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>{<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">        </span>int temp = a;<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">        </span>a = b;<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">        </span>b = temp;<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>}<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>int main()<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>{<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">      </span><span style=""> </span>int x = 1, y = 2;<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">       </span>swap(x, y);<span style="">    </span>// 噢...<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">       </span>... // others<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">       </span>return 0;<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>}<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>问
题：执行了swap(x, y)之后，x, y的值分别是多少？毫无疑问，当然是x==1,
y==2，因为执行swap时，交换的并不是x,y变量的值，而只是它们的一个副本。我们可以从某个角度认为：在调用swap函数时，将会“新创建”两个
变量a, b，而a, b分别以x, y的值进行初始化，像这样：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>int a(x), b(y);<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>...<span style="">  </span>// 此后的操作都与x, y无关了<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>同样，假如有这样一个函数：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>void swap(Complex a, Complex b)<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>{<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">        </span>...<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>}<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>在出现诸如swap(p, q)这样的调用时，也会对p, q进行复制操作，类似于：Complex a(p), b(q);<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>与参数的传入一样，函数在返回时(如果有返回的话)，只要不是返回某个引用，则也会出现类似的复制操作(这里不考虑某些省却复制步骤的编译优化)。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>所以，假如系统不会为我们默认定义这样的特殊的构造函数，我们将不能定义任何出现Complex类型的参数，或者返回值为Complex类型的函数，而这简直是没有道理的，至少，看上去不是那么好令人接受。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>由于这样的构造函数可以看作是从一个既有的同型对象中“复制”创建出一个新对象，所以也把这个构造函数称为复制构造函数，或拷贝构造函数(copy constructor).实质上它与其它的构造函数没有区别，只是：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>1.如果没有明确给出，系统会默认提供一个复制构造函数(类似于不带参数的构造函数，以及析构函数)；<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>2.进行值传递的函数调用或返回时，系统将使用此构造函数(相对于其它的通常只存在人为调用的构造函数)。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>噫，以上便是有关复制构造函数的讲解。时间不早，该休息了。朋友，祝您晚安，下次见...<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>哦，
不不不，弄错了，没有这么简单。我们...我们才刚刚开始...唔，至少我还得在睡前把这篇文章打完，而且下面似乎内容不少，总之，还有相当多的因素要考
虑。嗯，你可能说，C++提供的默认复制构造函数不是已经尽职尽责地、一个bit不漏地为我们将对象原原本本地克隆过去么，那么所得的新对象肯定与被复制
对象完全一样，还有什么要考虑的？<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>问
题就出在对于“完全一样”的理解上。我们说两个三角形完全一样，是指它们具有对应相同的边、角；我们说两个复数完全一样，是指它们具有对应相等的实部、虚
部；我们说两个文件完全一样，是指它们的内容一丝不苟地相同...那我们说某个类型的两个对象完全一样，当然，从朴素的意义上说，应该是指这两个对象具有
相同的成员，包括成员函数与成员变量；不过，同型对象当然有相同的成员函数，所以更确切地说，完全相同即是具有相同的成员变量。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>但C
++中的类的对象并非、也不应该仅被视为绻缩于内存中某个角落的一系列二进制数据，那是机器的观点。事实上，对象作为现实模型的一个描述，它本身应该具有
一定的抽象而来意义。一个Orange类的对象，在编程时也许我们更多的时候会有意无意地将其作为一个活生生的桔子进行考虑，而非一撮二进制流。C++的
面向对象抽象使我们更好地刻画现实模型，并进行正确的、恰当的使用。因此，当我们说两个对象“完全相等”，基于抽象的思想，我们所指的，或者说所要求的，
只是对象所代表的现实模型的意义上的相等，至于在二进制层面的实现上，它们内部的0101是否一样，倒不是我们最关心的，当然，可能在许多情况下，两者是
等同的，但也不尽然。譬如两个IntArray数组对象，当然，它们各包含了一个整型指针作为私有成员，以存放数组所处内存空间的首地址。但我们说这两个
数组对象相同，更多意义上指的是它们含有相同的维数、尺寸，以及对应相等的元素，至于存放首地址的指针值，尽管它们在大多数情况下都不相等，但这并不妨碍
我们认为两个数组相同。在这个例子中，“对象”所代表的概念上的意义与它在机器层面的意义出现了分岐，程序语言的任务之一就在于提供更恰当的抽象，使程序
具有某种吻合于现实模型的条理性。所以两者出现分岐之时，既然我们使用的是具有相当抽象能力的高级语言，就应当倾向于尊重现实的概念，而不是返朴归真。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>说
了这么多，现在该回过头来看一看默认复制构造函数所采用的“完全照搬”复制模式将有可能带来怎样的“概念层面”与“机器层面”的矛盾。刚才我们已经抓到了
IntArray类的尾巴，现在来看看，假如使用代表着“机器层面理解”的默认复制函数对它进行复制构造，会发生什么事情。嗯，没错，新创建的
IntArray对象--不妨称为b--将具有与原对象--不妨称为a--完全相同的成员变量，当然也包括用于存储数组内存空间首地址的指针成员，也就是
说，a与b实际上是“共享”了同一块内存以存放“它们”的数据。从此，如果我改变a数组中的某个元素的值，则b中相应元素也会改变，反之亦然--我们的程
序闹鬼了。更为严重的是，如果我们在IntArray的析构函数中加入了释放数组内存的代码(几乎所有的容器都会这样做)，那么由于有多个对象共享同一块
内存，这块可怜的内存将会被释放多次，事实上当第二次来临时我们的程序很可能就已经崩溃了，这种情况在值传递调用函数时最为典型。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>我
们概念意义上对“数组复制”的理解是产生一个新数组，使之与原数组的元素均对应相同，而绝不是什么共享内存的鬼把戏。但我们忠厚的C++编译器可不了解这
些，毕竟它只是机器，所以也只会尽职尽责地为我们施行位拷贝。这样一来，我们就有义务把我们对概念本身的理解告诉C++，当然，这个途径就是显示地定义一
个复制构造函数。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><b style=""><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>2.关于声明的讨论<o:p></o:p></font></font></span></b></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>首
先，以IntArray类为例，我们来看看复制构造函数的声明应该是什么样子：构造函数是没有返回值的，复制构造函数当然也不例外，因此我们只须考虑参
数。复制构造函数只有一个参数，由于在创建时传入的是同种类型的对象，所以一个很自然的想法是将该类型的对象作为参数，像这样：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray(IntArray a);<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>不
幸的是，即使是这样朴实无华的声明也隐含了一个微妙的错误，呵，我们来看看：当某个时候需要以一个IntArray对象的值来为一个新对象进行初始化时，
当然，编译器会在各个重载的构造函数版本(如果有多个的话)搜寻，它找到的这个版本，发现声明参数与传入的对象一致，因此该构造函数将会被调用。目前为
止，一切都在我们的意料之中，但问题很快来了：该函数的参数我们使用了值传递的方式，按照前面的分析，这需要调用复制构造函数，于是编译器又再度搜寻，最
后当然又找到了它，于是进行调用，但同样地，传参时又要进行复制，于是再调用...这个过程周而复始，每次都是到了函数入口处就进行递归，直到堆栈空间耗
尽，程序崩溃...<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>当
然，这样的好戏在现实中不大会出现，因为编译器会及时发现这一明显是问题的问题，并报告错误，终止编译；所以接下来我们还得想想其它办法。我们刚才之所以
没有获得想当然的成功是由于在传参时出现了复制构造函数的调用--而这本来就是它需要解决的操作--从而产生无穷递归。由是观之，值传递看来是行不通的
了；我想C语言的用户这时很快会反应到与值传递对应的方式：地址传递(传址)，于是声明变为这样：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray(IntArray *p);<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>只作为一般的构造函数，它应该可以运行得很好，但别忘了我们要提供的是复制构造函数，它要求能够接受一个同类型对象，像这样：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray a;<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>... // 对a操作<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray b(a);<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>而不是接受指针：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray a;<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>... // 对a操作<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray b(&amp;a);<span style="">  </span>// 还要取地址？当然，它可以正确运行，但...<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>否则，虽然在初始化对象时可以像上面一样人为加一个取址符，但在函数参数表中(或者函数返回)进行值传递时，编译器可不知道在找不着合适定义的情况下牵就选择你的指针版本。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>既然复制构造函数括号里放的必须是某个对象，但又不能通过值传递，也不能通过传址代替，解决的方案，我想你一定早想到了。没错，就是使用引用：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray(IntArray&amp; a);<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>由于引用产生的只是一个别名，而实质上使用的还是“原来的”被引用的对象，所以，当然，嗯，也就不会存在什么参数复制的问题，从而不会再去调用复制构造函数--也就是它自己！<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>成功之后我们再来看看能不能再做一些改进：我们在复制对象的过程中，当然，从语义上说，一般不会改变被复制的“母体对象”的值。我们难以想象，诸如：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>Complex b(a);<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style=""><font face="宋体"><font size="3">的语句过后，会使复数<span lang="EN-US">a
变得面目全非；同时，假如“母体对象”是const类型，将意味着我们不能用它来初始化其它对象：因为参数IntArray&amp;
a不能保证a不会被修改！将const常量传给非const引用会导致编译出错，但这个限制显然并非我们所要的；并且，我们有可能不小心的情况在复制构造
函数中修改了本不希望改动的“母体对象”，而这一切将很难在今后查出。综上所述，我们通常会给复制构造函数的引用参数前加上const进行修饰：<o:p></o:p></span></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray(const IntArray&amp; a);<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>这样一来就更完美了，它避免了上述的问题；而且即使是非const的对象也可以作为const型的引用(如前文所分析，反过来就不可以)。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><b style=""><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>3.定义的实现<o:p></o:p></font></font></span></b></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>好，
我们已经找到了复制构造函数的一个合适的参数，对于声明的讨论也就告一段落了。现在我们还是以IntArray为例，来看看它的实现应当是什么样子。如果
你读过《构造函数(上)》，那么还记得上一节开头我所给出的有关IntArray的声明么？如果你的回答是Yes，那么我很佩服你的用心，不过我自己是记
不得了，为了我自己，以及那些同我一样的朋友和暂时没有读过上节内容的朋友，我把上一节的IntArray主要部分声明粘贴如下(其实很简单)：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">class IntArray<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">{<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">public:<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>... // others<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">private:<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>int *_p;<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>int _size;<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">};<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>如
你所推测，IntArray使用整型指针_p存储在自由存储区上以new表达式分配得来的内存空间的首地址，而_size则存放该空间可以容纳的整型元素
的个数，换句话说，它也就代表了数组的尺寸。以机器的观点，在IntArray中，_p和_size是标识两个IntArray对象是否相同的特征变量
(我们假设pulic区段所声明的都是成员函数，而没有成员变量)，但从我们对数组概念上的理解，_size和_p所指的内存中元素是否均对应相同，才是
数组相同的意义；换言之，_size和_p所指的内存的内容(而不是_p存储的地址值)才是构成我们“概念理解上”的数组的信息。因而在进行复制的时候，
基于尊重“概念抽象”的观点，应当对_p所指的内存空间进行复制，而不是简单地复制_p本身。这就是我们在自定义的复制构造函数中所要表明的；下面是一个
可能的定义，我把分析放在注释部分：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray(const IntArray&amp; a)<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>{<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">        </span>_size = a._size;<span style="">  </span>// 我们显示定义了复制构造函数之后，默认构造函数就不存在了，<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">                          </span>// 所以必须自己实现所有必要的成员变量的复制<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">        </span>if (_size &gt; 0)<span style="">    </span>// 只有a的尺寸大于0，也就是a有内容时，才需要复制<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">        </span>{<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">             </span>_p = new int[_size];<span style="">  </span>// 构造函数总是在创建新对象时调用，所以别忘了分配内存<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">             </span>for (int i = 0; i &lt; _size; ++i)<span style="">  </span>// 逐个复制a中的内容<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">                 </span>_p[i] = a._p[i];<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">         </span>}<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">         </span>else<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">             </span>_p = 0;<span style="">     </span>// 安全起见，我们把零内容数组的指针设为0<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>}<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>嗯，
再补充一点。如果你的程序非常在意效率，那么你可以用诸如memcopy()的内存拷贝函数把整块a._p所指的内存复制过来，一般这样会比使用循环快一
些。不过在C++中对这个函数的使用不是不需要经过慎重考虑的：和相当部分的默认复制构造函数一样，它只是简单机械地拷贝内存，所以你如果将此函数应用在
诸如IntArray的对象上，以希望“有效率地”拷贝多个IntArray对象，那么几乎一定会出现问题：它不会知道应该拷贝_p所指的内容，因而将产
生前面所说的种种问题；甚至我们显式定义了IntArray的复制构造函数，它也不会调用--因为你使用它就意味着你要求的是“位拷贝”，而不是“复制构
造”。所以，在C++中，只有当memcopy应用在内置基本类型上时，我才敢保证它是安全的。当然，如果你把握不准，那么在C++中把这个C时代遗留下
来的函数忘了不失为一个很好的对策。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><b style=""><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>4.组合或继承情况下的复制构造<o:p></o:p></font></font></span></b></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>不知你注意到没有，我刚刚说memcopy()的机械拷贝只是和“相当部分”的默认复制构造函数一样，呃，应当反过来说，只是“相当部分”的默认复制构造函数采用“位拷贝”模式。咦，难道还有某种神秘的力量在控制着另一种默认复制构造函数？<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>先考虑以下例子：假如我现在要设计一个类，不妨叫A，它包含了一个IntArray对象作为其中一个成员，当然，这是不奇怪的，像这样：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">class A<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">{<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">public:<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>... // others<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">private:<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>IntArray _array; // that's it<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>... // others<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">};<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>然后我的代码中出现了A的对象的复制构造，这也是很有可能的，像这样一个函数：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">A dosomething(A a)<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">{<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>...<span style="">      </span>// 一些操作<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>A b(a);<span style="">  </span>// 以a复制构造出b<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>...<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>return b;<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">}<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>以
上的片断就隐含了三个关于A对象的复制构造(你看得出来吗？)，但如果我没有为A定义复制构造函数，如前面所说，编译器当然就会建立一个默认复制构造函
数，然后在需要的时候调用它。问题在于，这个默认复制构造函数假如还是傻呵呵地采用简单的位拷贝，那至少可以断定我们的_array成员将遭遇不测。当
然，你或许会责怪我没有为A添置一个复制构造函数，但我可以说，而且是很有理由地辩解说，class
A的其余成员并不需要提供复制构造函数，至于IntArray类型成员，我只是这个类的用户，它封装好的内部机制不应当由我负责，事实上我也无从负责：即
使我真的愿意专门为之设计一个复制构造函数，我又该怎么实现呢？作为用户，我得到的只是IntArray的接口，也就是说我只有权利使用它，而无法关心也
不该它内部是怎样运作的，而复制构造函数通常需要涉及上述内容。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>作
为一门成功的语言，C++当然不能允许存在上述的尴尬。事实上，假如一个类存在需要调用(用户定义的，可能是间接的)复制构造函数的成员对象，而类本身又
没有提供复制构造函数，则其默认构造函数不是简单地采用位拷贝模式，而是将其对象“逐一”分别拷贝，对于需要调用复制构造函数的对象，则进行相应的调用，
以保持复制构造的概念上的意义。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>对于继承的情况也是类似，假如有一个SuperIntArray类继承至IntArray：<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">class SuperIntArray: public IntArray<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">{<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">public:<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>... // something<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">private:<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>... // something<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3">};<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>即使SuperIntArray本身没有提供复制构造函数，在其对象需要复制构造时，对基类IntArray部分的构造，同样也会调用IntArray(const IntArray&amp;)来实现。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><font face="宋体"><font size="3"><span style="">    </span>嗯，如果前面所提到的组成与继承的情况中，新的类型显示提供了复制构造函数，则相应成员，或者基类的复制构造函数也同样会被调用。实际上前一节我们提到构造函数时已经就这个问题讨论过了，所以这一部分基本上没有太多的新意：别忘了，复制构造函数只不过是构造函数的一种。<o:p></o:p></font></font></span></p><p class="MsoPlainText" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><o:p><font face="宋体" size="3"> </font></o:p></span></p><br /><!--内容结束//--><br /><br /><br /><br /><img src ="http://www.cppblog.com/swo2006/aggbug/14818.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-07 22:15 <a href="http://www.cppblog.com/swo2006/articles/14818.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>typedef的使用</title><link>http://www.cppblog.com/swo2006/articles/14741.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Mon, 06 Nov 2006 10:51:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/14741.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/14741.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/14741.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/14741.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/14741.html</trackback:ping><description><![CDATA[
		<br />　　1、typedef的最简单使用<br /><br /><table align="center" bgcolor="#e6e4dd" border="1" bordercolor="#ffcc66" width="90%"><tbody><tr><td>typedef long byte_4;</td></tr></tbody></table><br />　　给已知数据类型long起个新名字，叫byte_4。<br /><br />　　<strong>2、 typedef与结构结合使用<br /></strong><br /><table align="center" bgcolor="#e6e4dd" border="1" bordercolor="#ffcc66" width="90%"><tbody><tr><td>typedef struct tagMyStruct<br />{ <br />　int iNum;<br />　long lLength;<br />} MyStruct;</td></tr></tbody></table><br />　　这语句实际上完成两个操作：<br /><br />　　1) 定义一个新的结构类型<br /><br /><table align="center" bgcolor="#e6e4dd" border="1" bordercolor="#ffcc66" width="90%"><tbody><tr><td>struct tagMyStruct<br />{ <br />　int iNum; <br />　long lLength; <br />};</td></tr></tbody></table><br />　　分析：tagMyStruct称为“tag”，即“标签”，实际上是一个临时名字，struct 关键字和tagMyStruct一起，<a href="http://www.yesky.com/key/340/460340.html" class="bluekey" target="_blank">构成</a>了这个结构类型，不论是否有typedef，这个结构都存在。<br /><br />　　我们可以用struct tagMyStruct varName来定义变量，但要注意，使用tagMyStruct varName来定义变量是不对的，因为struct 和tagMyStruct合在一起才能表示一个结构类型。<br /><br />　　2) typedef为这个新的结构起了一个名字，叫MyStruct。<br /><br /><table align="center" bgcolor="#e6e4dd" border="1" bordercolor="#ffcc66" width="90%"><tbody><tr><td>typedef struct tagMyStruct MyStruct;</td></tr></tbody></table><br />　　因此，MyStruct实际上相当于struct tagMyStruct，我们可以使用MyStruct varName来定义变量。<img src ="http://www.cppblog.com/swo2006/aggbug/14741.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-06 18:51 <a href="http://www.cppblog.com/swo2006/articles/14741.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>伪随机数生成</title><link>http://www.cppblog.com/swo2006/articles/11687.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Fri, 25 Aug 2006 02:41:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11687.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11687.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11687.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11687.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11687.html</trackback:ping><description><![CDATA[摘
要伪随机数在计算机软件设计中有很广泛的用途。本文介绍了基于数学方法的利用计算机产生伪随机数的一种方法，即线性同余法，任何伪随机数的产生都是运用递
推的原理来生成的。以及在Visual
C++环境中产生伪随机数的两个重要函数，rand和srand函数，正确地使用这两个函数是产生性能良好的伪随机数的关键，最后介绍了利用伪随机数生成
技术在MFC中生成基于C/S模式应用<a href="http://www.xker.com/article/articlelist/article_5_adddate_desc_1.htm" target="_blank" class="a_link">程序</a>的随机校验码以及利用一种软件工具ImagePassword产生随机密码。<br /><br />　　<b>关键词</b>伪随机数生成；线性同余法；Visual C++；随机校验码 <br /><br />　
　为追求真正的随机序列，人们曾采用很多种原始的物理方法用于生成一定范围内满足精度（位数）的均匀分布序列，其缺点在于：速度慢、效率低、需占用大量存
储空间且不可重现等。为满足计算机模拟研究的需求，人们转而研究用算法生成模拟各种概率分布的伪随机序列。伪随机数是指用数学递推公式所产生的随机数。从
实用的角度看，获取这种数的最简单和最自然的方法是利用计算机语言的函数库提供的随机数发生器。典型情况下，它会输出一个均匀分布在0和1区间内的伪随机
变量的值。其中应用的最为广泛、研究最彻底的一个算法即线性同余法。<br /><br />　　线性同余法LCG（Linear Congruence Generator）<br /><br />　　选取足够大的正整数M和任意自然数n0，a，b，由递推公式：<br /><br /><code>ni+1=（af（ni）+b）mod M i=0，1，…，M-1 </code><br />　　生成的数值序列称为是同余序列。当函数f（n）为线性函数时，即得到线性同余序列：<br /><br /><code>ni+1=（a*ni+b）mod M i=0，1，…，M-1 </code><br />　　以下是线性同余法生成伪随机数的伪代码：<br /><br /><code>Random（n，m，seed，a，b）<br />{<br />　r0 = seed；<br />　for （i = 1；i&lt;=n；i++）<br />　ri = （a*ri-1 + b） mod m<br />}</code><br />　　其中种子参数seed可以任意选择，常常将它设为计算机当前的日期或者时间；m是一个较大数，可以把它取为2w，w是计算机的字长；a可以是0.01w和0.99w之间的任何整数。<br /><br />　　应用递推公式产生均匀分布随机数时，式中参数n0，a，b，M的选取十分重要。<br /><br />　　例如，选取M=10，a=b =n0=7，生成的随机序列为{6，9，0，7，6，9，……}，周期为4。<br /><br />　　取M=16，a=5，b =3，n0=7，生成的随机序列为{6，1，8，11，10，5，12，15，14，9，0，3，2，13，4，7，6，1……}，周期为16。<br /><br />　　取M=8，a=5，b =1，n0=1，生成的随机序列为{6，7，4，5，2，3，0，1，6，7……}，周期为8。<br /><br />　　<b>Visual C++中伪随机数生成机制</b><br /><br />　
　用VC产生随机数有两个函数，分别为rand（void）和srand（seed）。rand()产生的随机整数是在0~RAND_MAX之间平均分布
的，RAND_MAX是一个常量（定义为：#define RAND_MAX
0x7fff）。它是short型数据的最大值，如果要产生一个浮点型的随机数，可以将rand()/1000.0，这样就得到一个0~32.767之间
平均分布的随机浮点数。如果要使得范围大一点，那么可以通过产生几个随机数的线性组合来实现任意范围内的平均分布的随机数。<br /><br />　　其用法是先调用srand函数，如 <br /><br /><code>srand( (unsigned)time( NULL ) )</code><br />　
　这样可以使得每次产生的随机数序列不同。如果计算伪随机序列的初始数值（称为种子）相同，则计算出来的伪随机序列就是完全相同的。要解决这个问题，需要
在每次产生随机序列前，先指定不同的种子，这样计算出来的随机序列就不会完全相同了。以time函数值（即当前时间）作为种子数，因为两次调用rand函
数的时间通常是不同的，这样就可以保证随机性了。也可以使用srand函数来人为指定种子数。<br />分析以下两个<a href="http://www.xker.com/article/articlelist/article_5_adddate_desc_1.htm" target="_blank" class="a_link">程序</a>段，<br /><br />　　<a href="http://www.xker.com/article/articlelist/article_5_adddate_desc_1.htm" target="_blank" class="a_link">程序</a>段1：<br /><br /><code>//包含头文件 <br />void main() {<br />　int count=0;<br />　for (int i=0;i&lt;10;i++){<br />　　srand((unsigned)time(NULL)); <br />　　count++;<br />　　cout&lt;&lt;"No"&lt;<count>&lt;&lt;"="&lt;<rand()>&lt;&lt;" ?;<br /><br />　　<a href="http://www.xker.com/article/articlelist/article_5_adddate_desc_1.htm" target="_blank" class="a_link">程序</a>段1中由于将srand（）函数放在循环体内，而<a href="http://www.xker.com/article/articlelist/article_5_adddate_desc_1.htm" target="_blank" class="a_link">程序</a>执行的CPU时间较快，调用time函数获取的时间精度却较低（55ms），这样循环体内每次产生随机数用到的种子数都是一样的，因此产生的随机数也是一样的。而<a href="http://www.xker.com/article/articlelist/article_5_adddate_desc_1.htm" target="_blank" class="a_link">程序</a>段2中第1次产生的随机数要用到随机种子，以后的每次产生随机数都是利用递推关系得到的。<br />   基于MFC的随机校验码生成<br /><br />　　Web应用<a href="http://www.xker.com/article/articlelist/article_5_adddate_desc_1.htm" target="_blank" class="a_link">程序</a>中经常要利用到随机校验码，校验码的主要作用是防止<a href="http://www.xker.com/Article/ArticleList/Article_10_AddDate_Desc_1.Htm" target="_blank" class="a_link">黑客</a>利用工具软件在线破译用户登录密码，校验码、用户名、密码三者配合组成了进入Web应用系统的钥匙。在利用VC开发的基于客户机/浏览器（Client/Server）模式的应用软件系统中，为了防止非法用户入侵系统，通常也要运用随机校验码生成技术。<br /><br />　　本实现要用到以上介绍到的伪随机数生成技术。校验码数据将以16进制码方式显示。主要代码如下：<br /><br /><code>void CRandompasswordDlg::OnCreatekey() {<br />　int RanCheckNum = 0;<br />　char out[25]={0};<br />　char keytemp[5]={0};<br />　memset(out,0x30,18);<br />　srand((unsigned)timeGetTime());//产生随机数种子<br />　for(int i=0;i&lt;6;i++){ <br />　　RanCheckNum = rand();//产生随机数<br />　　_itoa(RanCheckNum,keytemp,16);//将随机数转换成16进制<br />　　memcpy(&amp;out[i*4],keytemp,strlen(keytemp));<br />　}<br />　out[24]=0x00;<br />　strcpy(m_key.GetBuffer(18),out);<br />　UpdateData(FALSE);<br />}</code><br />　　运行结果如图1所示：<br /><br /></rand()></count></code><center><img src="http://www.xker.com/article/UserFiles/2005-11/1/200511175019898.jpg" border="0" /><br /><br />图1 利用伪随机数生成随机校验码</center><br />　　<a href="http://www.xker.com/article/articlelist/article_5_adddate_desc_1.htm" target="_blank" class="a_link">程序</a>运行时，由于每一次点击"产生随机校验码"的系统时间不同，生成随机数的种子就不一样，因此产生的随机数也是不一样的，从而保证了校验码生成的随机性。<br /><br />　　<b>利用ImagePassword工具产生随机密码</b><br /><br />　　ImagePassword提供一个可选择的图形阵列，通过随机改变图形阵列中的阵点图形来产生随机密码。当随机点击图象阵列中的图象阵点，该阵点中的图象发生变化。其运行界面如图2所示：<br /><br /><center><img src="http://www.xker.com/article/UserFiles/2005-11/1/200511175019249.jpg" border="0" /><br /><br />图2 ImagePassword运行界面</center><br />　　点击OK按钮后所产生的随机密码如图3所示： <br /><br /><center><img src="http://www.xker.com/article/UserFiles/2005-11/1/200511175019278.jpg" border="0" /><br /><br />图3 ImagePassword运行结果</center><br />　　ImagePassword产生的密码的随机性依赖于用户对图象阵列中阵点图象的随机选择，一般来说用户在图象阵列中随机点击鼠标的次数越多，最后产生的密码的随机性越强。<br /><br />　　<b>结束语</b><br /><br />　
　伪随机数在不同的软件系统中都得到了很广泛的应用，如何选择随机数生成种子使得生成的伪随机数性能更佳是软件设计者追求的目标之一。本文提到了利用系统
时间作为种子参数在一定条件下可以满足软件的随机性需要。利用所产生的随机数在游戏编程，如扑克类游戏中的随机发牌，俄罗斯方块的随机生成等等其他应用中
都起到很重要的作用。<img src ="http://www.cppblog.com/swo2006/aggbug/11687.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-25 10:41 <a href="http://www.cppblog.com/swo2006/articles/11687.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>任意分布的随机数的产生方法—VC程序实现方法</title><link>http://www.cppblog.com/swo2006/articles/11634.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Thu, 24 Aug 2006 02:49:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11634.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11634.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11634.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11634.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11634.html</trackback:ping><description><![CDATA[
		<br />
		<img src="http://www.jcwcn.com/Files01/BeyondPic/2006-5/29/rar.gif" align="absmiddle" border="0" />
		<a title="" href="http://www.jcwcn.com/bbs/member.php?action=credits&amp;view=getattach" target="_blank" pop="查看积分策略说明">
				<font color="#003366">附件</font>
		</a>: <a class="bold" href="http://www.jcwcn.com/bbs/attachment.php?aid=20708" target="_blank"><strong><font color="#003366">random.rar</font></strong></a> (2006-4-20 10:14 AM, 24.78 K)<font face="Tahoma"><br /><br /></font>    隨機數在實際運用中非常之多，如游戲設計，信號處理，通常我們很容易得到平均分布的隨機數。但如何根據平均分布的隨機數進而產生其它分布的隨機數呢？本文提出了一種基於幾何直觀面積的方法，以正態分布隨機數的產生為例討論了任意分布的隨機數的產生方法。<br />正文：<br />一、平均分布隨機數的產生<br />    大家都知道，隨機數在各個方面都有很大的作用，在vc的環境下，為我們提供了庫函數rand()來產生一個隨機的整數。該隨機數是平均在0~RAND_MAX之間平均分布的，RAND_MAX是一個常量，在<a href="http://www.jcwcn.com/html/VC" target="_blank">VC</a>6.0環境下是這樣定義的：<br /><br /><div class="smalltxt" style="font-weight: bold; margin-left: 2em; margin-right: 2em;"><div style="float: left;">CODE:</div><div style="float: right; text-align: right;"><a class="smalltxt" onclick="copycode(findobj('code0'));" href="http://www.jcwcn.com/bbs/viewthread.php?tid=12228&amp;extra=page%3D1###"><font color="#003366">[Copy to clipboard]</font></a></div></div><div class="altbg2" id="code0" style="border: 1px solid rgb(105, 140, 195); margin: 3px 2em 2em; padding: 5px 10px 10px; clear: both;">#define RAND_MAX 0x7fff</div>它
是一個short
型數據的最大值，如果要產生一個浮點型的隨機數，可以將rand()/1000.0這樣就得到一個0~32.767之間平均分布的隨機浮點數。如果要使得
范圍大一點，那麼可以通過產生幾個隨機數的線性組合來實現任意范圍內的平均分布的隨機數。例如要產生-1000~1000之間的精度為四位小數的平均分布
的隨機數可以這樣來實現。先產生一個0到10000之間的隨機整數。方法如下 ：<br /><br /><div class="smalltxt" style="font-weight: bold; margin-left: 2em; margin-right: 2em;"><div style="float: left;">CODE:</div><div style="float: right; text-align: right;"><a class="smalltxt" onclick="copycode(findobj('code1'));" href="http://www.jcwcn.com/bbs/viewthread.php?tid=12228&amp;extra=page%3D1###"><font color="#003366">[Copy to clipboard]</font></a></div></div><div class="altbg2" id="code1" style="border: 1px solid rgb(105, 140, 195); margin: 3px 2em 2em; padding: 5px 10px 10px; clear: both;">int a = rand()%10000;</div>然後保留四位小數產生0~1之間的隨機小數：<br /><br /><div class="smalltxt" style="font-weight: bold; margin-left: 2em; margin-right: 2em;"><div style="float: left;">CODE:</div><div style="float: right; text-align: right;"><a class="smalltxt" onclick="copycode(findobj('code2'));" href="http://www.jcwcn.com/bbs/viewthread.php?tid=12228&amp;extra=page%3D1###"><font color="#003366">[Copy to clipboard]</font></a></div></div><div class="altbg2" id="code2" style="border: 1px solid rgb(105, 140, 195); margin: 3px 2em 2em; padding: 5px 10px 10px; clear: both;">double b = (double)a/10000.0;</div>然後通過線性組合就可以實現任意范圍內的隨機數的產生，要實現-1000~1000內的平均分布的隨機數可以這樣做：<br /><br /><div class="smalltxt" style="font-weight: bold; margin-left: 2em; margin-right: 2em;"><div style="float: left;">CODE:</div><div style="float: right; text-align: right;"><a class="smalltxt" onclick="copycode(findobj('code3'));" href="http://www.jcwcn.com/bbs/viewthread.php?tid=12228&amp;extra=page%3D1###"><font color="#003366">[Copy to clipboard]</font></a></div></div><div class="altbg2" id="code3" style="border: 1px solid rgb(105, 140, 195); margin: 3px 2em 2em; padding: 5px 10px 10px; clear: both;">double dValue = (rand()%10000)/10000.0*1000-(rand()%10000)/10000.0*1000;</div>則dValue就是所要的值。<br />   到現在為止，你或許以為一切工作都已經完成了，其實不然，仔細一看，你會發現有問題的，上面的式子化簡後就變為：<br /><br /><div class="smalltxt" style="font-weight: bold; margin-left: 2em; margin-right: 2em;"><div style="float: left;">CODE:</div><div style="float: right; text-align: right;"><a class="smalltxt" onclick="copycode(findobj('code4'));" href="http://www.jcwcn.com/bbs/viewthread.php?tid=12228&amp;extra=page%3D1###"><font color="#003366">[Copy to clipboard]</font></a></div></div><div class="altbg2" id="code4" style="border: 1px solid rgb(105, 140, 195); margin: 3px 2em 2em; padding: 5px 10px 10px; clear: both;">double dValue = (rand()%10000)/10.0-(rand()%10000)/10.0;</div>這樣一來，產生的隨機數范圍是正確的，但是精度不正確了，變成了只有一位正確的小數的隨機數了，後面三位的小數都是零，顯然不是我們要求的，什麼原因呢，又怎麼辦呢。<br />   先找原因，rand()產生的隨機數分辨率為32767，兩個就是65534，而經過求餘後分辨度還要減小為10000，兩個就是20000而要求的分辨率為1000*10000*2=20000000，顯然遠遠不夠。下面提供的方法可以實現正確的結果：<br /><br /><div class="smalltxt" style="font-weight: bold; margin-left: 2em; margin-right: 2em;"><div style="float: left;">CODE:</div><div style="float: right; text-align: right;"><a class="smalltxt" onclick="copycode(findobj('code5'));" href="http://www.jcwcn.com/bbs/viewthread.php?tid=12228&amp;extra=page%3D1###"><font color="#003366">[Copy to clipboard]</font></a></div></div><div class="altbg2" id="code5" style="border: 1px solid rgb(105, 140, 195); margin: 3px 2em 2em; padding: 5px 10px 10px; clear: both;">double a = (rand()%10000) * (rand()%1000)/10000.0;<br />        double b = (rand()%10000) * (rand()%1000)/10000.0;<br />        double dValue = a-b;</div>則dValue就是所要求的結果。在下面的函數中可以實現產生一個在一個區間之內的平均分布的隨機數，精度是4位小數。<br /><br /><div class="smalltxt" style="font-weight: bold; margin-left: 2em; margin-right: 2em;"><div style="float: left;">CODE:</div><div style="float: right; text-align: right;"><a class="smalltxt" onclick="copycode(findobj('code6'));" href="http://www.jcwcn.com/bbs/viewthread.php?tid=12228&amp;extra=page%3D1###"><font color="#003366">[Copy to clipboard]</font></a></div></div><div class="altbg2" id="code6" style="border: 1px solid rgb(105, 140, 195); margin: 3px 2em 2em; padding: 5px 10px 10px; clear: both;">double AverageRandom(double min,double max)<br />        {<br />        int minInteger = (int)(min*10000);<br />        int maxInteger = (int)(max*10000);<br />        int randInteger = rand()*rand();<br />        int diffInteger = maxInteger - minInteger;<br />        int resultInteger = randInteger % diffInteger + minInteger;<br />        return resultInteger/10000.0;<br />        }</div>但
是有一個值得注意的問題，隨機數的產生需要有一個隨機的種子，因為用計算機產生的隨機數是通過遞推的方法得來的，必須有一個初始值，也就是通常所說的隨機
種子，如果不對隨機種子進行初始化，那麼計算機有一個確省的隨機種子，這樣每次遞推的結果就完全相同了，因此需要在每次程序運行時對隨機種子進行初始化，
在vc中的方法是調用srand（int）這個函數，其參數就是隨機種子，但是如果給一個常量，則得到的隨機序列就完全相同了，因此可以使用系統的時間來
作為隨機種子，因為系統時間可以保證它的隨機性。<br /><br /> 調用方法是srand(GetTickCount()),但是又不能在每次調用rand()的時候都用srand(GetTickCount())來初
始化，因為現在計算機運行時間比較快，當連續調用rand()時，系統的時間還沒有更新，所以得到的隨機種子在一段時間內是完全相同的，因此一般只在進行
一次大批隨機數產生之前進行一次隨機種子的初始化。下面的代碼產生了400個在-1~1之間的平均分布的隨機數。<br /><br /><div class="smalltxt" style="font-weight: bold; margin-left: 2em; margin-right: 2em;"><div style="float: left;">CODE:</div><div style="float: right; text-align: right;"><a class="smalltxt" onclick="copycode(findobj('code7'));" href="http://www.jcwcn.com/bbs/viewthread.php?tid=12228&amp;extra=page%3D1###"><font color="#003366">[Copy to clipboard]</font></a></div></div><div class="altbg2" id="code7" style="border: 1px solid rgb(105, 140, 195); margin: 3px 2em 2em; padding: 5px 10px 10px; clear: both;">double dValue[400];<br />        srand(GetTickCount());<br />        for(int i= 0;i &lt; 400; i++)<br />        {<br />        double dValue[i] = AverageRandom(-1,1);<br />        }</div>用該方法產生的隨機數運行結果如圖1所示：<br /><br /><img onmousewheel="return imgzoom(this);" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="if(!this.resized) {return false;} else {window.open('attachments/month_0604/1_UZCg7GxQ0BaJ.png');}" src="http://www.jcwcn.com/Files01/BeyondPic/2006-5/29/1_UZCg7GxQ0BaJ.png" onload="if(this.width&gt;screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='点击在新窗口查看全图\nCTRL+鼠标滚轮放大或缩小';}" border="0" /><br /><br />圖1 400個-1~1之間平均分布的隨機數<br /><br />二、任意分布隨機數的產生<br />   下面提出了一種已知概率密度函數的分布的隨機數的產生方法，以典型的正態分布為例來說名任意分布的隨機數的產生方法。<br />   如果一個隨機數序列服從一維正態分布，那麼它有有如下的概率密度函數：<br /><br /><br /><br /><img src="http://www.jcwcn.com/Files01/BeyondPic/2006-5/29/image.gif" align="absmiddle" border="0" /><a title="查看积分策略说明" href="http://www.jcwcn.com/bbs/member.php?action=credits&amp;view=getattach" target="_blank"><font color="#003366">图片附件</font></a>: <a class="bold" href="http://www.jcwcn.com/bbs/attachment.php?aid=20703" target="_blank"><strong><font color="#003366">1.gif</font></strong></a> (2006-4-20 10:08 AM, 2.69 K)<br /><br /><img onmousewheel="return imgzoom(this);" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="if(!this.resized) {return false;} else {window.open('attachments/month_0604/1_isUWVKzXMBNS.gif');}" src="http://www.jcwcn.com/Files01/BeyondPic/2006-5/29/1_isUWVKzXMBNS.gif" onload="if(this.width&gt;screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='点击在新窗口查看全图\nCTRL+鼠标滚轮放大或缩小';}" border="0" /><br /><br />其中μ，σ（ &gt;0）為常數，它們分別為數學期望和均方差，如果讀者對數學期望和均方差的概念還不大清楚，請查閱有關概率論的書。如果取μ =0，σ =0.2,則其曲線為<br /><br /><br /><img onmousewheel="return imgzoom(this);" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="if(!this.resized) {return false;} else {window.open('attachments/month_0604/2_VhPXWLXaw4sd.png');}" src="http://www.jcwcn.com/Files01/BeyondPic/2006-5/29/2_VhPXWLXaw4sd.png" onload="if(this.width&gt;screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='点击在新窗口查看全图\nCTRL+鼠标滚轮放大或缩小';}" border="0" /><br /><br />圖2 正態分布的概率密度函數曲線<br />從
圖中可以看出，在μ附近的概率密度大，遠離μ的地方概率密度小，我們要產生的隨機數要服從這種分布，就是要使產生的隨機數在μ附近的概率要大，遠離μ處
小，怎樣保證這一點呢，可以采用如下的方法：在圖2的大矩形中隨機產生點，這些點是平均分布的，如果產生的點落在概率密度曲線的下方，則認為產生的點是符
合要求的，將它們保留，如果在概率密度曲線的上方，則認為這些點不合格，將它們去處。如果隨機產生了一大批在整個矩形中均勻分布的點，那麼被保留下來的點
的橫坐標就服從了正態分布。可以設想，由於在μ處的f(x)的值比較大，理所當然的在μ附近的點個數要多，遠離μ處的少，這從面積上就可以看出來。我們要
產生的隨機數就是這裡的橫坐標。<br />   基於以上思想，我們可以用程序實現在一定范圍內服從正態分布的隨機數。程序如下：<br /><br /><div class="smalltxt" style="font-weight: bold; margin-left: 2em; margin-right: 2em;"><div style="float: left;">CODE:</div><div style="float: right; text-align: right;"><a class="smalltxt" onclick="copycode(findobj('code8'));" href="http://www.jcwcn.com/bbs/viewthread.php?tid=12228&amp;extra=page%3D1###"><font color="#003366">[Copy to clipboard]</font></a></div></div><div class="altbg2" id="code8" style="border: 1px solid rgb(105, 140, 195); margin: 3px 2em 2em; padding: 5px 10px 10px; clear: both;">double Normal(double x,double miu,double sigma) //概率密度函數<br />        {<br />        return 1.0/sqrt(2*PI*sigma) * exp(-1*(x-miu)*(x-miu)/(2*sigma*sigma));<br />        }<br />        double NormalRandom(double miu,                  double sigma,double min,double max)//產生正態分布隨機數<br />        {<br />        double x;<br />        double dScope;<br />        double y;<br />        do<br />        {<br />        x = AverageRandom(min,max); <br />        y = Normal(dResult, miu, sigma);<br />        dScope = AverageRandom(0, Normal(miu,miu,sigma));<br />        }while( dScope &gt; y);<br />        return x;<br />        }</div>參數說明：double miu：μ，正態函數的數學期望<br /><br /><br />                  double sigma：σ，正態函數的均方差<br />                  double min,double max，表明產生的隨機數的范圍<br />用如上方法，取 μ=0，σ=0.2，范圍是-1~1產生400個正態隨機數如圖3所示：<br /><br /><br /><img onmousewheel="return imgzoom(this);" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="if(!this.resized) {return false;} else {window.open('attachments/month_0604/3_nKAkI2bwyAXY.png');}" src="http://www.jcwcn.com/Files01/BeyondPic/2006-5/29/3_nKAkI2bwyAXY.png" onload="if(this.width&gt;screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='点击在新窗口查看全图\nCTRL+鼠标滚轮放大或缩小';}" border="0" /><br /><br />圖3 μ=0， σ=0.2，范圍在-1~1時的400個正態分布的隨機數分布圖<br />取 μ=0， σ=0.05，范圍是-1~1產生400個正態隨機數如圖4所示：<br /><br /><br /><img onmousewheel="return imgzoom(this);" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="if(!this.resized) {return false;} else {window.open('attachments/month_0604/4_jPkYmttHkHBU.png');}" src="http://www.jcwcn.com/Files01/BeyondPic/2006-5/29/4_jPkYmttHkHBU.png" onload="if(this.width&gt;screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='点击在新窗口查看全图\nCTRL+鼠标滚轮放大或缩小';}" border="0" /><br /><br />圖4 μ=0，σ=0.05，范圍在-1~1時的400個正態分布的隨機數分布圖<br />從圖3和圖4的比較可以看出， 越小，產生的隨機數靠近 的數量越多，也說明了產生的隨機數靠近 的概率越大。<br />我們，先產生4000個在0到4之間的正態分布的隨機數，取μ=0，σ=0.2，再把產生的數據的數量做個統計，畫成曲線，如下圖5所示：<br /><br /><br /><img onmousewheel="return imgzoom(this);" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="if(!this.resized) {return false;} else {window.open('attachments/month_0604/5_zNstr0g3VeOG.png');}" src="http://www.jcwcn.com/Files01/BeyondPic/2006-5/29/5_zNstr0g3VeOG.png" onload="if(this.width&gt;screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='点击在新窗口查看全图\nCTRL+鼠标滚轮放大或缩小';}" border="0" /><br /><br />圖5 μ=0， σ=0.2，范圍在0~4時的4000個正態分布的隨機數統計圖<br />從圖5中也可以看出，在靠近 處的產生的個數多，遠離 處的產生的數量少，該圖的輪廓線和概率密度曲線的形狀剛好吻合。也就驗證了該方法的正確性。<br />有了以上基礎，也就用同樣的方法，只要知道概率密度函數，也就不難產生任意分布的隨機數，方法都是先產生一個點，然後進行取捨，落在概率密度曲線下方的點就滿足要求，取其橫坐標就是所要獲取的隨機數。<br /><br />參考文獻:<br />1、《概率論與數理統計》高等教育出版社，盛驟，謝式千等<br />2、《基於Matlab/Simulink的系統仿真技術與應用》清華大學出版社，薛定宇，陳陽泉<br /><img src ="http://www.cppblog.com/swo2006/aggbug/11634.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-24 10:49 <a href="http://www.cppblog.com/swo2006/articles/11634.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>打开文件</title><link>http://www.cppblog.com/swo2006/articles/11452.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Sat, 19 Aug 2006 06:46:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11452.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11452.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11452.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11452.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11452.html</trackback:ping><description><![CDATA[
		<div>
				<pre>
						<a href="http://www.koders.com/c/fid25FC3676105CA8BE2D5D4967DF5771931349240C.aspx?s=fopen#L1" name="L1">
						</a>
						<a href="http://www.koders.com/c/fid25FC3676105CA8BE2D5D4967DF5771931349240C.aspx?s=fopen#L53" name="L53">
						</a>#<a title="Search for references of 'include'" href="javascript:searchRef('include')" class="r">include</a><span class="str">"global.h"</span><br /><br /><span class="c">/* Initialisation du module DEBUG pour les environnements<br />   ne permettant pas de consulter la ligne de commande  <br />   travers CLP.<br />*/</span><br />#<a title="Search for references of 'define'" href="javascript:searchRef('define')" class="r">define</a><a title="Search for references of 'DEBUGLINELENGTH'" href="javascript:searchRef('DEBUGLINELENGTH')" class="r">DEBUGLINELENGTH</a> 256<br /><br /><span class="k">void</span><a title="Search for references of 'dbInit'" href="javascript:searchRef('dbInit')" class="r">dbInit</a>()<br />{<br /><span class="k">char</span><a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>[<a title="Search for references of 'DEBUGLINELENGTH'" href="javascript:searchRef('DEBUGLINELENGTH')" class="r">DEBUGLINELENGTH</a>];<br /><a title="Search for references of 'FILE'" href="javascript:searchRef('FILE')" class="r">FILE</a> *<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>;<br /><br /><a title="Search for references of 'stdebug'" href="javascript:searchRef('stdebug')" class="r">stdebug</a>=<a title="Search for references of 'stderr'" href="javascript:searchRef('stderr')" class="r">stderr</a>;<br /><a title="Search for references of 'memset'" href="javascript:searchRef('memset')" class="r">memset</a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>,0,<a title="Search for references of 'DEBUGLINELENGTH'" href="javascript:searchRef('DEBUGLINELENGTH')" class="r">DEBUGLINELENGTH</a>);<br /><br /><a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>=<a title="Search for references of 'fopen'" href="javascript:searchRef('fopen')" class="r"><span class="s0">fopen</span></a>(<span class="str">".dbfile"</span>,<span class="str">"r"</span>);<br /><span class="k">if</span> (<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>) {<br /><span class="c">/* open the debug output device */</span><br /><a title="Search for references of 'fgets'" href="javascript:searchRef('fgets')" class="r">fgets</a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>,<a title="Search for references of 'DEBUGLINELENGTH'" href="javascript:searchRef('DEBUGLINELENGTH')" class="r">DEBUGLINELENGTH</a>,<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>);<br /><a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>[<a title="Search for references of 'strlen'" href="javascript:searchRef('strlen')" class="r">strlen</a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>)-1]=0;<br /><span class="k">if</span> (!(<a title="Search for references of 'stdebug'" href="javascript:searchRef('stdebug')" class="r">stdebug</a>=<a title="Search for references of 'fopen'" href="javascript:searchRef('fopen')" class="r"><span class="s0">fopen</span></a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>,<span class="str">"w"</span>))) <br /><a title="Search for references of 'stdebug'" href="javascript:searchRef('stdebug')" class="r">stdebug</a>=<a title="Search for references of 'fopen'" href="javascript:searchRef('fopen')" class="r"><span class="s0">fopen</span></a>(<span class="str">"/dev/null"</span>,<span class="str">"w"</span>);<br /><span class="c">/* open the debug INPUT device */</span><br /><a title="Search for references of 'fgets'" href="javascript:searchRef('fgets')" class="r">fgets</a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>,<a title="Search for references of 'DEBUGLINELENGTH'" href="javascript:searchRef('DEBUGLINELENGTH')" class="r">DEBUGLINELENGTH</a>,<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>);<br /><a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>[<a title="Search for references of 'strlen'" href="javascript:searchRef('strlen')" class="r">strlen</a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>)-1]=0;<br /><span class="k">if</span> (!(<a title="Search for references of 'stdbin'" href="javascript:searchRef('stdbin')" class="r">stdbin</a>=<a title="Search for references of 'fopen'" href="javascript:searchRef('fopen')" class="r"><span class="s0">fopen</span></a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>,<span class="str">"r"</span>))) <br /><a title="Search for references of 'stdbin'" href="javascript:searchRef('stdbin')" class="r">stdbin</a>=<a title="Search for references of 'fopen'" href="javascript:searchRef('fopen')" class="r"><span class="s0">fopen</span></a>(<span class="str">"/dev/null"</span>,<span class="str">"r"</span>);<br /><br /><a title="Search for references of 'fclose'" href="javascript:searchRef('fclose')" class="r">fclose</a>(<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>);<br />  }<br /><span class="k">else</span><a title="Search for references of 'stdebug'" href="javascript:searchRef('stdebug')" class="r">stdebug</a>=<a title="Search for references of 'fopen'" href="javascript:searchRef('fopen')" class="r"><span class="s0">fopen</span></a>(<span class="str">"/dev/null"</span>,<span class="str">"w"</span>);<br /><br /><br /><a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>=<a title="Search for references of 'fopen'" href="javascript:searchRef('fopen')" class="r"><span class="s0">fopen</span></a>(<span class="str">".dblevel"</span>,<span class="str">"r"</span>);<br /><span class="k">if</span>(<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>) {<br /><a title="Search for references of 'fgets'" href="javascript:searchRef('fgets')" class="r">fgets</a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>,<a title="Search for references of 'DEBUGLINELENGTH'" href="javascript:searchRef('DEBUGLINELENGTH')" class="r">DEBUGLINELENGTH</a>,<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>);<br /><a title="Search for references of 'DbLvl'" href="javascript:searchRef('DbLvl')" class="r">DbLvl</a>=<a title="Search for references of 'atoi'" href="javascript:searchRef('atoi')" class="r">atoi</a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>);<br /><a title="Search for references of 'fclose'" href="javascript:searchRef('fclose')" class="r">fclose</a>(<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>);<br />  }<br /><br /><br /><a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>=<a title="Search for references of 'fopen'" href="javascript:searchRef('fopen')" class="r"><span class="s0">fopen</span></a>(<span class="str">".dbmask"</span>,<span class="str">"r"</span>);<br /><span class="k">if</span>(<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>) {<br /><a title="Search for references of 'fgets'" href="javascript:searchRef('fgets')" class="r">fgets</a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>,<a title="Search for references of 'DEBUGLINELENGTH'" href="javascript:searchRef('DEBUGLINELENGTH')" class="r">DEBUGLINELENGTH</a>,<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>);<br /><a title="Search for references of 'DbMsk'" href="javascript:searchRef('DbMsk')" class="r">DbMsk</a>=<a title="Search for references of 'atoi'" href="javascript:searchRef('atoi')" class="r">atoi</a>(<a title="Search for references of 'buffer'" href="javascript:searchRef('buffer')" class="r">buffer</a>);<br /><a title="Search for references of 'fclose'" href="javascript:searchRef('fclose')" class="r">fclose</a>(<a title="Search for references of 'db'" href="javascript:searchRef('db')" class="r">db</a>);<br />  }</pre>
		</div>
<img src ="http://www.cppblog.com/swo2006/aggbug/11452.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-19 14:46 <a href="http://www.cppblog.com/swo2006/articles/11452.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>static用法小结(ZT)</title><link>http://www.cppblog.com/swo2006/articles/11375.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Thu, 17 Aug 2006 13:21:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11375.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11375.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11375.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11375.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11375.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="text-align: left;" align="left">
				<b>
						<span style="font-size: 14pt; font-family: 宋体; color: rgb(41, 82, 0);" lang="EN-US">static</span>
				</b>
				<b>
						<span style="font-size: 14pt; font-family: 宋体; color: rgb(41, 82, 0);">用法小结<span lang="EN-US"></span></span>
				</b>
				<span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<table class="MsoNormalTable" style="border: medium none ; width: 100%; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr style="">
								<td style="border: 1pt inset rgb(165, 189, 107); padding: 0cm;">
										<div align="center">
												<table class="MsoNormalTable" style="width: 100%; border-collapse: collapse;" border="0" cellpadding="0" cellspacing="0" width="100%">
														<tbody>
																<tr style="">
																		<td style="padding: 0cm;">
																				<div align="center">
																						<table class="MsoNormalTable" style="width: 100%; border-collapse: collapse;" border="0" cellpadding="0" cellspacing="0" width="100%">
																								<tbody>
																										<tr style="">
																												<td style="padding: 0cm;">
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;" lang="EN-US">static</span>
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">关键字是<span lang="EN-US">C, C++</span>中都存在的关键字<span lang="EN-US">, </span>它主要有三种使用方式<span lang="EN-US">, </span>其中前两种只指在<span lang="EN-US">C</span>语言中使用<span lang="EN-US">, </span>第三种在<span lang="EN-US">C++</span>中使用<span lang="EN-US">(C,C++</span>中具体细微操作不尽相同<span lang="EN-US">, </span>本文以<span lang="EN-US">C++</span>为准<span lang="EN-US">).<br />
      (1)</span>局部静态变量<span lang="EN-US"><br />
      (2)</span>外部静态变量<span lang="EN-US">/</span>函数<span lang="EN-US"><br />
      (3)</span>静态数据成员<span lang="EN-US">/</span>成员函数<span lang="EN-US"><br /></span>下面就这三种使用方式及注意事项分别说明<span lang="EN-US"><o:p></o:p></span></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">一、局部静态变量<span lang="EN-US"><br /></span>在<span lang="EN-US">C/C++</span>中<span lang="EN-US">, </span>局部变量按照存储形式可分为三种<span lang="EN-US">auto, static, register<br />
      (&lt;C</span>语言程序设计<span lang="EN-US">(</span>第二版<span lang="EN-US">)&gt;</span>谭浩强<span lang="EN-US">, </span>第<span lang="EN-US">174-175</span>页<span lang="EN-US">)<br /></span>与<span lang="EN-US">auto</span>类型<span lang="EN-US">(</span>普通<span lang="EN-US">)</span>局部变量相比<span lang="EN-US">, static</span>局部变量有三点不同<span lang="EN-US"><br />
      1. </span>存储空间分配不同<span lang="EN-US"><br />
      auto</span>类型分配在栈上<span lang="EN-US">, </span>属于动态存储类别<span lang="EN-US">, </span>占动态存储区空间<span lang="EN-US">, </span>函数调用结束后自动释放<span lang="EN-US">, </span>而<span lang="EN-US">static</span>分配在静态存储区<span lang="EN-US">, </span>在程序整个运行期间都不释放<span lang="EN-US">. </span>两者之间的作用域相同<span lang="EN-US">, </span>但生存期不同<span lang="EN-US">.<br />
      2. static</span>局部变量在所处模块在初次运行时进行初始化工作<span lang="EN-US">, </span>且只操作一次<span lang="EN-US"><br />
      3. </span>对于局部静态变量<span lang="EN-US">, </span>如果不赋初值<span lang="EN-US">, </span>编译期会自动赋初值<span lang="EN-US">0</span>或空字符<span lang="EN-US">, </span>而<span lang="EN-US">auto</span>类型的初值是不确定的<span lang="EN-US">. (</span>对于<span lang="EN-US">C++</span>中的<span lang="EN-US">class</span>对象例外<span lang="EN-US">, class</span>的对象实例如果不初始化<span lang="EN-US">, </span>则会自动调用默认构造函数<span lang="EN-US">, </span>不管是否是<span lang="EN-US">static</span>类型<span lang="EN-US">)<o:p></o:p></span></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">特点<span lang="EN-US">: static</span>局部变量的<span lang="EN-US">”</span>记忆性<span lang="EN-US">”</span>与生存期的<span lang="EN-US">”</span>全局性<span lang="EN-US">”<br /></span>所谓<span lang="EN-US">”</span>记忆性<span lang="EN-US">”</span>是指在两次函数调用时<span lang="EN-US">, </span>在第二次调用进入时<span lang="EN-US">, </span>能保持第一次调用退出时的值<span lang="EN-US">. <br /></span>示例程序一<span lang="EN-US"><br />
      #include &lt;iostream&gt;<o:p></o:p></span></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;" lang="EN-US">using namespace std;<o:p></o:p></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;" lang="EN-US">void staticLocalVar()<br />
      {<br />
       static int a = 0; // </span>
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">运行期时初始化一次<span lang="EN-US">, </span>下次再调用时<span lang="EN-US">, </span>不进行初始化工作<span lang="EN-US"><br />
       cout&lt;&lt;"a="&lt;&lt;a&lt;&lt;endl;<br />
       ++a;<br />
      }<o:p></o:p></span></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;" lang="EN-US">int main()<br />
      {<br />
       staticLocalVar(); // </span>
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">第一次调用<span lang="EN-US">, </span>输出<span lang="EN-US">a=0<br />
       staticLocalVar(); // </span>第二次调用<span lang="EN-US">, </span>记忆了第一次退出时的值<span lang="EN-US">, </span>输出<span lang="EN-US">a=1<br />
       return 0;<br />
      }<o:p></o:p></span></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">应用<span lang="EN-US">:<br />
       </span>利用<span lang="EN-US">”</span>记忆性<span lang="EN-US">”, </span>记录函数调用的次数<span lang="EN-US">(</span>示例程序一<span lang="EN-US">)<br />
         </span>利用生存期的<span lang="EN-US">”</span>全局性<span lang="EN-US">”,
      </span>改善<span lang="EN-US">”return a pointer / reference to a local
      object”</span>的问题<span lang="EN-US">. Local object</span>的问题在于退出函数<span lang="EN-US">, </span>生存期即结束<span lang="EN-US">,. </span>利用<span lang="EN-US">static</span>的作用<span lang="EN-US">, </span>延长变量的生存期<span lang="EN-US">.<br /></span>示例程序二<span lang="EN-US">:<br />
      // IP address to string format<br />
      // Used in Ethernet Frame and IP Header analysis<br />
      const char * IpToStr(UINT32 IpAddr)<br />
      {<br />
       static char strBuff[16]; // static</span>局部变量<span lang="EN-US">, </span>用于返回地址有效<span lang="EN-US"><br />
       const unsigned char *pChIP = (const unsigned char *)&amp;IpAddr;<br />
       sprintf(strBuff, "%u.%u.%u.%u",  pChIP[0], pChIP[1],
      pChIP[2], pChIP[3]);<br />
       return strBuff;<br />
      }<o:p></o:p></span></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">注意事项<span lang="EN-US">:<br />
      1. “</span>记忆性<span lang="EN-US">”, </span>程序运行很重要的一点就是可重复性<span lang="EN-US">, </span>而<span lang="EN-US">static</span>变量的<span lang="EN-US">”</span>记忆性<span lang="EN-US">”</span>破坏了这种可重复性<span lang="EN-US">, </span>造成不同时刻至运行的结果可能不同<span lang="EN-US">.<br />
      2. “</span>生存期<span lang="EN-US">”</span>全局性和唯一性<span lang="EN-US">. </span>普通的<span lang="EN-US">local</span>变量的存储空间分配在<span lang="EN-US">stack</span>上<span lang="EN-US">, </span>因此每次调用函数时<span lang="EN-US">, </span>分配的空间都可能不一样<span lang="EN-US">, </span>而<span lang="EN-US">static</span>具有全局唯一性的特点<span lang="EN-US">, </span>每次调用时<span lang="EN-US">, </span>都指向同一块内存<span lang="EN-US">, </span>这就造成一个很重要的问题<span lang="EN-US"> ---- </span>不可重入性<span lang="EN-US">!!!<br /></span>这样在多线程程序设计或递归程序设计中<span lang="EN-US">, </span>要特别注意这个问题<span lang="EN-US">.<br />
      (</span>不可重入性的例子可以参见<span lang="EN-US">&lt;effective C++ (2nd)&gt;(</span>影印版<span lang="EN-US">)</span>第<span lang="EN-US">103-105</span>页<span lang="EN-US">)<br /></span>下面针对示例程序二<span lang="EN-US">, </span>分析在多线程情况下的不安全性<span lang="EN-US">.(</span>为方便描述<span lang="EN-US">, </span>标上行号<span lang="EN-US">)<br />
      ① const char * IpToStr(UINT32 IpAddr)<br />
      ② {<br />
      ③  static char strBuff[16]; // static</span>局部变量<span lang="EN-US">, </span>用于返回地址有效<span lang="EN-US"><br />
      ④  const unsigned char *pChIP = (const unsigned char *)&amp;IpAddr;<br />
      ⑤  sprintf(strBuff, "%u.%u.%u.%u",  pChIP[0],
      pChIP[1], pChIP[2], pChIP[3]);<br />
      ⑥  return strBuff;<br />
      ⑦ }<br /></span>假 设现在有两个线程<span lang="EN-US">A,B</span>运行期间都需要调用<span lang="EN-US">IpToStr()</span>函数<span lang="EN-US">, </span>将<span lang="EN-US">32</span>位的<span lang="EN-US">IP</span>地址转换成点分<span lang="EN-US">10</span>进制的字符串形式<span lang="EN-US">. </span>现<span lang="EN-US">A</span>先获得执行机会<span lang="EN-US">, </span>执行<span lang="EN-US">IpToStr(), </span>传入的参数是<span lang="EN-US">0x0B<st1:chmetcnv unitname="a" sourcevalue="90" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">090A</st1:chmetcnv><st1:chmetcnv unitname="a" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">0A</st1:chmetcnv>, </span>顺序执行完应该返回的指针存储区内容是<span lang="EN-US">:”<st1:chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">10.10.9</st1:chsdate>.11”,
      </span>现执行到<span lang="EN-US">⑥</span>时<span lang="EN-US">, </span>失去执行权<span lang="EN-US">, </span>调度到<span lang="EN-US">B</span>线程执行<span lang="EN-US">, B</span>线程传入的参数是<span lang="EN-US">0xA<st1:chmetcnv unitname="a" sourcevalue="8" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">8A</st1:chmetcnv><st1:chmetcnv unitname="a" sourcevalue="8" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">8A</st1:chmetcnv><st1:chmetcnv unitname="C" sourcevalue="8" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">8C</st1:chmetcnv>0, </span>执行至<span lang="EN-US">⑦, </span>静态存储区的内容是<span lang="EN-US">192.168.168.168. </span>当再调度到<span lang="EN-US">A</span>执行时<span lang="EN-US">, </span>从<span lang="EN-US">⑥</span>继续执行<span lang="EN-US">, </span>由于<span lang="EN-US">strBuff</span>的全局唯一性<span lang="EN-US">, </span>内容已经被<span lang="EN-US">B</span>线程冲掉<span lang="EN-US">, </span>此时返回的将是<span lang="EN-US">192.168.168.168</span>字符串<span lang="EN-US">, </span>不再是<span lang="EN-US">10.10.9.11</span>字符串<span lang="EN-US">.<o:p></o:p></span></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">二、外部静态变量／函数<span lang="EN-US"><br /></span>在<span lang="EN-US">C</span>中<span lang="EN-US">static</span>有了第二种含义：用来表示不能被其它文件访问的全局变量和函数。<span lang="EN-US">, </span>但为了限制全局变量<span lang="EN-US">/</span>函数的作用域<span lang="EN-US">, </span>函数或变量前加<span lang="EN-US">static</span>使得函数成为静态函数。但此处<span lang="EN-US">“static”</span>的含义不是指存储方式，而是指对函数的作用域仅局限于本文件<span lang="EN-US">(</span>所以又称内部函
      数<span lang="EN-US">)</span>。注意此时<span lang="EN-US">, </span>对于外部<span lang="EN-US">(</span>全局<span lang="EN-US">)</span>变量<span lang="EN-US">, </span>不论是否有<span lang="EN-US">static</span>限制<span lang="EN-US">, </span>它的存储区域都是在静态存储区<span lang="EN-US">, </span>生存期都是全局的<span lang="EN-US">. </span>此时的<span lang="EN-US">static</span>只是起作用域限制作用<span lang="EN-US">, </span>限定作用域在本模块<span lang="EN-US">(</span>文件<span lang="EN-US">)</span>内部<span lang="EN-US">.<br /></span>使用内部函数的好处是：不同的人编写不同的函数时，不用担心自己定义的函数，是否会与其它文件中的函数同名。<span lang="EN-US"><br /></span>示例程序三<span lang="EN-US">:<br />
       <br />
      //file1.cpp<o:p></o:p></span></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;" lang="EN-US">static int varA;<br />
      int varB;<br />
      extern void funA()<br />
      {<br />
      ……<br />
      }<o:p></o:p></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;" lang="EN-US">static void funB()<br />
      {<br />
      ……<br />
      }<o:p></o:p></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;" lang="EN-US">//file2.cpp<o:p></o:p></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;" lang="EN-US">extern int varB; // </span>
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">使用<span lang="EN-US">file1.cpp</span>中定义的全局变量<span lang="EN-US"><br />
      extern int varA; // </span>错误<span lang="EN-US">! varA</span>是<span lang="EN-US">static</span>类型<span lang="EN-US">, </span>无法在其他文件中使用<span lang="EN-US"><br />
      extern vod funA(); // </span>使用<span lang="EN-US">file1.cpp</span>中定义的函数<span lang="EN-US"><br />
      extern void funB(); // </span>错误<span lang="EN-US">! </span>无法使用<span lang="EN-US">file1.cpp</span>文件中<span lang="EN-US">static</span>函数<span lang="EN-US"><o:p></o:p></span></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;" lang="EN-US"> <o:p></o:p></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">三、静态数据成员／成员函数<span lang="EN-US">(C++</span>特有<span lang="EN-US">)<br />
      C++</span>重用了这个关键字，并赋予它与前面不同的第三种含义：表示属于一个类而不是属于此类的 任何特定对象的变量和函数<span lang="EN-US">. </span>这是与普通成员函数的最大区别<span lang="EN-US">, </span>也是其应用所在<span lang="EN-US">, </span>比如在对某一个类的对象进行计数时<span lang="EN-US">, </span>计数生成多少个类的实例<span lang="EN-US">, </span>就可以用到静态数据成员<span lang="EN-US">. </span>在这里面<span lang="EN-US">, static</span>既不是限定作用域的<span lang="EN-US">, </span>也不是扩展生存期的作用<span lang="EN-US">, </span>而是指示变量<span lang="EN-US">/</span>函数在此类中的唯一性<span lang="EN-US">. </span>这也是<span lang="EN-US">”</span>属于一个类而不是属于此类的任何特定对象的变量和函数<span lang="EN-US">”</span>的含义<span lang="EN-US">. </span>因为它是对整个类来说是唯一的<span lang="EN-US">, </span>因此不可能属于某一个实例对象的<span lang="EN-US">. (</span>针对静态数据成员而言<span lang="EN-US">, </span>成员函数不管是否是<span lang="EN-US">static, </span>在内存中只有一个副本<span lang="EN-US">, </span>普通成员函数调用时<span lang="EN-US">, </span>需要传入<span lang="EN-US">this</span>指针<span lang="EN-US">, static</span>成员函数调用时<span lang="EN-US">, </span>没有<span lang="EN-US">this</span>指针<span lang="EN-US">. )<br /></span>请看示例程序四<span lang="EN-US">(&lt;effective c++ (2nd)&gt;(</span>影印版<span lang="EN-US">)</span>第<span lang="EN-US">59</span>页<span lang="EN-US">)<br />
      class EnemyTarget {<br />
      public:<br />
        EnemyTarget() { ++numTargets; }<br />
        EnemyTarget(const EnemyTarget&amp;) { ++numTargets; }<br />
        ~EnemyTarget() { --numTargets; }<br />
        static size_t numberOfTargets() { return numTargets; }<br />
        bool destroy();   // returns success of attempt to
      destroy EnemyTarget object<br />
      private:<br />
        static size_t
      numTargets;              
      // object counter<br />
      };<br />
      // class statics must be defined outside the class;<br />
      // initialization is to 0 by default<br />
      size_t EnemyTarget::numTargets;<o:p></o:p></span></span>
																														</p>
																														<p class="MsoNormal" style="text-align: left; line-height: 150%;" align="left">
																																<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">在这个例子中<span lang="EN-US">, </span>静态数据成员<span lang="EN-US">numTargets</span>就是用来计数产生的对象个数的<span lang="EN-US">.<br /></span>另外<span lang="EN-US">, </span>在设计类的多线程操作时<span lang="EN-US">, </span>由于<span lang="EN-US">POSIX</span>库下的线程函数<span lang="EN-US">pthread_create()</span>要求是全局的<span lang="EN-US">, </span>普通成员函数无法直接做为线程函数<span lang="EN-US">, </span>可以考虑用<span lang="EN-US">Static</span>成员函数做线程函数<span lang="EN-US">.<o:p></o:p></span></span>
																														</p>
																												</td>
																										</tr>
																								</tbody>
																						</table>
																				</div>
																				<p class="MsoNormal" style="text-align: center;" align="center">
																						<span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">
																								<o:p>
																								</o:p>
																						</span>
																				</p>
																		</td>
																</tr>
														</tbody>
												</table>
										</div>
										<p class="MsoNormal" style="text-align: center;" align="center">
												<span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">
														<o:p>
														</o:p>
												</span>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p class="MsoNormal"> 
				<span lang="EN-US"><o:p></o:p></span></p>
		<b>
		</b>
		<table>
				<tbody>
						<tr>
								<td>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/swo2006/aggbug/11375.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-17 21:21 <a href="http://www.cppblog.com/swo2006/articles/11375.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++类库网站介绍</title><link>http://www.cppblog.com/swo2006/articles/11374.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Thu, 17 Aug 2006 12:53:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11374.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11374.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11374.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11374.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11374.html</trackback:ping><description><![CDATA[
		<font style="font-size: 14pt;" color="#295200">
				<b>C++类库网站介绍</b>
		</font>
		<table style="border-collapse: collapse;" border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<div style="margin: 15px;" id="art">
												<div>XMLBooster<br /><br />参考网站：http://www.xmlbooster.com/'&gt;http://www.xmlbooster.com/<br /><br />这个库通过产生特制的parser的办法极大的提高了XML解析的速度，并且能够产生相应的GUI程序来修改这个parser。在DOM和SAX两大主流XML解析办法之外提供了另外一个可行的解决方案。<br /><br />Pull Parser<br /><br />参考网站：http://www.extreme.indiana.edu/xgws/xsoap/xpp/'&gt;http://www.extreme.indiana.edu/xgws/xsoap/xpp/<br /><br />这个库采用pull方法的parser。在每个SAX的parser底层都有一个pull的parser，这个xpp把这层暴露出来直接给大家使用。在要充分考虑速度的时候值得尝试。<br /><br />Xalan<br /><br />参考网站：http://xml.apache.org/xalan-c/<br /><br />Xalan是一个用于把XML文档转换为HTML，纯文本或者其他XML类型文档的XSLT处理器。<br /><br />CMarkup<br /><br />参考网站：http://www.firstobject.com/xml.htm'&gt;http://www.firstobject.com/xml.htm<br /><br />这是一种使用EDOM的XML解析器。在很多思路上面非常灵活实用。值得大家在DOM和SAX之外寻求一点灵感。<br /><br />libxml++<br /><br />http://libxmlplusplus.sourceforge.net/<br /><br />libxml++是对著名的libxml XML解析器的C++封装版本<br /><br /> <br /><br />科学计算<br /><br />Blitz++<br /><br />参考网站：http://www.oonumerics.org/blitz/'&gt;http://www.oonumerics.org/blitz/<br /><br />Blitz++
是一个高效率的数值计算函数库，它的设计目的是希望建立一套既具像C++
一样方便，同时又比Fortran速度更快的数值计算环境。通常，用C++所写出的数值程序，比
Fortran慢20%左右，因此Blitz++正是要改掉这个缺点。方法是利用C++的template技术，程序执行甚至可以比Fortran更快。
Blitz++目前仍在发展中，对于常见的SVD，FFTs，QMRES等常见的线性代数方法并不提供，不过使用者可以很容易地利用Blitz++所提供
的函数来构建。<br /><br />POOMA<br /><br />参考网站：http://www.c'&gt;http://www.c'&gt;http://www.c'&gt;http://www.codesourcery.com/pooma/pooma<br /><br />POOMA是一个免费的高性能的C++库，用于处理并行式科学计算。POOMA的面向对象设计方便了快速的程序开发，对并行机器进行了优化以达到最高的效率，方便在工业和研究环境中使用。<br /><br />MTL<br /><br />参考网站：http://www.osl.iu.edu/research/mtl/'&gt;http://www.osl.iu.edu/research/mtl/<br /><br />Matrix Template Library(MTL)是一个高性能的泛型组件库，提供了各种格式矩阵的大量线性代数方面的功能。在某些应用使用高性能编译器的情况下，比如Intel的编译器，从产生的汇编代码可以看出其与手写几乎没有两样的效能。<br /><br />CGAL<br /><br />参考网站：www.cgal.org<br /><br />Computational Geometry Algorithms Library的目的是把在计算几何方面的大部分重要的解决方案和方法以C++库的形式提供给工业和学术界的用户。<br /><br /> <br /><br />游戏开发<br /><br />Audio/Video 3D C++ Programming Library<br /><br />参考网站：http://www.galacticasoftware.com/products/av/'&gt;http://www.galacticasoftware.com/products/av/<br /><br />AV3D是一个跨平台，高性能的C++库。主要的特性是提供3D图形，声效支持（SB,以及S3M），控制接口（键盘，鼠标和遥感），XMS。<br /><br />KlayGE<br /><br />参考网站：http://home.g365.net/enginedev/<br /><br />国内游戏开发高手自己用C++开发的游戏引擎。KlayGE是一个开放源代码、跨平台的游戏引擎，并使用Python作脚本语言。KlayGE在LGPL协议下发行。感谢龚敏敏先生为中国游戏开发事业所做出的贡献。<br /><br />OGRE<br /><br />参考网站：http://www.ogre3d.org'&gt;http://www.ogre3d.org<br /><br />OGRE
（面向对象的图形渲染引擎）是用C++开发的，使用灵活的面向对象3D引擎。它的目的是让开发者能更方便和直接地开发基于3D硬件设备的应用程序或游戏。
引擎中的类库对更底层的系统库（如：Direct3D和OpenGL）的全部使用细节进行了抽象，并提供了基于现实世界对象的接口和其它类。<br /><br /> <br /><br />线程<br /><br />C++ Threads<br /><br />参考网站：http://threads.sourceforge.net/<br /><br />这个库的目标是给程序员提供易于使用的类，这些类被继承以提供在Linux环境中很难看到的大量的线程方面的功能。<br /><br />ZThreads<br /><br />参考网站：http://zthread.sourceforge.net/<br /><br />一个先进的面向对象，跨平台的C++线程和同步库。<br /><br /> <br /><br />序列化<br /><br />s11n<br /><br />参考网站：http://s11n.net/<br /><br />一个基于STL的C++库，用于序列化POD，STL容器以及用户定义的类型。<br /><br />Simple XML Persistence Library<br /><br />参考网站：http://sxp.sourceforge.net/<br /><br />这是一个把对象序列化为XML的轻量级的C++库。<br /><br /> <br /><br />字符串<br /><br />C++ Str Library<br /><br />参考网站：http://www.utilitycode.com/str/'&gt;http://www.utilitycode.com/str/<br /><br />操作字符串和字符的库，支持Windows和支持gcc的多种平台。提供高度优化的代码，并且支持多线程环境和Unicode，同时还有正则表达式的支持。<br /><br />Common Text Transformation Library<br /><br />参考网站：http://cttl.sourceforge.net/<br /><br />这是一个解析和修改STL字符串的库。CTTL substring类可以用来比较，插入，替换以及用EBNF的语法进行解析。<br /><br />GRETA<br /><br />参考网站：http://research.microsoft.com/projects/greta/<br /><br />这是由微软研究院的研究人员开发的处理正则表达式的库。在小型匹配的情况下有非常优秀的表现。<br /><br />综合<br /><br />P::Classes<br /><br />参考网站：http://pclasses.com/<br /><br />一个高度可移植的C++应用程序框架。当前关注类型和线程安全的signal/slot机制，i/o系统包括基于插件的网络协议透明的i/o架构，基于插件的应用程序消息日志框架，访问sql数据库的类等等。<br /><br />ACDK - Artefaktur Component Development Kit<br /><br />参考网站：http://acdk.sourceforge.net/<br /><br />这是一个平台无关的C++组件框架，类似于Java或者.NET中的框架（反射机制，线程，Unicode，废料收集，I/O，网络，实用工具，XML，等等），以及对Java, Perl, Python, TCL, Lisp, COM 和 CORBA的集成。<br /><br />dlib C++ library<br /><br />参考网站：http://www.c'&gt;http://www.c'&gt;http://www.c'&gt;http://www.cis.ohio-state.edu/~kingd/dlib/<br /><br />各种各样的类的一个综合。大整数，Socket，线程，GUI，容器类,以及浏览目录的API等等。<br /><br />Chilkat C++ Libraries<br /><br />参考网站：http://www.c'&gt;http://www.c'&gt;http://www.c'&gt;http://www.chilkatsoft.com/cpp_libraries.asp<br /><br />这是提供zip，e-mail，编码，S/MIME，XML等方面的库。<br /><br />C++ Portable Types Library (PTypes)<br /><br />参考网站：http://www.melikyan.com/ptypes/'&gt;http://www.melikyan.com/ptypes/<br /><br />这是STL的比较简单的替代品，以及可移植的多线程和网络库。<br /><br />LFC<br /><br />参考网站：http://lfc.sourceforge.net/<br /><br />哦，这又是一个尝试提供一切的C++库<br /><br /> <br /><br />其他库<br /><br />Loki<br /><br />参
考网站：http://www.moderncppdesign.com/'&gt;http:
//www.moderncppdesign.com/'&gt;http://www.moderncppdesign.com/'&gt;http://www.moderncppdesign.com/<br /><br />哦，你可能抱怨我早该和Boost一起介绍它，一个实验性质的库。作者在loki中把C++模板的功能发挥到了极致。并且尝试把类似设计模式这样思想层面的东西通过库来提供。同时还提供了智能指针这样比较实用的功能。<br /><br />ATL<br /><br />ATL(Active Template Library)是一组小巧、高效、灵活的类，这些类为创建可互操作的COM组件提供了基本的设施。<br /><br />FC++: The Functional C++ Library<br /><br />这
个库提供了一些函数式语言中才有的要素。属于用库来扩充语言的一个代表作。如果想要在OOP之外寻找另一分的乐趣，可以去看看函数式程序设计的世界。大师
Peter Norvig在 "Teach Yourself Programming in Ten
Years"一文中就将函数式语言列为至少应当学习的6类编程语言之一。<br /><br />FACT!<br /><br />参考网站：http://www.kfa'&gt;http://www.kfa-juelich.de/zam/FACT/start/index.html<br /><br />另外一个实现函数式语言特性的库<br /><br />Crypto++<br /><br />提供处理密码，消息验证，单向hash，公匙加密系统等功能的免费库。<br /><br />还有很多非常激动人心或者是极其实用的C++库，限于我们的水平以及文章的篇幅不能包括进来。在对于这些已经包含近来的库的介绍中，由于并不是每一个我们都使用过，所以难免有偏颇之处，请读者见谅。<br /><br /> <br /><br />资源网站<br /><br />正
如我们可以通过计算机历史上的重要人物了解计算机史的发展，C++相关人物的网站也可以使我们得到最有价值的参考与借鉴，下面的人物我们认为没有介绍的必
要，只因下面的人物在C++领域的地位众所周知，我们只将相关的资源进行罗列以供读者学习，他们有的工作于贝尔实验室，有的工作于知名编译器厂商，有的在
不断推进语言的标准化，有的为读者撰写了多部千古奇作......<br /><br />Bjarne Stroustrup http://www.research.att.com/~bs/<br /><br />Stanley B. Lippman<br /><br />http:
//blogs.msdn.com/slippman/(中文版http://www.zengyihome.net/slippman/index.htm)<br /><br />Scott Meyers   http://www.aristeia.com/<br /><br />David Musser   http://www.cs.rpi.edu/~musser/<br /><br />Bruce Eckel    http://www.bruceeckel.com<br /><br />Nicolai M. Josuttis http://www.josuttis.com/<br /><br />Herb Sutter http://www.gotw.ca/<br /><br />Andrei
Alexandrescu  http://www.moderncppdesign.com/</div>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/swo2006/aggbug/11374.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-17 20:53 <a href="http://www.cppblog.com/swo2006/articles/11374.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解析C语言中的sizeof</title><link>http://www.cppblog.com/swo2006/articles/11367.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Thu, 17 Aug 2006 09:40:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11367.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11367.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11367.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11367.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11367.html</trackback:ping><description><![CDATA[
		<div>解析C语言中的sizeof </div>
		<div>一、sizeof的概念　 <br />　　sizeof是C语言的一种单目操作符，如C语言的其他操作符++、--等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。　 </div>
		<div>二、sizeof的使用方法　 <br />　　1、用于数据类型　 </div>
		<div>　　sizeof使用形式：sizeof（type）　 </div>
		<div>　　数据类型必须用括号括住。如sizeof（int）。　 </div>
		<div>　　2、用于变量　 </div>
		<div>　　sizeof使用形式：sizeof（var_name）或sizeof　var_name　 </div>
		<div>　　变量名可以不用括号括住。如sizeof　(var_name)，sizeof　var_name等都是正确形式。带括号的用法更普遍，大多数程序员采用这种形式。　 </div>
		<div>　　注意：sizeof操作符不能用于函数类型，不完全类型或位字段。不完全类型指具有未知存储大小的数据类型，如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。　 </div>
		<div>　　如sizeof(max)若此时变量max定义为int　max(),sizeof(char_v)　若此时char_v定义为char　char_v　[MAX]且MAX未知，sizeof(void)都不是正确形式。　 </div>
		<div>三、sizeof的结果　 <br />　　sizeof操作符的结果类型是size_t，它在头文件 </div>
		<div>中typedef为unsigned　int类型。该类型保证能容纳实现所建立的最大对象的字节大小。　 </div>
		<div>　　1、若操作数具有类型char、unsigned　char或signed　char，其结果等于1。　 </div>
		<div>　　ANSI　C正式规定字符类型为1字节。　 </div>
		<div>　　2、int、unsigned　int　、short　int、unsigned　short　、long　int　、unsigned　
long　、float、double、long　double类型的sizeof　在ANSI　C中没有具体规定，大小依赖于实现，一般可能分别为2、
2、2、2、4、4、4、8、10。　 </div>
		<div>　　3、当操作数是指针时，sizeof依赖于编译器。例如Microsoft　C/C++7.0中，near类指针字节数为2，far、huge类指针字节数为4。一般Unix的指针字节数为4。　 </div>
		<div>　　4、当操作数具有数组类型时，其结果是数组的总字节数。　 </div>
		<div>　　5、联合类型操作数的sizeof是其最大字节成员的字节数。结构类型操作数的sizeof是这种类型对象的总字节数，包括任何垫补在内。　 </div>
		<div>　　让我们看如下结构：　 </div>
		<div>　　struct　{char　b;　double　x;}　a;　 </div>
		<div>　　在某些机器上sizeof（a）=12，而一般sizeof（char）+　sizeof（double）=9。　 </div>
		<div>　　这是因为编译器在考虑对齐问题时，在结构中插入空位以控制各成员对象的地址对齐。如double类型的结构成员x要放在被4整除的地址。　 </div>
		<div>　　6、如果操作数是函数中的数组形参或函数类型的形参，sizeof给出其指针的大小。　 </div>
		<div>四、sizeof与其他操作符的关系　 <br />　　sizeof的优先级为2级，比/、%等3级运算符优先级高。它可以与其他操作符一起组成表达式。如i*sizeof（int）；其中i为int类型变量。　 </div>
		<div>五、sizeof的主要用途　 <br />　　1、sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如：　 </div>
		<div>　　void　*malloc（size_t　size）,　 </div>
		<div>　　size_t　fread(void　*　ptr,size_t　size,size_t　nmemb,FILE　*　stream)。　 </div>
		<div>　　2、sizeof的另一个的主要用途是计算数组中元素的个数。例如：　 </div>
		<div>　　void　*　memset（void　*　s,int　c,sizeof(s)）。　 </div>
		<div>六、建议　 <br />　　由于操作数的字节数在实现时可能出现变化，建议在涉及到操作数字节大小时用sizeof来代替常量计算。</div>
		<div>------------------------------------------------------------------</div>
		<div>本文主要包括二个部分，第一部分重点介绍在VC中，怎么样采用sizeof来求结构的大小，以及容易出现的问题，并给出解决问题的方法，第二部分总结出VC中sizeof的主要用法。 </div>
		<div>1、 sizeof应用在结构上的情况 </div>
		<div>请看下面的结构： </div>
		<div>struct MyStruct </div>
		<div>{ </div>
		<div>double dda1; </div>
		<div>char dda; </div>
		<div>int type </div>
		<div>}; </div>
		<div>对结构MyStruct采用sizeof会出现什么结果呢？sizeof(MyStruct)为多少呢？也许你会这样求： </div>
		<div>sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13 </div>
		<div>但是当在VC中测试上面结构的大小时，你会发现sizeof(MyStruct)为16。你知道为什么在VC中会得出这样一个结果吗？ </div>
		<div>其实，这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度，VC对一些变量的起始地址做了“对齐”处理。在默认情况下，VC规定各成
员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式(vc6.0,32位系统)。
</div>
		<div>类型 <br />对齐方式（变量存放的起始地址相对于结构的起始地址的偏移量） </div>
		<div>Char <br />偏移量必须为sizeof(char)即1的倍数 </div>
		<div>int <br />偏移量必须为sizeof(int)即4的倍数 </div>
		<div>float <br />偏移量必须为sizeof(float)即4的倍数 </div>
		<div>double <br />偏移量必须为sizeof(double)即8的倍数 </div>
		<div>Short <br />偏移量必须为sizeof(short)即2的倍数 </div>
		<div> </div>
		<div>各成员变量在存放的时候根据在结构中出现的顺序依次申请空间，同时按照上面的对齐方式调整位置，空缺的字节VC会自动填充。同时VC为了确保结
构的大小为结构的字节边界数（即该结构中占用最大空间的类型所占用的字节数）的倍数，所以在为最后一个成员变量申请空间后，还会根据需要自动填充空缺的字
节。 </div>
		<div>下面用前面的例子来说明VC到底怎么样来存放结构的。 </div>
		<div>struct MyStruct </div>
		<div>{ </div>
		<div>double dda1; </div>
		<div>char dda; </div>
		<div>int type </div>
		<div>}； </div>
		<div>为上面的结构分配空间的时候，VC根据成员变量出现的顺序和对齐方式，先为第一个成员dda1分配空间，其起始地址跟结构的起始地址相同（刚好
偏移量0刚好为sizeof(double)的倍数），该成员变量占用sizeof(double)=8个字节；接下来为第二个成员dda分配空间，这时
下一个可以分配的地址对于结构的起始地址的偏移量为8，是sizeof(char)的倍数，所以把dda存放在偏移量为8的地方满足对齐方式，该成员变量
占用sizeof(char)=1个字节；接下来为第三个成员type分配空间，这时下一个可以分配的地址对于结构的起始地址的偏移量为9，不是
sizeof(int)=4的倍数，为了满足对齐方式对偏移量的约束问题，VC自动填充3个字节（这三个字节没有放什么东西），这时下一个可以分配的地址
对于结构的起始地址的偏移量为12，刚好是sizeof(int)=4的倍数，所以把type存放在偏移量为12的地方，该成员变量占用sizeof
(int)=4个字节；这时整个结构的成员变量已经都分配了空间，总的占用的空间大小为：8+1+3+4=16，刚好为结构的字节边界数（即结构中占用最
大空间的类型所占用的字节数sizeof(double)=8）的倍数，所以没有空缺的字节需要填充。所以整个结构的大小为：sizeof
(MyStruct)=8+1+3+4=16，其中有3个字节是VC自动填充的，没有放任何有意义的东西。 </div>
		<div>下面再举个例子，交换一下上面的MyStruct的成员变量的位置，使它变成下面的情况： </div>
		<div>struct MyStruct </div>
		<div>{ </div>
		<div>char dda; </div>
		<div>double dda1; </div>
		<div>int type </div>
		<div>}； </div>
		<div>这个结构占用的空间为多大呢？在VC6.0环境下，可以得到sizeof(MyStruc)为24。结合上面提到的分配空间的一些原则，分析下VC怎么样为上面的结构分配空间的。（简单说明） </div>
		<div>struct MyStruct </div>
		<div>{ </div>
		<div>char dda;//偏移量为0，满足对齐方式，dda占用1个字节； </div>
		<div>double dda1;//下一个可用的地址的偏移量为1，不是sizeof(double)=8 </div>
		<div>//的倍数，需要补足7个字节才能使偏移量变为8（满足对齐 </div>
		<div>//方式），因此VC自动填充7个字节，dda1存放在偏移量为8 </div>
		<div>//的地址上，它占用8个字节。 </div>
		<div>int type；//下一个可用的地址的偏移量为16，是sizeof(int)=4的倍 </div>
		<div>//数，满足int的对齐方式，所以不需要VC自动填充，type存 </div>
		<div>//放在偏移量为16的地址上，它占用4个字节。 </div>
		<div>}；//所有成员变量都分配了空间，空间总的大小为1+7+8+4=20，不是结构 </div>
		<div>//的节边界数（即结构中占用最大空间的类型所占用的字节数sizeof </div>
		<div>//(double)=8）的倍数，所以需要填充4个字节，以满足结构的大小为 </div>
		<div>//sizeof(double)=8的倍数。 </div>
		<div> </div>
		<div>所以该结构总的大小为：sizeof(MyStruc)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的，没有放任何有意义的东西。 </div>
		<div> </div>
		<div>VC对结构的存储的特殊处理确实提高CPU存储变量的速度，但是有时候也带来了一些麻烦，我们也屏蔽掉变量默认的对齐方式，自己可以设定变量的对齐方式。 </div>
		<div>VC中提供了#pragma
pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况：第一、如果n大于等于该变量所占用的字节数，那么偏
移量必须满足默认的对齐方式，第二、如果n小于该变量的类型所占用的字节数，那么偏移量为n的倍数，不用满足默认的对齐方式。结构的总大小也有个约束条
件，分下面两种情况：如果n大于所有成员变量类型所占用的字节数，那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数； </div>
		<div>否则必须为n的倍数。下面举例说明其用法。 </div>
		<div>#pragma pack(push) //保存对齐状态 </div>
		<div>#pragma pack(4)//设定为4字节对齐 </div>
		<div>struct test </div>
		<div>{ </div>
		<div>char m1; </div>
		<div>double m4; </div>
		<div>int m3; </div>
		<div>}; </div>
		<div>#pragma pack(pop)//恢复对齐状态 </div>
		<div>以上结构的大小为16，下面分析其存储情况，首先为m1分配空间，其偏移量为0，满足我们自己设定的对齐方式（4字节对齐），m1占用1个字
节。接着开始为m4分配空间，这时其偏移量为1，需要补足3个字节，这样使偏移量满足为n=4的倍数（因为sizeof(double)大于n）,m4占
用8个字节。接着为m3分配空间，这时其偏移量为12，满足为4的倍数，m3占用4个字节。这时已经为所有成员变量分配了空间，共分配了16个字节，满足
为n的倍数。如果把上面的#pragma pack(4)改为#pragma
pack(16)，那么我们可以得到结构的大小为24。（请读者自己分析） </div>
		<div>2、 sizeof用法总结 </div>
		<div>在VC中，sizeof有着许多的用法，而且很容易引起一些错误。下面根据sizeof后面的参数对sizeof的用法做个总结。 </div>
		<div>A． 参数为数据类型或者为一般变量。例如sizeof(int),sizeof(long)等等。这种情况要注意的是不同系统系统或者不同编译器得到的结果可能是不同的。例如int类型在16位系统中占2个字节，在32位系统中占4个字节。 </div>
		<div>B． 参数为数组或指针。下面举例说明. </div>
		<div>int a[50]; //sizeof(a)=4*50=200; 求数组所占的空间大小 </div>
		<div>int *a=new int[50];// sizeof(a)=4; a为一个指针，sizeof(a)是求指针 </div>
		<div>//的大小,在32位系统中，当然是占4个字节。 </div>
		<div>C． 参数为结构或类。Sizeof应用在类和结构的处理情况是相同的。但有两点需要注意，第一、结构或者类中的静态成员不对结构或者类的大小产生影响，因为静态变量的存储位置与结构或者类的实例地址无关。 </div>
		<div>第二、没有成员变量的结构或类的大小为1，因为必须保证结构或类的每一 </div>
		<div>个实例在内存中都有唯一的地址。 </div>
		<div>下面举例说明， </div>
		<div>Class Test{int a;static double c};//sizeof(Test)=4. </div>
		<div>Test *s;//sizeof(s)=4,s为一个指针。 </div>
		<div>Class test1{ };//sizeof(test1)=1; </div>
		<div>D． 参数为其他。下面举例说明。 </div>
		<div>int func(char s[5]); </div>
		<div>{ </div>
		<div>cout&lt; <br />//数的参数在传递的时候系统处理为一个指针，所 </div>
		<div>//以sizeof(s)实际上为求指针的大小。 </div>
		<div>return 1; </div>
		<div>} </div>
		<div>sizeof(func(“1234”))=4//因为func的返回类型为int，所以相当于 </div>
		<div>//求sizeof(int). </div>
		<div> </div>
		<div>以上为sizeof的基本用法，在实际的使用中要注意分析VC的分配变量的分配策略，这样的话可以避免一些错误。 </div>
		<div>-------------------------------------------------------------------</div>
		<div>sizeof详解</div>
		<div>1、什么是sizeof</div>
		<div>    首先看一下sizeof在msdn上的定义：</div>
		<div>    The sizeof keyword gives the amount of storage, in bytes,
associated with a variable or a type (including aggregate types). This
keyword returns a value of type size_t.</div>
		<div>   
看到return这个字眼，是不是想到了函数？错了，sizeof不是一个函数，你见过给一个函数传参数，而不加括号的吗？sizeof可以，所以
sizeof不是函数。网上有人说sizeof是一元操作符，但是我并不这么认为，因为sizeof更像一个特殊的宏，它是在编译阶段求值的。举个例子：</div>
		<div>cout&lt;&lt;sizeof(int)&lt;&lt;endl; // 32位机上int长度为4<br />cout&lt;&lt;sizeof(1==2)&lt;&lt;endl; // == 操作符返回bool类型，相当于 cout&lt;&lt;sizeof(bool)&lt;&lt;endl;</div>
		<div>    在编译阶段已经被翻译为：</div>
		<div>cout&lt;&lt;4&lt;&lt;endl;<br />cout&lt;&lt;1&lt;&lt;endl;</div>
		<div>    这里有个陷阱，看下面的程序：</div>
		<div>int a = 0;<br />cout&lt;&lt;sizeof(a=3)&lt;&lt;endl;<br />cout&lt;&lt;a&lt;&lt;endl;</div>
		<div>   
输出为什么是4，0而不是期望中的4，3？？？就在于sizeof在编译阶段处理的特性。由于sizeof不能被编译成机器码，所以sizeof作用范围
内，也就是()里面的内容也不能被编译，而是被替换成类型。=操作符返回左操作数的类型，所以a=3相当于int，而代码也被替换为：</div>
		<div>int a = 0;<br />cout&lt;&lt;4&lt;&lt;endl;<br />cout&lt;&lt;a&lt;&lt;endl;</div>
		<div>    所以，sizeof是不可能支持链式表达式的，这也是和一元操作符不一样的地方。</div>
		<div>    结论：不要把sizeof当成函数，也不要看作一元操作符，把他当成一个特殊的编译预处理。</div>
		<div>2、sizeof的用法</div>
		<div>    sizeof有两种用法：<br />  <br />    （1）sizeof(object)<br />    也就是对对象使用sizeof，也可以写成sizeof object 的形式。例如：</div>
		<div>    （2）sizeof(typename)<br />    也就是对类型使用sizeof，注意这种情况下写成sizeof typename是非法的。下面举几个例子说明一下：</div>
		<div>
				<br />int i = 2;<br />cout&lt;&lt;sizeof(i)&lt;&lt;endl; // sizeof(object)的用法，合理<br />cout&lt;&lt;sizeof i&lt;&lt;endl; // sizeof object的用法，合理<br />cout&lt;&lt;sizeof 2&lt;&lt;endl; // 2被解析成int类型的object, sizeof object的用法，合理<br />cout&lt;&lt;sizeof(2)&lt;&lt;endl; // 2被解析成int类型的object, sizeof(object)的用法，合理<br />cout&lt;&lt;sizeof(int)&lt;&lt;endl;// sizeof(typename)的用法，合理<br />cout&lt;&lt;sizeof int&lt;&lt;endl; // 错误！对于操作符，一定要加()</div>
		<div>    可以看出，加()是永远正确的选择。</div>
		<div>    结论：不论sizeof要对谁取值，最好都加上()。</div>
		<div>
				<br />3、数据类型的sizeof</div>
		<div>（1）C++固有数据类型</div>
		<div>    32位C++中的基本数据类型，也就char,short int(short),int,long int(long),float,double, long double<br />大小分别是：1，2，4，4，4，8, 10。</div>
		<div>    考虑下面的代码：</div>
		<div>cout&lt;&lt;sizeof(unsigned int) == sizeof(int)&lt;&lt;endl; // 相等，输出 1</div>
		<div>    unsigned影响的只是最高位bit的意义，数据长度不会被改变的。</div>
		<div>    结论：unsigned不能影响sizeof的取值。</div>
		<div>（2）自定义数据类型</div>
		<div>    typedef可以用来定义C++自定义类型。考虑下面的问题：</div>
		<div>typedef short WORD;<br />typedef long DWORD;<br />cout&lt;&lt;(sizeof(short) == sizeof(WORD))&lt;&lt;endl; // 相等，输出1<br />cout&lt;&lt;(sizeof(long) == sizeof(DWORD))&lt;&lt;endl; // 相等，输出1</div>
		<div>    结论：自定义类型的sizeof取值等同于它的类型原形。</div>
		<div>（3）函数类型</div>
		<div>    考虑下面的问题：</div>
		<div>int f1(){return 0;};<br />double f2(){return 0.0;}<br />void f3(){}</div>
		<div>cout&lt;&lt;sizeof(f1())&lt;&lt;endl; // f1()返回值为int，因此被认为是int<br />cout&lt;&lt;sizeof(f2())&lt;&lt;endl; // f2()返回值为double，因此被认为是double<br />cout&lt;&lt;sizeof(f3())&lt;&lt;endl; // 错误！无法对void类型使用sizeof<br />cout&lt;&lt;sizeof(f1)&lt;&lt;endl;  // 错误！无法对函数指针使用sizeof   <br />cout&lt;&lt;sizeof*f2&lt;&lt;endl;  // *f2，和f2()等价，因为可以看作object，所以括号不是必要的。被认为是double</div>
		<div>    结论：对函数使用sizeof，在编译阶段会被函数返回值的类型取代，</div>
		<div>4、指针问题</div>
		<div>    考虑下面问题：</div>
		<div>cout&lt;&lt;sizeof(string*)&lt;&lt;endl; // 4<br />cout&lt;&lt;sizeof(int*)&lt;&lt;endl; // 4<br />cout&lt;&lt;sizof(char****)&lt;&lt;endl; // 4</div>
		<div>    可以看到，不管是什么类型的指针，大小都是4的，因为指针就是32位的物理地址。</div>
		<div>    结论：只要是指针，大小就是4。（64位机上要变成8也不一定）。</div>
		<div>   
顺便唧唧歪歪几句，C++中的指针表示实际内存的地址。和C不一样的是，C++中取消了模式之分，也就是不再有small,middle,big,取而代
之的是统一的flat。flat模式采用32位实地址寻址，而不再是c中的 segment:offset模式。举个例子，假如有一个指向地址
f000:8888的指针，如果是C类型则是8888(16位,
只存储位移，省略段)，far类型的C指针是f0008888(32位，高位保留段地址，地位保留位移),C++类型的指针是f8888(32位，相当于
段地址*16 + 位移，但寻址范围要更大)。</div>
		<div>5、数组问题</div>
		<div>    考虑下面问题：</div>
		<div>char a[] = "abcdef";<br />int b[20] = {3, 4};<br />char c[2][3] = {"aa", "bb"};</div>
		<div>
				<br />cout&lt;&lt;sizeof(a)&lt;&lt;endl; // 7<br />cout&lt;&lt;sizeof(b)&lt;&lt;endl; // 20<br />cout&lt;&lt;sizeof(c)&lt;&lt;endl; // 6</div>
		<div>
				<br />    数组a的大小在定义时未指定，编译时给它分配的空间是按照初始化的值确定的，也就是7。c是多维数组，占用的空间大小是各维数的乘积，也就是6。可以看出，数组的大小就是他在编译时被分配的空间，也就是各维数的乘积*数组元素的大小。</div>
		<div>    结论：数组的大小是各维数的乘积*数组元素的大小。</div>
		<div>    这里有一个陷阱：</div>
		<div>int *d = new int[10];</div>
		<div>cout&lt;&lt;sizeof(d)&lt;&lt;endl; // 4</div>
		<div>    d是我们常说的动态数组，但是他实质上还是一个指针，所以sizeof(d)的值是4。</div>
		<div>    再考虑下面的问题：</div>
		<div>double* (*a)[3][6];</div>
		<div>cout&lt;&lt;sizeof(a)&lt;&lt;endl;  // 4<br />cout&lt;&lt;sizeof(*a)&lt;&lt;endl;  // 72<br />cout&lt;&lt;sizeof(**a)&lt;&lt;endl; // 24<br />cout&lt;&lt;sizeof(***a)&lt;&lt;endl; // 4<br />cout&lt;&lt;sizeof(****a)&lt;&lt;endl; // 8</div>
		<div>    a是一个很奇怪的定义，他表示一个指向 double*[3][6]类型数组的指针。既然是指针，所以sizeof(a)就是4。</div>
		<div>   
既然a是执行double*[3][6]类型的指针，*a就表示一个double*[3][6]的多维数组类型，因此sizeof(*a)=
3*6*sizeof(double*)=72。同样的，**a表示一个double*[6]类型的数组，所以sizeof(**a)=6*sizeof
(double*)=24。***a就表示其中的一个元素，也就是double*了，所以sizeof(***a)=4。至于****a，就是一个
double了，所以sizeof(****a)=sizeof(double)=8。<br />6、向函数传递数组的问题。</div>
		<div>    考虑下面的问题：<br />#include &lt;iostream&gt;<br />using namespace std;</div>
		<div>int Sum(int i[])<br />{<br />int sumofi = 0;<br />for (int j = 0; j &lt; sizeof(i)/sizeof(int); j++) //实际上，sizeof(i) = 4<br />{<br />  sumofi += i[j];<br />}<br />return sumofi;<br />}</div>
		<div>int main()<br />{<br />int allAges[6] = {21, 22, 22, 19, 34, 12};<br />cout&lt;&lt;Sum(allAges)&lt;&lt;endl;<br />system("pause");<br />return 0;<br />}</div>
		<div>    Sum的本意是用sizeof得到数组的大小，然后求和。但是实际上，传入自函数Sum的，只是一个int 类型的指针，所以sizeof(i)=4，而不是24，所以会产生错误的结果。解决这个问题的方法使是用指针或者引用。</div>
		<div>    使用指针的情况：<br />int Sum(int (*i)[6])<br />{<br />int sumofi = 0;<br />for (int j = 0; j &lt; sizeof(*i)/sizeof(int); j++) //sizeof(*i) = 24<br />{<br />  sumofi += (*i)[j];<br />}<br />return sumofi;<br />}</div>
		<div>int main()<br />{<br />int allAges[] = {21, 22, 22, 19, 34, 12};<br />cout&lt;&lt;Sum(&amp;allAges)&lt;&lt;endl;<br />system("pause");<br />return 0;<br />}<br />   
在这个Sum里，i是一个指向i[6]类型的指针，注意，这里不能用int Sum(int
(*i)[])声明函数，而是必须指明要传入的数组的大小，不然sizeof(*i)无法计算。但是在这种情况下，再通过sizeof来计算数组大小已经
没有意义了，因为此时大小是指定为6的。<br />使用引用的情况和指针相似：</div>
		<div>int Sum(int (&amp;i)[6])<br />{<br />int sumofi = 0;<br />for (int j = 0; j &lt; sizeof(i)/sizeof(int); j++)<br />{<br />  sumofi += i[j];<br />}<br />return sumofi;<br />}</div>
		<div>int main()<br />{<br />int allAges[] = {21, 22, 22, 19, 34, 12};<br />cout&lt;&lt;Sum(allAges)&lt;&lt;endl;<br />system("pause");<br />return 0;<br />}<br />    这种情况下sizeof的计算同样无意义，所以用数组做参数，而且需要遍历的时候，函数应该有一个参数来说明数组的大小，而数组的大小在数组定义的作用域内通过sizeof求值。因此上面的函数正确形式应该是：<br />#include &lt;iostream&gt;<br />using namespace std;</div>
		<div>int Sum(int *i, unsigned int n)<br />{<br />int sumofi = 0;<br />for (int j = 0; j &lt; n; j++)<br />{<br />  sumofi += i[j];<br />}<br />return sumofi;<br />}</div>
		<div>int main()<br />{<br />int allAges[] = {21, 22, 22, 19, 34, 12};<br />cout&lt;&lt;Sum(i, sizeof(allAges)/sizeof(int))&lt;&lt;endl;<br />system("pause");<br />return 0;<br />}</div>
		<div>7、字符串的sizeof和strlen</div>
		<div>    考虑下面的问题：</div>
		<div>char a[] = "abcdef";<br />char b[20] = "abcdef";<br />string s = "abcdef";</div>
		<div>cout&lt;&lt;strlen(a)&lt;&lt;endl;  // 6，字符串长度<br />cout&lt;&lt;sizeof(a)&lt;&lt;endl;  // 7，字符串容量<br />cout&lt;&lt;strlen(b)&lt;&lt;endl;  // 6，字符串长度<br />cout&lt;&lt;strlen(b)&lt;&lt;endl;  // 20，字符串容量<br />cout&lt;&lt;sizeof(s)&lt;&lt;endl;  // 12, 这里不代表字符串的长度，而是string类的大小<br />cout&lt;&lt;strlen(s)&lt;&lt;endl;  // 错误！s不是一个字符指针。</div>
		<div>a[1] = '\0';<br />cout&lt;&lt;strlen(a)&lt;&lt;endl;  // 1<br />cout&lt;&lt;sizeof(a)&lt;&lt;endl;  // 7，sizeof是恒定的</div>
		<div>
				<br />   
strlen是寻找从指定地址开始，到出现的第一个0之间的字符个数，他是在运行阶段执行的，而sizeof是得到数据的大小，在这里是得到字符串的容
量。所以对同一个对象而言，sizeof的值是恒定的。string是C++类型的字符串，他是一个类，所以sizeof(s)表示的并不是字符串的长
度，而是类string的大小。strlen(s)根本就是错误的，因为strlen的参数是一个字符指针，如果想用strlen得到s字符串的长度，应
该使用sizeof(s.c_str())，因为string的成员函数c_str()返回的是字符串的首地址。实际上，string类提供了自己的成员
函数来得到字符串的容量和长度，分别是Capacity()和Length()。string封装了常用了字符串操作，所以在C++开发过程中，最好使用
string代替C类型的字符串。</div>
		<div>
				<br />8、从union的sizeof问题看cpu的对界</div>
		<div>    考虑下面问题：（默认对齐方式）</div>
		<div>union u<br />{<br />  double a;<br />  int b;<br />};</div>
		<div>union u2<br />{<br />  char a[13];<br />  int b;<br />};</div>
		<div>union u3<br />{<br />  char a[13];<br />  char b;<br />};</div>
		<div>cout&lt;&lt;sizeof(u)&lt;&lt;endl;  // 8<br />cout&lt;&lt;sizeof(u2)&lt;&lt;endl;  // 16<br />cout&lt;&lt;sizeof(u3)&lt;&lt;endl;  // 13</div>
		<div>   
都知道union的大小取决于它所有的成员中，占用空间最大的一个成员的大小。所以对于u来说，大小就是最大的double类型成员a了，所以
sizeof(u)=sizeof(double)=8。但是对于u2和u3，最大的空间都是char[13]类型的数组，为什么u3的大小是13，而
u2是16呢？关键在于u2中的成员int
b。由于int类型成员的存在，使u2的对齐方式变成4，也就是说，u2的大小必须在4的对界上，所以占用的空间变成了16（最接近13的对界）。</div>
		<div>    结论：复合数据类型，如union，struct，class的对齐方式为成员中对齐方式最大的成员的对齐方式。</div>
		<div>   
顺便提一下CPU对界问题，32的C++采用8位对界来提高运行速度，所以编译器会尽量把数据放在它的对界上以提高内存命中率。对界是可以更改的，使用
#pragma
pack(x)宏可以改变编译器的对界方式，默认是8。C++固有类型的对界取编译器对界方式与自身大小中较小的一个。例如，指定编译器按2对界，int
类型的大小是4，则int的对界为2和4中较小的2。在默认的对界方式下，因为几乎所有的数据类型都不大于默认的对界方式8（除了long
double），所以所有的固有类型的对界方式可以认为就是类型自身的大小。更改一下上面的程序：</div>
		<div>#pragma pack(2)<br />union u2<br />{<br />  char a[13];<br />  int b;<br />};</div>
		<div>union u3<br />{<br />  char a[13];<br />  char b;<br />};<br />#pragma pack(8)</div>
		<div>cout&lt;&lt;sizeof(u2)&lt;&lt;endl;  // 14<br />cout&lt;&lt;sizeof(u3)&lt;&lt;endl;  // 13</div>
		<div>    由于手动更改对界方式为2，所以int的对界也变成了2，u2的对界取成员中最大的对界，也是2了，所以此时sizeof(u2)=14。</div>
		<div>    结论：C++固有类型的对界取编译器对界方式与自身大小中较小的一个。</div>
		<div>9、struct的sizeof问题</div>
		<div>    因为对齐问题使结构体的sizeof变得比较复杂，看下面的例子：(默认对齐方式下)</div>
		<div>struct s1<br />{<br />  char a;<br />  double b;<br />  int c;<br />  char d; <br />};</div>
		<div>struct s2<br />{<br />  char a;<br />  char b;<br />  int c;<br />  double d;<br />};</div>
		<div>cout&lt;&lt;sizeof(s1)&lt;&lt;endl; // 24<br />cout&lt;&lt;sizeof(s2)&lt;&lt;endl; // 16</div>
		<div>   
同样是两个char类型，一个int类型，一个double类型，但是因为对界问题，导致他们的大小不同。计算结构体大小可以采用元素摆放法，我举例子说
明一下：首先，CPU判断结构体的对界，根据上一节的结论，s1和s2的对界都取最大的元素类型，也就是double类型的对界8。然后开始摆放每个元
素。<br />   
对于s1，首先把a放到8的对界，假定是0，此时下一个空闲的地址是1，但是下一个元素d是double类型，要放到8的对界上，离1最接近的地址是8
了，所以d被放在了8，此时下一个空闲地址变成了16，下一个元素c的对界是4，16可以满足，所以c放在了16，此时下一个空闲地址变成了20，下一个
元素d需要对界1，也正好落在对界上，所以d放在了20，结构体在地址21处结束。由于s1的大小需要是8的倍数，所以21-23的空间被保留，s1的大
小变成了24。<br />   
对于s2，首先把a放到8的对界，假定是0，此时下一个空闲地址是1，下一个元素的对界也是1，所以b摆放在1，下一个空闲地址变成了2；下一个元素c的
对界是4，所以取离2最近的地址4摆放c，下一个空闲地址变成了8，下一个元素d的对界是8，所以d摆放在8，所有元素摆放完毕，结构体在15处结束，占
用总空间为16，正好是8的倍数。</div>
		<div>    这里有个陷阱，对于结构体中的结构体成员，不要认为它的对齐方式就是他的大小，看下面的例子：</div>
		<div>struct s1<br />{<br />  char a[8];<br />};</div>
		<div>struct s2<br />{<br />  double d;<br />};</div>
		<div>struct s3<br />{<br />  s1 s;<br />  char a;<br />};</div>
		<div>struct s4<br />{<br />  s2 s;<br />  char a; <br />};</div>
		<div>cout&lt;&lt;sizeof(s1)&lt;&lt;endl; // 8<br />cout&lt;&lt;sizeof(s2)&lt;&lt;endl; // 8<br />cout&lt;&lt;sizeof(s3)&lt;&lt;endl; // 9<br />cout&lt;&lt;sizeof(s4)&lt;&lt;endl; // 16;</div>
		<div>    s1和s2大小虽然都是8，但是s1的对齐方式是1，s2是8（double），所以在s3和s4中才有这样的差异。</div>
		<div>    所以，在自己定义结构体的时候，如果空间紧张的话，最好考虑对齐因素来排列结构体里的元素。</div>
		<div>10、不要让double干扰你的位域</div>
		<div>    在结构体和类中，可以使用位域来规定某个成员所能占用的空间，所以使用位域能在一定程度上节省结构体占用的空间。不过考虑下面的代码：</div>
		<div>struct s1<br />{<br />  int i: 8;<br />  int j: 4;<br />  double b;<br />  int a:3;<br />};</div>
		<div>struct s2<br />{<br />  int i;<br />  int j;<br />  double b;<br />  int a;<br />};</div>
		<div>struct s3<br />{<br />  int i;<br />  int j;<br />  int a;<br />  double b;<br />};</div>
		<div>struct s4<br />{<br />  int i: 8;<br />  int j: 4;<br />  int a:3;<br />  double b;<br />};</div>
		<div>cout&lt;&lt;sizeof(s1)&lt;&lt;endl;  // 24<br />cout&lt;&lt;sizeof(s2)&lt;&lt;endl;  // 24<br />cout&lt;&lt;sizeof(s3)&lt;&lt;endl;  // 24<br />cout&lt;&lt;sizeof(s4)&lt;&lt;endl;  // 16</div>
		<div>    可以看到，有double存在会干涉到位域（sizeof的算法参考上一节），所以使用位域的的时候，最好把float类型和double类型放在程序的开始或者最后。</div>
<img src ="http://www.cppblog.com/swo2006/aggbug/11367.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-17 17:40 <a href="http://www.cppblog.com/swo2006/articles/11367.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Exceptional C++ 读书笔记</title><link>http://www.cppblog.com/swo2006/articles/11351.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Thu, 17 Aug 2006 07:34:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11351.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11351.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11351.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11351.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11351.html</trackback:ping><description><![CDATA[
		<div>Exceptional C++ 读书笔记</div>
		<div>
				<br /> //内存管理的一部分来自于<a href="http://blog.csdn.net/kingofark/category/9109.aspx">http://blog.csdn.net/kingofark/category/9109.aspx</a></div>
		<div> Item 1 Iterator: <br />   <br /> （1）: 注意当前迭代器是否有效，如果无效则解引用产生程序错误；<br /> （2）：注意当前迭代器生命期，某些容器经过某些操作后将重新分配内部存储空间，则当前迭代器无效;<br /> (3) : 有效范围, 类似find(first, last, value)时, 迭代器first 必须在last之前,必须保证指向同一个容器;<br />       (4): 有效的内部操作;</div>
		<div>
				<br /> Item 2, 3: Case-Insensitive String<br />      <br /> (1) 1 关于std::string: std::string实际是<br />  template&lt;class charT, class traits = char_traits&lt;charT&gt;, class Allocator = allocator&lt;charT&gt; &gt;<br />  class basic_string;</div>
		<div>  typedef basic_string&lt;char&gt; string;</div>
		<div>  要实现case-insensitive string需要改变string的compare方式,因为char_traits&lt;char&gt;类提供compare等方式,所以<br />  就需要对char_traits&lt;char&gt;作相应的变动;<br />  char_traits::eq()和lt()提供相等和小于的对比方式,compare()和find()提供对比和搜索字符串序列的功能;更改这四个成员函数  就可以实现case-insensitive string;</div>
		<div> (2)关于实际应用中,最好选用一个单一的函数去接受两个相应的std::string对象,而非用更改traits的方法来实现一个ci_string;<br /> 例如 bool CaseInsensitiveString(std::string &amp;a, std::string &amp;b)</div>
		<div> (3)类似ci_char_traits : public char_traits&lt;char&gt;,
用于变换traits或者iterator功能等情形,而非当作传统的OO方式来使用时,可以当作合理的派生,不必考虑virtual
destructor等;</div>
		<div> </div>
		<div> Item 4, 5 Max Reusable Generic Containers</div>
		<div> (1) template constructor永远不会是一个copy constructor, 因为永远存在一个最适合的copy
constructor, 因此overload resolution决不会将template constructor 当作copy
constructor <br /> <br /> (2) 善于使用模板成员函数</div>
		<div>
				<br /> Item 6, 7 Temporary Objects<br /> <br /> (1) a: 用传递const T&amp; 代替传值;<br />         b: 用预先创建的对象代替不需要的重复创建的对象,类似(container.end()每次被调用将返回一个临时的对象,这是不必要的);<br />     c: 用++T 代替 T++ (因为T++ 一般先制造一个临时对象,然后更新本身,最后返回临时对象);<br />         d: 用++T来实现T++;<br />     e: 避免做无用的隐式转换;<br /> <br /> (2) 注意对象生命期,绝不准让函数返回一个函数内部的auto变量的指针或者引用;</div>
		<div> (3) 多用标准库的代码;</div>
		<div>
				<br /> Item 8 -- 17 Writing Exception-Safe Code</div>
		<div> （1）当一个函数不能处理内部的异常时，应当将它抛给函数调用者去处理；<br /> (2) 当异常出现时，请让资源正确的被释放，数据处于一个稳定的状态；<br /> （3）绝不能让从destructor或者被重载的delete中抛出，写析构函数和资源分配函数时应当写上throw(); <br /> (4)先将所有可能抛出异常的操作和安全的的操作分离出来，当可能抛出异常的操作执行成功时，再用no throw操作改变对象状态；<br /> （5）让每一个代码片段（类，模块，函数）负责单一的任务，类似STL stack中的pop和top是分离的<br /> <br /> (6): exception-safe基本准则:</div>
		<div>  A: 基本安全: 当异常抛出时不产生资源泄漏；<br />  B: 健壮的安全性：如果某个操作因为异常的抛出而终止，则对象当前状态不应改变；<br />  C: 不抛出异常： 约定这个函数决不抛出异常；</div>
		<div> <br /> (7): 将资源管理单独的封装成一个类类似书上的例子 StackImpl封装了内存管理功能<br /> (8): 多用聚合,少用继承(包括这种聚合 pivate继承 -- 因为这将导致在constructor中无法控制base class</div>
		<div> (9): 用资源申请既初始化来隔离类的实现和资源的管理与所有权<br /> <br /> (10): 什么时候应当用private继承代替containment?<br />  a: 需要存取某个类的protected成员<br />  b: 需要覆写虚函数<br />  c: base 对象需要在其他类对象建构之前建构</div>
		<div> (11): 析构函数中决不允许抛出异常:<br />  a: 对象本身所申请的的资源不能完全释放；<br />  b：考虑 T t[20];的情况；析构某个T时抛出异常会产生未定义情况<br />  <br />Item 18, 19 Code Complexity</div>
		<div> (1): 提供强异常安全需要损失一定程度的性能;<br /> (2): 如果一个函数存在几个不相关的副作用,那么它不可能实现异常安全, 否则应当把这几个函数分割为不同的函数<br /> (3): 不是所有的函数都需要强异常安全;</div>
		<div>
				<br /> Item 20 Class Mechanics<br /> (1): 设计时首先考虑标准库是否存在相关的类<br /> (2):  用explicit constructor代替隐式转换<br /> (3): 如果提供一个常规的operator op(类似+)，那么应该同样提供一个operator op=(+=),<br />  operator op(类似的 + - * /)不应该改变对象值, 它应当返回一个 + 操作后的临时对象；<br /> (4): 多用a op= b 代替 a = a op b； 一般 const T operator op(T, T)产生一个临时变量；<br /> <br /> (5)  一元运算符是成员函数<br />       =，（），[]和-&gt;必须是成员函数<br />       +=，-=，/=，*=（等等）是成员函数<br />       所有其它的二元运算符是非成员函数</div>
		<div> (6) ++T 应当返回一个引用， T++应当返回一个const T，以防止 T++++这种情况发生；T++应当由++T来实现；<br /> (7) 避免使用前导下划线来命名，前导下划线是留给编译器使用的<br /> </div>
		<div> Item 21 override 虚函数 <br /> (1): 除非确定某个类不被派生,否则都应当提供一个虚函数;<br /> (2): 关于 overload, override和 hide<br />  a: overload意思是提供一个相同名称但是不同参数的函数， 编译时由编译器决定哪个是最匹配的函数<br />  b: override意思是在派生类提供一个相同名称且相同参数不同实现的虚函数，动态调用时将从派生类指针调用这个函数<br />  c: hide 某个函数的意思是有一个函数在某个范围内(派生类，嵌套类，名称空间等），隐藏同名函数<br />  <br /> （3） 当派生类提供一个和基类的某个成员函数同名的函数时,如果你不想隐藏基类的同名函数,请在派生类声明基类的同名函数,<br />  例如: using Base::f;<br /> (4) 永远不要在派生类override virtual function中改变默认参数;<br /> </div>
		<div> Item 22, 23 Class Relationships<br /> (1): 什么时候不应该选用public 继承<br />      a: 如果某个类为提供虚函数，这个类本身不打算实施多态；<br />      b: 如果某个类未提供protected 成员<br />      c: 类型为不是IS-A, WORKS-LIKE-A or USABLE-AS-A;<br />      d: 派生类只用了基类的public 成员；</div>
		<div> (2): 只有当需要存取某个类protected 成员或者override 虚函数的时候才应该选用private继承；不是IS-A, WORKS-LIKE-A or <br />      USABLE-AS-A的时候决不应当用public 继承;<br /> <br /> (3): 避免提供public virtual function, 使用template method 设计模式代替；从算法中提取出那些每次都要进行的步骤，将其抽象出  来，只把一些因地制宜的细节通过virtual function 留给派生类来实现。<br /> (4): 应用compiler-firewall 方法隐藏实现细节,使用一个不透明的指针(指向一个声明但未定义的类<br />  (struct xxxImpl; xxxImpl *pimpl_)来存private 成员，包括状态变量和成员函数）；<br />  例如: clas Map { private: struct MapImpl; MapImpl *pimpl_; };<br /> </div>
		<div> </div>
		<div> Item 24 Uses and Abuses of Inheritance<br /> (1): 多用聚合，（containment, composition, layering HAS-A, delegation),当关系模型为 IS-IMPLEMENTED-IN-TERMS-OF时，请多考虑聚合，最好不用继承；</div>
		<div> (2): 非public 继承的条件:<br />  a: 当需要override virtual function时候;<br />  b: 需要存取基类protected成员时候<br />  c: 需要保证初始化顺序的时候(基类必须建构在派生类之前,析构在派生类之后等情况);<br />  d: 需要某种多态的访问控制时；</div>
		<div> （3）： 用public继承时应当避免的问题：<br />  a: 如果非public继承可以做，那么决不要用public继承；绝不能用public继承表述一个依据什么实现的关系模型;<br />  b: 绝不能用public继承表述一个 IS-ALMOST-A关系模型(类似正方形是一个矩形等关系模型);</div>
		<div> (4): 应当总是先确定 public继承关系模型为 IS－A或者WORKS－LIKE－A</div>
		<div>
				<br /> Item 25 Object-Oriented Programming<br /> 略;</div>
		<div> Item 26-28 Minimizing Compile-Time Dependencies<br /> (1): 决不#include无用的头文件；<br /> (2): 当前向声明某个stream时候用&lt;iosfwd&gt;足够了；<br /> (3): 如果composition足够的话,决不能用继承;<br /> </div>
		<div> Item 29 Compilation Firewalls<br /> (1): 放置所有的非virtual函数 private member 到Pimpl类中去; 客户程序员无论如何也不应当看到这些private成员;<br />      Pimpl类中某些函数可能需要类中某些成员的支持,所有需要一个back pointer指向类本身,back pointer通常命名为self_<br /> <br /> Item 30 The "Fast Pimpl" Idiom<br /> (1):绝不能放置对象到一个buffer里面,例如<br />  char buffer[100];<br />  new (&amp;buffer[0]) T;<br />  a: 不能保证对齐规则；<br />  b: 脆弱<br />  c: 难于维护;<br />  </div>
		<div> <br /> Item 31 - 34 Name Lookup and Interface Principle<br /> (1): 对于一个class X,任何提及并且含有X（例如来自同一头文件或者名称空间)的函数(括成员函数，static函数和自由函数），逻辑上都属于class X的一部分，因为它们是X接口的一部分</div>
		<div>  任何class X的成员函数都一定提及X；<br />  任何class X的成员函数都一定含有X(隐式的this)；</div>
		<div>
				<br />  例如:<br />   class X{...};<br />   ostream&amp; operator&lt;&lt;(ostream&amp;, const X&amp;)//肯定提及X;<br />   如果operator&lt;&lt;含有X ，例如在同一个头文件或者名称空间，那么它逻辑上属于X的一部分，因为他建构了X的一部分接口；<br />   否则反之；</div>
		<div>  <br /> (2): 关于 supplied with;<br />  struct _iobuf{...};<br />  typedef struct _iobuf FILE;<br />  FILE* fopen(const char *filename, const char* mode);<br />  int fclose(FILE* stream);<br />  int fseek(FILE* stream, long offset, int origin);<br />  ......<br />  这些函数都是非成员,但是它们确实是 FILE接口的一部分;(part of the interface of FILE);</div>
		<div>  class File <br />  {<br />  public:<br />   int fseek(long offset, int origin);<br />   ......<br />  };</div>
		<div>  int fseek(FILE* stream, long offset, int origin);<br />  例如上例: int fseek(FILE* stream, long offset, int origin);<br />  提及并且同File都来自于头一个头文件或者名称空间，此函数一样属于File接口的一部分；</div>
		<div> <br /> (3):如果在某个作用域内调用了一个接受另一个作用域内类型参数的函数，那么编译器不止在当前作拥域内查找该函数，同时也会到接受的的  类型所在的作用域去查找该函数，而且不用特别声明；类似<br />  void f()<br />  {<br />   std:string hello = "hello world";<br />   std::cout  &lt;&lt;  hello;   //正确调用std::operator&lt;&lt;;<br />  }<br />  
如果没有Koenig
lookup，则编译器无法查找到operator&lt;&lt;是哪一个我们想要的；（这个函数封装在std::string内,是string接口
的  一部分）；如果希望正确调用的operator&lt;&lt;，我们需要 std::operator&lt;&lt;(std::cout,
hello);<br />  <br />  所以,如果在同一个名称空间内定义了一个类和一个提及这个类的函数, 那么编译器将强制关联这个类和这个自由函数;</div>
		<div> (4): namespace A { class X {};  void f(X x) {} }<br />  namespace B { void f(A::X x) {} void g(A:: xx) { f(xx); } }<br />  这将导致B::g出现二义性而无法编译；原因在于g涉及A::X，所以编译时编译器同样将名称空间A内的函数也考虑进来，此时出现两个参  数为A::X的函数f</div>
		<div>  类的成员函数将被优先考虑,例如<br />  namespace A { class X {};  void f(X x) {} }<br />  class B <br />  { <br />   void f(A::X x) {} <br />   void g(A:: xx) { f(xx); } //此时不会出现二义性问题;<br />  };<br />  如果编译器发现一个类成员函数为f(A::X)，则不再使用Koenig lookup去搜索自由函数；<br />  </div>
		<div> （5）：结论为名称空间不像想象的那样完全隔离函数声明，它只能属于部分独立；<br /> <br /> <br /> (6): 根据Interface Principle,如果一个函数提及了两个类,class X和class Y， 并且此函数同X包含在同一个名称空间或者头文件之中，那么，首先，此函数逻辑上是X的界面接口的一部分；由于此函数依赖Y，因此，X同样依赖于Y；</div>
		<div> (7): 如果A,B是类，f(A,B)是自由函数， 那么<br />  a: 如果A和f在同一头文件或名称空间内，那么f逻辑上是A的一部分，所以，A也依赖于B；<br />  b: 如果A,B和f在同一头文件或名称空间内，那么f逻辑上是A的一部分也是B的一部分，故此，A,B互相依赖；<br /> <br />  如果 ，A,B是类，A::g(B)是一个A的成员函数，那么：<br />  a: 因为A::g(B)，所以，A，依赖于B；<br />  b:如果A,B被声明在一起(同一个头文件或名称空间),那么A,B互相依赖,A::g(B)逻辑上同样属于B的一部分;<br />  实际上,上述情况的实际含义是,类型A,B通常将被放在一起使用,,如果修改了一个,那么将影响另一个;</div>
		<div> (8):关于名称隐藏：<br />  struct B<br />  {<br />   int f(int);<br />   int f(double);<br />   int g(int);<br />  };</div>
		<div>  struct D : public B<br />  {<br />  private:<br />   int g(std::string, bool);<br />  };</div>
		<div>  D d;<br />  int i;<br />  d.f(i)  //调用B::f(int);<br />  d.g(i); //错误，提示应当提供两个参数；<br />  <br />   
实际上，编译器查找匹配函数名称时候，先查找当前范围内的名称匹配函数，例如这里是D，然后列出一个编译器所能找到的函  数名称 相同的函数的列表，但
是并不考虑存取权限和所携带参数是否正确，如果它一个名称匹配的函数都没找到的话，那么将向外一层  继续查找，如果编译器找到一个或者多个候选的函数，
编译器将停止查找，然后提交函数的重载决议；<br />  两种解决方法是<br />  a: d.B::g(i);//编译器自然会考虑B的范围；<br />  b:<br />   struct D : public B<br />   {<br />   using B::g;<br />   private:<br />    int g(std::string, bool);<br />   };</div>
		<div>  <br />  <br />  </div>
		<div> (9): 使用名称空间，如果写一个类在名称空间N中，那么请将所有的协助函数和操作符都都写在N中；<br />Item 35, 36 Memory Management<br /> <br /> (1):</div>
		<div>  [常量数据（const data）区：]<br />  常量数据区存储字符串等在编译期间就能确定的值。类对象不能存在于这个区域中。在程
序的整个生存周期内，区域中的数据都是可  用的。区域内所有的数据都是只读的，任何企图修改本区域数据的行为都会造成无法预料的后果。之所以会如此，是
因为在实际的实现  当中，即使是最底层的内部存储格式也受制于所实现的特定的优化方案。例如，一种编译器完全可以把字符串存放在几个重叠的对象里  面
——只要实现者愿意的话。  </div>
		<div>  [栈（stack）区：]<br />  栈区存储自动变量（automatic
variables）。一般来说，栈区的分配操作要比动态存储区（比如堆（heap）或者自由存储区（free
  store））快得多，这是因为栈区的分配只涉及到一个指针的递增，而动态存储区的分配涉及到较为复杂的管理机制。栈区中，内存一  旦被分配，对象
就立即被构造好了；对象一旦被销毁，分配的内存也立即被收回（译注：这里作者用了“去配（deallocate）”一词，  鄙人一律翻译为“回收”）。
因此，在栈区中，程序员没有办法直接操纵那些已经被分配但还没有被初始化的栈空间（当然，那些通过  使用显式（explicit）析构函数
（destructor）和new运算符而故意这么做的情况不算在内）。</div>
		<div>  [自由存储区（free store）：]<br />    自由存储区（free
store）是C++两个动态内存区域之一，使用new和delete来予以分配和释放（freed）。在自由存储区（free
   store）中，对象的生存周期可以比存放它的内存区的生存周期短；这也就是说，我们可以获得一片内存区而不用马上对其进行初始  化；同时，在对
象被销毁之后，也不用马上收回其占用的内存区。在对象被销毁而其占用的内存区还未被收回的这段时间内，我们可以  通过void*型的指针访问这片区域，
但是其原始对象的非静态成员以及成员函数（即使我们知道了它们的地址）都不能被访问或者操  纵。<br />  <br />  [堆（heap）区：]<br />  
堆（heap）区是另一个动态存储区域，使用malloc、free以及一些相关变量来进行分配和回收。要注意，虽然在特定的编译器里缺省的  全局运 
算符new和delete也许会按照malloc和free的方式来被实现，但是堆（heap）与自由存储区（free
store）是不同的——在某  一个区域内被分配的内存不可能在另一个区域内被安全的回收。堆（heap）中被分配的内存一般用于存放在使用new的构
造过程中和显  式（explicit）的析构过程中涉及到的类对象。堆中对象的生存周期与自由存储区（free store）中的类似。</div>
		<div>  [全局/静态区（Global/Static）：]<br />  
  全局的或静态的变量和对象所占用的内存区域在程序启动（startup）的时候才被分配，而且可能直到程序开始执行的时候才被初始  化。比如，函数
中的静态变量就是在程序第一次执行到定义该变量的代码时才被初始化的。对那些跨越了翻译单元（translation
   unit）的全局变量进行初始化操作的顺序是没有被明确定义的，因而需要特别注意管理全局对象（包括静态类对象）之间的依赖关系。  最后，和前面
讲的一样，全局/静态区（Global/Static）中没有被初始化的对象存储区域可以通过void*来被访问和操纵，但是只要是  在对象真正的生存
周期之外，非静态成员和成员函数是无法被使用或者引用的。</div>
		<div>  </div>
		<div>  [关于“堆（heap）vs.自由存储区（free store）”]：<br />  本条款中我们将堆（heap）和自由存储区（free store）区分开来，是因为在C++标准草案中，关于这两种区域是否有联系的问题一直  很谨慎的没有予以详细说明。比如当内存在通过delete运算符进行回收时，18.4.1.1中说道：<br />   It
is unspecified under what conditions part or all of such reclaimed
storage is allocated by a     subsequent call to operator new or any of
calloc, malloc, or realloc, declared in &lt;cstdlib&gt;.</div>
		<div>   [关于在何种情况下，这种内存区域的部分或全部才会通过后续的对new（或者是在&lt;cstdlib&gt;里声明的calloc，malloc，    realloc中的任何一个）的调用来被分配的问题，在此不作详细规定，不予详述。]</div>
		<div> </div>
		<div>      
同样，在一个特定的实现中，到底new和delete是按照malloc和free来实现的，或者反过来malloc和free是按照new和
delete来实现  的，这也没有定论。简单地说吧，这两种内存区域运作方式不一样，访问方式也不一样——所以嘛，当然应该被当成不一样的两个东西  
来使用了！</div>
		<div> </div>
		<div> Item 37: AUTO_PTR<br />  略</div>
		<div> Item 38 Object Identity</div>
		<div> (1): 千万别写一个依赖于检测自身赋值达到正确操作的operator=(),一个拷贝赋值操作符应当使用create-a-temporary-and-swap<br />  方法来自动维持强异常安全和安全的自身赋值;<br /> <br /> (2): 自身赋值是个可行的优化去避免无用的工作;</div>
		<div> </div>
		<div> Item 39 Automatic Conversions<br /> <br /> (1): 避免使用隐式转换操作符:<br />  a: 隐式转换会影响重载决议;<br />  b: 隐式转换会让错误的代码安静的编译通过;</div>
		<div> (2): C++标准保证「对指向同一个对象的多个指针的比较之结果必须是“相等（equal）” 」，但却并不保证「对指向不同对象的多个指针  的比较之结果必须是“不相等（unequal）”」。</div>
		<div> Item 40,41 Object Lifetimes<br /> <br /> (1): void f()<br />  {<br />   T t(1);<br />   T&amp; rt = t;<br />   //#1  do something;<br />   t.~T();<br />   new (&amp;t) T(2);<br />   //#2  do something;<br />  };</div>
		<div> a: #2是合法的;<br /> b: #2是不安全的;</div>
		<div> 请总是尝试写异常安全级别的代码, 总是尝试正确的组织代码让资源正确的申请和释放当异常抛出时;</div>
		<div> <br /> (2): 避免C++ 语言级别定义不太明确的技巧，应该多用清晰简单的编程技巧；   </div>
		<div> (3): 用同一个成员函数完成两种拷贝操作（拷贝构造和拷贝赋值）的注意是很好的：这意味着我们只需在一个地方编写和维护操作代码。本条  款问题中的惯用法只不过是选择了错误的函数来做这件事。如此而已。</div>
		<div> </div>
		<div>  其实，惯用法应该是反过来实现的：拷贝构造操作应该以拷贝赋值操作来实现，不是反过来实现。例如： </div>
		<div>  T::T( const T&amp; other ) {<br />        /* T:: */ operator=( other );<br />  } <br />      <br />  T&amp; T::operator=( const T&amp; other ) {<br />        // 真正的工作在这里进行<br />        // (大概可以在异常安全的状态下完成，但现在<br />        // 其可以抛出异常，却不会像原来那样产生什么不良影响<br />         return *this;<br />      }<br />  这段代码拥有原惯用法的所有益处，却不存在任何原惯用法中存在的问题。[注5] 为了代码的美观，你或许还要编写一个常见的私有辅  助函数，利用其做真正的工作；但这也是一样的，无甚区别： </div>
		<div>      T::T( const T&amp; other ) {<br />        do_copy( other );<br />      } <br />      <br />  T&amp; T::operator=( const T&amp; other ) {<br />        do_copy( other );<br />        return *this;<br />      } <br />      <br />  T&amp; T::do_copy( const T&amp; other ) {<br />        // 真正的工作在这里进行<br />        // (大概可以在异常安全的状态下完成，但现在<br />        // 其可以抛出异常，却不会像原来那样产生什么不良影响<br />  }</div>
		<div> </div>
		<div> </div>
		<div>
				<br />  如果需要的话，请编写一个私有函数来使拷贝操作和拷贝赋值共享代码；千万不要利用「使用显式的析构函数并且后跟一个
placement
  new」的方法来达到「以拷贝构造操作实现拷贝赋值操作」这样的目的，即使这个所谓的技巧会每隔三个月就在新闻组中出现几次。  （也就是说，决不要
编写如下的代码：） </div>
		<div>         T&amp; T::operator=( const T&amp; other )<br />         {<br />             if( this != &amp;other)<br />             {<br />                  this-&gt;~T();             // 有害！<br />                  new (this) T( other );  // 有害！<br />             }<br />             return *this;<br />         }</div>
		<div> </div>
		<div>
				<br /> Item 42: Variable Initialization -- Or is it?</div>
		<div> (1): 关于 T u; T t = u;<br />  这时，编译器总会是调用 copy-construct而不是调用默认constructor之后调用operator=(),这只是一个从C继承来的语法，   并没有赋值操作</div>
		<div> (2): 用 T t(u);代替 T t = u;</div>
		<div>
				<br /> Item 43 Const-Correctiness;</div>
		<div> (1): 避免在某个函数参数使用 const by value <br /> (2): 如果是非内部类型的return by value,那么优先考虑返回一个const value;<br /> (3): 如果某个类数据成员的改变并不影响到类状态的改变,例如class X { private: char buffer[1024]; ...};<br />  那么当某函数只改变这个类数据成员,而不改变其他成员时,也应当把这个函数为const ,并将这个被改变但无关类状态的成员声明为<br />  mutable;</div>
		<div>
				<br /> Item 44 Casts</div>
		<div> (1): 请优先使用新转型风格cast;</div>
		<div> (2): 避免用const_cast消除const ，请优先使用mutable;</div>
		<div> (3): 避免动态的向下转型;</div>
		<div> Item 45: BOOL<br /> 略</div>
		<div> Item 46 Forwarding Functions;</div>
		<div> (1): 多考虑传递对象的const &amp;；<br /> (2): 避免语言的隐晦角落,多用简单的技巧;<br /> (3): 如果不认为性能上绝对需要，请避免inline或者内部优化；</div>
		<div>
				<br /> Item 47 Control Flow</div>
		<div> (1): 避免使用全局或者静态变量；如果必须如此，那么请注意它们的初始化顺序（因为多个头文件内引入的静态变量的声明顺寻并不是标准定  义的）；</div>
		<div> (2): 将基类的constructor在初始化器列表中的顺序和类声明的顺序是一样的，基类的初始化顺序是依据类定义时的顺序的；</div>
		<div> (3): 将类的数据成员的初始化顺序与初始化器列表中声明的顺序是一样的,同样依据类定义;</div>
		<div> (4): 努力去实现代码的异常级安全;</div>
 (5): 绝不能写依赖函数参数赋值顺序的代码;<img src ="http://www.cppblog.com/swo2006/aggbug/11351.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-17 15:34 <a href="http://www.cppblog.com/swo2006/articles/11351.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>