﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-白纸人生-随笔分类-C++</title><link>http://www.cppblog.com/andxie99/category/1882.html</link><description>上学时，因我年龄最小，个头也最小，上课时，就像大猩猩堆里的猴一般。如今，这猴偶尔也把最近的一些情况写在这里。</description><language>zh-cn</language><lastBuildDate>Sat, 16 Oct 2010 23:57:31 GMT</lastBuildDate><pubDate>Sat, 16 Oct 2010 23:57:31 GMT</pubDate><ttl>60</ttl><item><title>网上看到的一个面试题：利用星号输出画一个任意大小的圆</title><link>http://www.cppblog.com/andxie99/archive/2010/10/16/130177.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Sat, 16 Oct 2010 15:41:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2010/10/16/130177.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/130177.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2010/10/16/130177.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/130177.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/130177.html</trackback:ping><description><![CDATA[<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #008000;">/*</span><span style="color: #008000;">利用星号输出画一个任意大小的圆</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">math.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">stdio.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;"></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;max(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;a,&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;b)<br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">{<br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;a&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;b&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;a&nbsp;:&nbsp;b;<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">}<br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;print_char(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;x1,&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;x2)<br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">{<br></span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i;<br></span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;计算这一行的宽度，终端最多显示80列</span><span style="color: #008000;"><br></span><span style="color: #008080;">14</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;n&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;max(x1,&nbsp;x2)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br></span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;n&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;n&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">80</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">80</span><span style="color: #000000;">&nbsp;:&nbsp;n;<br></span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;n;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br></span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">18</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(i&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;x1&nbsp;</span><span style="color: #000000;">||</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;x2)<br></span><span style="color: #008080;">19</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">*</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br></span><span style="color: #008080;">20</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br></span><span style="color: #008080;">21</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br></span><span style="color: #008080;">22</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">23</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">\n</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br></span><span style="color: #008080;">24</span>&nbsp;<span style="color: #000000;">}<br></span><span style="color: #008080;">25</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">26</span>&nbsp;<span style="color: #000000;"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;print_circle(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;r)<br></span><span style="color: #008080;">27</span>&nbsp;<span style="color: #000000;">{<br></span><span style="color: #008080;">28</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;x1,&nbsp;x2,&nbsp;y;<br></span><span style="color: #008080;">29</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;d&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;r;<br></span><span style="color: #008080;">30</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;offset;<br></span><span style="color: #008080;">31</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">(y&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;y&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;d;&nbsp;y</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br></span><span style="color: #008080;">32</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">33</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/*</span><span style="color: #008000;">终端字符宽高比为2:1</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br></span><span style="color: #008080;">34</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">)(</span><span style="color: #000000;">0.5</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;sqrt((</span><span style="color: #0000ff;">double</span><span style="color: #000000;">)(r</span><span style="color: #000000;">*</span><span style="color: #000000;">r&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;(y</span><span style="color: #000000;">-</span><span style="color: #000000;">r)</span><span style="color: #000000;">*</span><span style="color: #000000;">(y</span><span style="color: #000000;">-</span><span style="color: #000000;">r)))</span><span style="color: #000000;">*</span><span style="color: #000000;">2.0</span><span style="color: #000000;">);<br></span><span style="color: #008080;">35</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;d&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;offset;<br></span><span style="color: #008080;">36</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;d&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;offset;<br></span><span style="color: #008080;">37</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print_char(x1,&nbsp;x2);<br></span><span style="color: #008080;">38</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">39</span>&nbsp;<span style="color: #000000;">}<br></span><span style="color: #008080;">40</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">41</span>&nbsp;<span style="color: #000000;"></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;main(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;argn,&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">argv[])<br></span><span style="color: #008080;">42</span>&nbsp;<span style="color: #000000;">{<br></span><span style="color: #008080;">43</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;r&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">;<br></span><span style="color: #008080;">44</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(argn&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br></span><span style="color: #008080;">45</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;atoi(argv[</span><span style="color: #000000;">1</span><span style="color: #000000;">]);<br></span><span style="color: #008080;">46</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">47</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;print_circle(r);<br></span><span style="color: #008080;">48</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br></span><span style="color: #008080;">49</span>&nbsp;<span style="color: #000000;">}<br></span><span style="color: #008080;">50</span>&nbsp;<span style="color: #000000;"></span></div>
<br><img src ="http://www.cppblog.com/andxie99/aggbug/130177.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2010-10-16 23:41 <a href="http://www.cppblog.com/andxie99/archive/2010/10/16/130177.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>聊聊封装、继承</title><link>http://www.cppblog.com/andxie99/archive/2007/07/21/28494.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Sat, 21 Jul 2007 08:18:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/07/21/28494.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/28494.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/07/21/28494.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/28494.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/28494.html</trackback:ping><description><![CDATA[&nbsp;
<p>&nbsp;</p>
<p align=left><span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>在</span><span>C++</span><span>中封装的概念是把一个对象的外观接口同实际工作方式（实现）分离开来，但是</span><span>C++</span><span>的封装是不完全的，</span><span>编译器必须知道一个对象的所有部分的声明，以便创建和管理它。我们可以想象一种只需声明一个对象的公共接口部分的编程语言，而将私有的实现部分隐藏起来。</span><span>C + +</span><span>在编译期间要尽可能多地做静态类型检查。这意味着尽早捕获错误，也意味着程序具有更高的效率。然而这对私有的实现部分来说带来两个影响：一是即使程序员不能轻易地访问实现部分，但他可以看到它；二是造成一些不必要的重复编译<span>。</span></span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>然而</span><span>C++</span><span>并没有将这个原则应用到二进制层次上，这是因为</span><span>C++</span><span>的类既是描述了一个接口同时也描述了实现的过程</span><span>,</span><span>示例如下：</span></p>
<p><span>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;CMyString<br><img id=Codehighlighter1_16_172_Open_Image onclick="this.style.display='none'; Codehighlighter1_16_172_Open_Text.style.display='none'; Codehighlighter1_16_172_Closed_Image.style.display='inline'; Codehighlighter1_16_172_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_16_172_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_16_172_Closed_Text.style.display='none'; Codehighlighter1_16_172_Open_Image.style.display='inline'; Codehighlighter1_16_172_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_16_172_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_16_172_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;m_cch;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">m_psz;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;CMyString(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">psz);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">CMyString();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;Length()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;Index(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">psz)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p></span>&nbsp;</p>
<p>&nbsp;</p>
<p><span>CMyStirng</span><span>对外过多的暴露了内存布局实现的细节，这些信息过度的依赖于这些成员变量的大小和顺序，从而导致了客户过度依赖于可执行代码之间的二进制耦合关系，这样的接口不利于跨语言跨平台的软件开发和移植。</span></p>
<p>&nbsp;</p>
<p><strong><span>1.1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Handle-Body</span></strong><span>模式</span><strong></strong></p>
<p>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>解决这个问题的技术有一种叫句柄类（ </span><span>handle classes</span><span>）</span><span>。有关实现的任何东西都消失了，只剩一个单一的指针&#8220;</span><strong><span>m_pThis</span></strong><span>&#8221;。该指针指向一个结构，该结构的定义与其所有的成员函数的定义都出现在实现文件中。这样，只要接口部分不改变，头文件就不需变动。而实现部分可以按需要任意更动，完成后只要对实现文件进行重新编译，然后再连接到项目中。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面是</span></span><span>这项技术的简单例子。头文件中只包含公共的接口和一个简单的没有完全指定的类指针。</span></p>
<p align=left>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;CMyStringHandle<br><img id=Codehighlighter1_22_201_Open_Image onclick="this.style.display='none'; Codehighlighter1_22_201_Open_Text.style.display='none'; Codehighlighter1_22_201_Closed_Image.style.display='inline'; Codehighlighter1_22_201_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_22_201_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_22_201_Closed_Text.style.display='none'; Codehighlighter1_22_201_Open_Image.style.display='inline'; Codehighlighter1_22_201_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_22_201_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_22_201_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;CMyString；<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;CMyString&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">m_pThis;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;CMyStringHandle&nbsp;(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">psz);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">&nbsp;CMyStringHandle&nbsp;();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;Length()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;Index(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">psz)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">；<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>CMyStringHandle::&nbsp;CMyStringHandle(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">psz)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>:m_pThis(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;CMyString(psz));<br><img id=Codehighlighter1_286_288_Open_Image onclick="this.style.display='none'; Codehighlighter1_286_288_Open_Text.style.display='none'; Codehighlighter1_286_288_Closed_Image.style.display='inline'; Codehighlighter1_286_288_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_286_288_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_286_288_Closed_Text.style.display='none'; Codehighlighter1_286_288_Open_Image.style.display='inline'; Codehighlighter1_286_288_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_286_288_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_286_288_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>CMyStringHandle::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">&nbsp;CMyStringHandle()<br><img id=Codehighlighter1_328_349_Open_Image onclick="this.style.display='none'; Codehighlighter1_328_349_Open_Text.style.display='none'; Codehighlighter1_328_349_Closed_Image.style.display='inline'; Codehighlighter1_328_349_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_328_349_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_328_349_Closed_Text.style.display='none'; Codehighlighter1_328_349_Open_Image.style.display='inline'; Codehighlighter1_328_349_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_328_349_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_328_349_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;delete&nbsp;m_pThis;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;CMyStringHandle::Length()<br><img id=Codehighlighter1_382_412_Open_Image onclick="this.style.display='none'; Codehighlighter1_382_412_Open_Text.style.display='none'; Codehighlighter1_382_412_Closed_Image.style.display='inline'; Codehighlighter1_382_412_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_382_412_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_382_412_Closed_Text.style.display='none'; Codehighlighter1_382_412_Open_Image.style.display='inline'; Codehighlighter1_382_412_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_382_412_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_382_412_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;m_pThis</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Length();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;CMyStringHandle::Index(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">psz)<br><img id=Codehighlighter1_459_490_Open_Image onclick="this.style.display='none'; Codehighlighter1_459_490_Open_Text.style.display='none'; Codehighlighter1_459_490_Closed_Image.style.display='inline'; Codehighlighter1_459_490_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_459_490_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_459_490_Closed_Text.style.display='none'; Codehighlighter1_459_490_Open_Image.style.display='inline'; Codehighlighter1_459_490_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_459_490_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_459_490_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;m_pThis</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Index(psz);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>这是所有客户程序员都能看到的。<br></span><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class</span></strong><span> <strong><span>CMyString</span></strong></span><strong><span>；</span></strong></p>
<p align=left><span>是一个没有完全指定的类型说明或类声明（一个类的定义包含类的主体）。它告诉编译器，</span><span><span><strong>CMyString</strong></span></span><span>是一个结构的名字，但没有提供有关该结构的任何东西。这对产生一个指向结构的指针来说已经足够了。但我们在提供一个结构的主体部分之前不能创建一个对象。在这种技术里，包含具体实现的结构主体被隐藏在实现文件中。</span></p>
<p align=left>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>在设计模式中，这就叫做</span><span>Handle-Body </span><span>模式，</span><strong><span>Handle-Body</span></strong><span>只含有一个实体指针，服务的数据成员永远被封闭在服务系统中。</span></p>
<p><strong><span>Handle-Body</span></strong><span>的布局结构永远不会随着实现类数据成员的加入或者删除或者修改而导致<strong><span>Handle-Body</span></strong>的修改，即<strong><span>Handle-Body</span></strong>协议不依赖于<span>C++</span>实现类的任何细节。这就有效的对用户的编译器隐藏了这些细节，用户在使用对这项技术时候，<strong><span>Handle-Body</span></strong><span> </span>接口成了它唯一的入口。</span></p>
<p>&nbsp;</p>
<p><span>然而</span><strong><span>Handle-Body</span></strong><span>模式也有自己的弱点：</span></p>
<p><span><span>1、</span></span><span>接口类必须把每一个方法调用显示的传递给实现类，这在一个只有一个构造和一个析构的类来说显然不构成负担，但是如果一个庞大的类库，它有上百上千个方法时候，光是编写这些方法传递就有可能非常冗长，这也增加了出错的可能性。</span></p>
<p><span><span>2、</span></span><span>对于关注于性能的应用每一个方法都得有两层的函数调用，嵌套的开销也不理想</span></p>
<p><span><span>3、</span></span><span>由于句柄的存在，依然存在编译连接器兼容性问题。</span></p>
<p>&nbsp;</p>
<p><strong><span><span>1.1.2<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span>抽象接口</span></strong></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>使用了&#8220;接口与实现的分离&#8221;技术的</span><span> <strong><span>Handle-Body </span></strong></span><span>解决了编译器</span><span>/</span><span>链接器的大部分问题，而</span><span>C++</span><span>面向对象编程中的抽象接口同样是运用了&#8220;接口与实现分离&#8221;的思想，而采用抽象接口对于解决这类问题是一个极其完美的解决方案。</span></p>
<p><span><span>1、</span></span><span>抽象接口的语言描述：</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>class IMyString</span></span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int Length() const = 0;&nbsp;//</span><span>这表示是一个纯虚函数，具有纯虚函数的接口</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int Index(const char *psz) const = 0;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span><span>；</span></p>
<p>&nbsp;</p>
<p><span><span>2、</span></span><span>抽象接口的内存结构：</span></p>
<p><span></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 抽象接口采用虚函数表来调用成员方法。&nbsp;</p>
<p><span><span>3、</span></span><span><span>&nbsp;&nbsp; </span></span><span>抽象接口的实现代码：</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>接口：</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span><span>class IMyString</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int Length() const = 0;&nbsp;//</span><span>这表示是一个纯虚函数，具有纯虚函数的接口</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int Index(const char *psz) const = 0;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span><span>；</span></p>
</span></span>
<p><span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>实现：</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>class CMyString</span><span>：</span><span>public IMyString</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>private:</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;const int m_cch;</span></span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>char *m_psz;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public:</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>CMyString(const char *psz);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual ~CMyString();</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>int Length() const;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>int Index(const char *psz) const;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>从上面采用抽象接口的实例来看，抽象接口解决了</span><span>Handle-Body</span><span>所遗留下来的全部缺陷。</span></p>
<p><span>抽象接口的一个典型应用：</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>抽象工厂（</span><span>AbstractFactroy</span><span>）</span></p>
<p><strong>&nbsp;</strong></p>
<p><strong><span><span>1.2<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span>多继承与菱形缺陷、<span>this</span>跳转等</span></strong></p>
<p><span>多重继承是<span>C++</span>语言独有的继承方式，其它几乎所有语言都秉承了单一继承的思想。这是因为多重继承致命的缺陷导致的：</span></p>
<p><strong><span><span>1.2.1<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span>菱形缺陷</span></strong></p>
<p><span>当继承基类时，在派生类中就获得了基类所有的数据成员副本。假如类<span>B </span>从<span>A1</span>和<span>A2</span>两个类多重继承而来，这样<span>B</span>类就包含<span>A1</span>、<span>A2</span>类的数据成员副本。</span></p>
<p><span></span><span>考虑如果<span>A1</span>、<span>A2</span>都从某基类派生，该基类称为<span>Base</span>，现在继承关系将出现</span><span>菱形继承关系。<br></span></p>
<p><span>
<div align=center src_cetemp="/images/cppblog_com/andxie99/diamondBug.JPG"><img src="http://www.cppblog.com/images/cppblog_com/andxie99/diamondBug.JPG" border=0></div>
<br>我们<span>C++</span>语言来描述这种继承关系：</span>
<p>&#160;</p>
<p><span>class Base{</span><span>&#8230;</span><span> </span><span>&#8230;</span><span> }</span><span>；</span></p>
<p><span>class A1 :public Base {</span><span>&#8230;</span><span> </span><span>&#8230;</span><span> }</span><span>；</span></p>
<p><span>class A2 :public Base {</span><span>&#8230;</span><span> </span><span>&#8230;</span><span> }</span><span>；</span></p>
<p><span>class B :public A1,public A2 {</span><span>&#8230;</span><span> </span><span>&#8230;</span><span> }</span><span>；</span></p>
<p>&nbsp;</p>
<p><span>那么<span>A1</span>、<span>A2</span>都具有<span>Base</span>的副本。这样<span>B</span>就包含了<span>Base</span>的两个副本，副本发生了重叠，不但增加了存储空间，同时也引入了二义性。这就是菱形缺陷，菱形缺陷的两个缺陷：</span></p>
<p><span><span>1、</span></span><span>子对象重叠</span></p>
<p><span><span>2、</span></span><span>向上映射的二义性。</span></p>
<p><span>菱形缺陷的其中一种解决办法是使用虚拟继承。</span></p>
<p>&nbsp;</p>
<p><span>在<span>C++</span>世界里最广泛的使用虚拟继承解决菱形缺陷的应用便是标准<span>C++</span>的输入<span>/</span>输出<span>iostream</span>；</span></p>
<p>
<div align=center src_cetemp="/images/cppblog_com/andxie99/diamondBug01.JPG"><img src="http://www.cppblog.com/images/cppblog_com/andxie99/diamondBug01.JPG" border=0></div>
<strong><span></span></strong>
<p>&#160;</p>
<p><span></span>&nbsp;</p>
<p><strong>&nbsp;</strong></p>
<p><strong><span><span>1.2.2<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span>多重接口与方法名冲突问题（</span><span>Siamese twins</span></strong><strong><span>）</span></strong></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>对继承而来的虚函数改写很容易，但是如果是在改写一个&#8220;在两个基类都有相同原型&#8221;的虚函数情况就不那么容易了。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span>提出问题：</span></strong></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>假设汽车最大速度的接口为</span><span>ICar</span><span>，潜艇最大速度的接口为</span><span> IBoat</span><span>，有一个两栖类的交通工具它可以奔跑在马路上，也可以航行在大海中，那么它就同时拥有</span><span>ICar</span><span>、</span><span>IBoat</span><span>两种交通工具的最大速度特性，我们定义它的接口为</span><span>ICarBoat</span><span>；</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class&nbsp;ICar</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int GetMaxSpeed</span><span>（）</span><span>= 0</span><span>；</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span><span>；</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class&nbsp;IBoat</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int GetMaxSpeed</span><span>（）</span><span>= 0</span><span>；</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span><span>；</span></p>
<p><span><span>&nbsp;&nbsp; </span></span><span>我们先对</span><span>ICarBoat</span><span>的接口做一个尝试：</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class CCarBoat</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int GetMaxSpeed</span><span>（）；</span><span>//</span><span>既完成</span><span>ICar</span><span>的</span><span>GetMaxSpeed</span><span>（）接口方法又</span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//</span><span>完成</span><span>IBoat</span><span>的接口方法？显然不能够</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>};</span></p>
<p><strong><span>解决问题：</span></strong></p>
<p><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><span>显然上面这个尝试根本就无法成功，只用一个实现方法，怎么能够求出这个</span><span>ICarBoat</span><span>交通工具奔跑在马路上的最高时速，同时也能够求出航行在大海上的最大航行速度呢。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>上面这一问题矛盾就在一一个方法，却需要两个答案。看来</span><span>ICarBoat</span><span>要返回两个答案就必须有两个方法了，我们假设一个方法是求在陆地上奔跑的速度，名称为</span><span>GetCarMaxSpeed</span><span>（）；另一个方法是求在大海上航行的最大速度，名称为</span><span>GetBoatMaxSpeed</span><span>（）；那这两个方法又怎么和</span><span>GetMaxSpeed</span><span>（）接口方法联系起来呢；</span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>幸运的是，我们找到了解决办法，而且解决办法有很多种，下面介绍一下继承法。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class IXCar :public ICar</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span>&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int GetMaxSpeed</span><span>（）</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>GetCarMaxSpeed();</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int GetCarMaxSpeed</span><span>（）</span><span> = 0;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span><span>；</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class IXBoat:public IBoat</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int GetMaxSpeed</span><span>（）</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>GetBoatMaxSpeed();</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int GetBoatMaxSpeed</span><span>（）</span><span> = 0;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span><span>；</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>classCCarBoat: public IXCar , public IXBoat</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int GetCarMaxSpeed</span><span>（）</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#8230; &#8230;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>virtual int GetBoatMaxSpeed</span><span>（）</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#8230; &#8230;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>};</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<div align=center src_cetemp="/images/cppblog_com/andxie99/MultiInherit.JPG"><img src="http://www.cppblog.com/images/cppblog_com/andxie99/MultiInherit.JPG" border=0></div>
</span></span>
<p>&#160;</p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<p><strong><span><span>1.2.3<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span>this</span></strong><strong><span>跳转</span></strong></p>
<p><span>this</span><span>跳转是指的&#8220;对象同一性&#8221;问题。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>在单一继承的世界内，无论继承关系怎么复杂，针对于同一对象，无论它的子类或者父类的<span>this</span>指针永远相等。即如果</span><span><span> </span></span><span>B</span><span>从</span><span>A</span><span>继承，</span><span>那么 对于一个已经实例化<span>B</span>类的对象 <span>bObject</span>，永远有（<span>B*</span>）<span>&amp;bObject ==(A*)&amp;bObject </span>成立。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>但是在多继承的世界内，上面的等式就不能恒成立，对象的同一性受到了挑战。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>特别的是，在多继承世界内如果菱形关系存在情况下，如果对于已经实例化<span>B</span>类的对象<span>bObject; </span>（<span>Base*</span>）（<span>A1*</span>）<span>&amp;bObject != </span>（<span>Base*</span>）（<span>A2*</span>）<span>&amp;bObject </span>成立，当这种事情发生的时候我们就只能特殊处理了。这种情况在<span>COM</span>应用中处处都会发生。</span></p>
<p>&nbsp;</p>
<p><strong><span><span>1.3<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span>C++</span></strong><strong><span>多态的两种多态形式和区别</span></strong></p>
<p><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><span>C++</span><span>有两种多态多态形式：</span></p>
<p><span><span>1、</span></span><span>编译时刻多态，编译时刻多态依靠函数重载或者模板实现</span></p>
<p><span><span>2、</span></span><span>运行时刻多态。运行时刻多态依靠需函数虚接口实现</span></p>
<img src ="http://www.cppblog.com/andxie99/aggbug/28494.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-07-21 16:18 <a href="http://www.cppblog.com/andxie99/archive/2007/07/21/28494.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++的底层机制</title><link>http://www.cppblog.com/andxie99/archive/2007/06/24/26855.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Sun, 24 Jun 2007 12:43:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/06/24/26855.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/26855.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/06/24/26855.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/26855.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/26855.html</trackback:ping><description><![CDATA[<p>　　c++为我们所提供的各种存取控制仅仅是在编译阶段给我们的限制，也就是说是编译器确保了你在完成任务之前的正确行为，如果你的行为不正确，那么你休想构造出任何可执行程序来。</p>
<p>　　但如果真正到了产生可执行代码阶段，无论是c，c++,还是pascal，大家都一样，你认为c和c++编译器产生的机器代码会有所不同吗，你认为c++产生的机器代码会有访问限制吗？那么你错了。什么const，private，统统没有(const变量或许会放入只读数据段)，它不会再给你任何的限制，你可以利用一切内存修改工具或者是自己写一个程序对某一进程空间的某一变量进行修改，不管它在你的印象中是 private，还是public，对于此时的你来说都一样，想怎样便怎样。</p>
<p>　　另外，你也不要为c++所提供的什么晚期捆绑等机制大呼神奇，它也仅仅是在所产生的代码中多加了几条而已，它远没有你想象的那么智能，所有的工作都是编译器帮你完成，真正到了执行的时候，计算机会完全按照编译器产生的代码一丝不苟的执行。</p>
<p>　　(以下的反汇编代码均来自visial c++ 7.0)</p>
<p>　　一.让我们从变量开始-----并非你想象的那么简单</p>
<p>　　变量是什么，变量就是一个在程序执行过程中可以改变的量。换一个角度，变量是一块内存区域的名字，它就代表这块内存区域，当我们对变量进行修改的时候，会引起内存区域中内容的改变。但是你若是学习过汇编或是计算机组成原理，那么你就会清楚对于一块内存区域来说，根本就不存在什么名字，它所仅有的标志就是他的地址，因此我们若想修改一块内存区域的内容，只有知道他的地址方能实现。看来所谓的变量一说只不过是编译器给我们进行的一种抽象，让我们不必去了解更多的细节，降低我们的思维跨度而已。例如下面这条语句：</p>
<p>　　int a=10;</p>
<p>　　按照我们的思维习惯来讲，就是&#8220;存在一个变量a，它的值是10&#8221;，一切都显得那么的自然。我们不必去在乎什么所谓的地址以及其他的一些细节。然而在这条语句的底层实现中，a已经不能算是一个变量了，它仅仅是一个标记，代表一个地址的标记：</p>
<p>　　mov dword ptr[a],0Ah;</p>
<p>　　怎么样，这条语句不像上面那条易于接受吧，因为它需要了解更多的细节，你几乎不能得到编译器的任何帮助，一切思维上的跨越必须由你自己完成。这条语句应该解释为&#8220;把10写入以a为地址的内存区域&#8221;。你说什么？a有些像指针？对，的确像，但还不是，只不过他们的过程似乎是类似的。这里所说的跨越实际上就是从一个现实问题到具体地址以及内存区域的跨越。</p>
<p>　　二.引用：你可以拥有引用，但编译器仅拥有指针(地址)</p>
<p>　　看过了第一条，你一定对编译器的工作有了一定的了解，实际上编译器就是程序员与底层之间的一个转换层，它把一个高级语言代码转换为低级语言代码，一个编译器完成的转换跨度越大，那么它也就会越复杂，因为程序员的工作都由他代为完成了。C++编译器必然比汇编编译器复杂就是这个道理。如果我问你引用和指针是一样的吗？你或许会说当然不一样了，指针容易产生不安全的因素，引用却不会，真的不会吗？我们来看下面这段代码：</p>
<p>　　int *e=new int(10);</p>
<p>　　int &amp;f=*e;</p>
<p>　　delete e;</p>
<p>　　f=30;</p>
<p>　　你认为上面这段代码怎么样，我感觉就不很安全，它和指针有相同的隐患。因为它所引用的内存区域就不合法。</p>
<p>　　我个人认为，所谓的引用其实就是一种指针，只不过二者的接口并不相同，引用的接口有一定的限制。指针可以一对多，而引用却只能一对一，即&amp;refer不能被改变，但却并不能说一对一就是安全的，只不过危险的系数降低罢了。引用比指针更容易控制。</p>
<p>　　Ok, 下面来说说指针，曾经有过汇编经验的人一定会说，恩，指针的某些地方有些像汇编，尤其是那个&#8220;*&#8221;，怎么就那么像汇编中的&#8220;[]&#8221;啊。的确，它也涵盖了一个寻址的过程。看来指针的确是个比较低级的东西。然而引用却并不那么直接，虽然程序员用起来方便安全了许多。但是你要清楚，只有你可以拥有引用，编译器可没有这个工具，计算机并不认识这个东西。因此，它的底层机制实际上是和指针一样的。不要相信只有一块内存拷贝，不要认为引用可以为你节省一个指针的空间，因为这一切不会发生，编译器还是会把引用解释为指针。不管你相不相信，请看下面这段代码：</p>
<p>　　int&amp; b=a;</p>
<p>　　lea eax,[a];</p>
<p>　　mov dword ptr[b],eax;把a的地址赋给地址为b的一块内存</p>
<p>　　b=50;</p>
<p>　　mov eax,dword ptr[b];</p>
<p>　　mov dword ptr[eax],32h;</p>
<p>　　int *d=&amp;a;</p>
<p>　　lea eax,[a];</p>
<p>　　mov dword ptr[d],eax</p>
<p>　　*d=60;</p>
<p>　　mov eax,dword ptr[d]</p>
<p>　　mov dword ptr[eax],3ch;</p>
<p>　　以上的代码均来自具体的编译器，怎么样，相信了吧，好，让我再来做一个或许不怎么恰当的比拟，你一定编过有关线性表和栈的程序吧，线性表是一个非常灵活的数据结构，在他上面有许多的操作，然而栈呢，它是一个限制性操作的线性表，它的底层操作实际上是由线性表操作实现的。就好比stack与vector的关系，因此指针和引用的关系就好比线性表和栈的关系，引用也就是受限的指针，它对外的接口和指针虽然并不一样，但底层是相同的。</p>
<p>　　下面再来看看引用的一个重要用途，作为函数的参数传递的时候是怎样的情形：</p>
<p>　　void swapr(int &amp;a, int &amp;b)；</p>
<p>　　void swapr(int* a, int *b)；</p>
<p>　　int a=10;</p>
<p>　　int b=20;</p>
<p>　　swapr(a, b);</p>
<p>　　lea eax,[a];</p>
<p>　　push eax; //把a的地址压入堆栈</p>
<p>　　lea ecx,[b];</p>
<p>　　push ecx;</p>
<p>　　call swapr;</p>
<p>　　swapr(&amp;a, &amp;b);</p>
<p>　　lea eax,[a];</p>
<p>　　push eax;</p>
<p>　　lea ecx,[b];</p>
<p>　　push ecx;</p>
<p>　　call swapr;</p>
<p>　　怎么样，用引用和指针传递参数无论是在效率上还是在空间上都是完全一样的，如果妄想不传入地址就修改实参的值，简直就是天方夜谭，这就说明引用的本质就是指针。毕竟它们的行为都太相似了，如果不是这样，你还有什么方法去实现引用吗？记住，引用只不过是编译器为你提供的一个有用且安全的工具，对于机器代码可无法表示它，它把指针一对多的缺点去除，禁止了你的不安全的操作。但回到问题的本源，他们没有任何区别。 </p>
<img src ="http://www.cppblog.com/andxie99/aggbug/26855.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-06-24 20:43 <a href="http://www.cppblog.com/andxie99/archive/2007/06/24/26855.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>This case pointers cannot be used </title><link>http://www.cppblog.com/andxie99/archive/2007/06/16/26452.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Sat, 16 Jun 2007 12:45:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/06/16/26452.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/26452.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/06/16/26452.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/26452.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/26452.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; References allow the use of expressions involving the usual arithmetic operators for large objects without excessive copying. Pointers cannot be used because it is not possible to redefine the meaning of an operator applied to a pointer.</p>
<img src ="http://www.cppblog.com/andxie99/aggbug/26452.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-06-16 20:45 <a href="http://www.cppblog.com/andxie99/archive/2007/06/16/26452.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>被误解的C++</title><link>http://www.cppblog.com/andxie99/archive/2007/06/15/26396.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Fri, 15 Jun 2007 12:41:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/06/15/26396.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/26396.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/06/15/26396.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/26396.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/26396.html</trackback:ping><description><![CDATA[<p><br>&nbsp;&nbsp;&nbsp; 从CSDN上读到一篇文章，深有同感，原文如下：<br>&nbsp;&nbsp;&nbsp; 传统上认为，C++相对于目前一些新潮的语言，如Java、C#，优势在于程序的运行性能。这种观念并不完全。如果一个人深信这一点，那么说明他并没有充分了解和理解C++和那个某某语言。同时，持有这种观念的人，通常也是受到了某种误导（罪魁祸首当然就是那些财大气粗的公司）。对于这些公司而言，他们隐藏了C++同某某语言间的核心差别，而把现在多数程序员不太关心的差别，也就是性能，加以强化。因为随着cpu性能的快速提升，性能问题已不为人们所关心。这叫&#8220;李代桃僵&#8221;。很多涉世不深的程序员，也就相信了他们。于是，大公司们的阴谋也就得逞了。<br>&nbsp;&nbsp;&nbsp; 这个文章系列里，我将竭尽所能，利用一些现实的案例，来戳破这种谎言，还世道一个清白。但愿我的努力不会白费。</p>
<p><br>软件工程</p>
<p>&nbsp;&nbsp;&nbsp; 一般认为，使用Java或C#的开发成本比C++低。但是，如果你能够充分分析C++和这些语言的差别，会发现这句话的成立是有条件的。这个条件就是：软件规模和复杂度都比较小。如果不超过3万行有效代码（不包括生成器产生的代码），这句话基本上还能成立。否则，随着代码量和复杂度的增加，C++的优势将会越来越明显。<br>&nbsp;&nbsp;&nbsp; 造成这种差别的就是C++的软件工程性。在Java和C#大谈软件工程的时候，C++实际上已经悄悄地将软件工程性提升到一个前所未有的高度。这一点被多数人忽视，并且被大公司竭力掩盖。<br>&nbsp;&nbsp;&nbsp; 语言在软件工程上的好坏，依赖于语言的抽象能力。从面向过程到面向对象，语言的抽象能力有了一个质的飞跃。但在实践中，人们发现面向对象无法解决所有软件工程中的问题。于是，精英们逐步引入、并拓展泛型编程，解决更高层次的软件工程问题。（实际上，面向对象和泛型编程的起源都可以追溯到1967年，但由于泛型编程更抽象，所以应用远远落后于面向对象）。<br>&nbsp;&nbsp;&nbsp; 一个偶然的机会，我突发奇想，试图将货币强类型化，使得货币类型可以采用普通的算术表达式计算，而无需关心汇率换算的问题。具体的内容我已经写成文章，放在blog里：<a href="http://blog.csdn.net/longshanks/archive/2007/05/30/1631391.aspx">http://blog.csdn.net/longshanks/archive/2007/05/30/1631391.aspx</a>。（CSDN的论坛似乎对大文章有些消化不良）。下面我只是简单地描述一下问题，重点还在探讨语言能力间的差异。<br>&nbsp;&nbsp;&nbsp; 当时我面临的问题是：假设有四种货币：RMB、USD、UKP、JPD。我希望能够这样计算他们：<br>RMB rmb_(1000);<br>USD usd_;<br>UKP ukp_;<br>JPD jpd_(2000);</p>
<p>usd_=rmb_;//赋值操作，隐含了汇率转换。usd_实际值应该是1000/7.68=130.21<br>rmb_=rmb_*2.5;//单价乘上数量。<br>ukp_=usd_*3.7;//单价乘上数量，赋值给英镑。隐含汇率转换。<br>double n=jpd_/(usd_-ukp_);//利用差价计算数量。三种货币参与，隐含汇率转换。<br>而传统上，我们通常用一个double或者currency类型表示所有货币。于是，当不同币种参与运算时，必须进行显式的汇率转换：<br>double rmb_(100), usd_(0), ukp_(0), jpn_(2000);</p>
<p>usd_=rmb_*usd_rmb_rate;<br>ukp_=(usd_*usd_ukp_rate)*3.7;<br>double n=jpd_/((usd_*usd_jpd_rate)-(ukp_*ukp_jpd_rate))<br>很显然，强类型化后，代码简洁的多。并且可以利用重载或特化，直接给出与货币相关的辅助信息，如货币符号等（这点我没有做，但加上也不复杂）。<br>在C++中，我利用模板、操作符重载，以及操作符函数模板等技术，很快开发出这个货币体系：<br>template&lt;int CurrType&gt;<br>class Currency<br>{<br>public:<br>&nbsp;&nbsp; Currency&lt;CurrType&gt;&amp; operator=(count Currency&lt;ct2&gt;&amp; v) {<br>&#8230;<br>&nbsp;&nbsp; }<br>public:<br>&nbsp;&nbsp; double _val;<br>&#8230;<br>};<br>template&lt;int ty, int tp&gt;<br>inline bool operator==(currency&lt;ty&gt;&amp; c1, const currency&lt;tp&gt;&amp; c2) {<br>&#8230;<br>}<br>&nbsp;<br>template&lt;int ty, int tp&gt;<br>inline currency&lt;ty&gt;&amp; operator+=(currency&lt;ty&gt;&amp; c1, const currency&lt;tp&gt;&amp; c2) {<br>&#8230;<br>}<br>template&lt;int ty, int tp&gt;<br>inline currency&lt;ty&gt; operator+(currency&lt;ty&gt;&amp; c1, const currency&lt;tp&gt;&amp; c2) {<br>&#8230;<br>}<br>&#8230;<br>总共不超过200行代码。（当然，一个工业强度的货币体系，需要更多的辅助类、函数等等。但基本上不会超过500行代码）。如果我需要一种货币，就先为其指定一个int类型的常量值，然后typedef一下即可：<br>const int CT_RMB=0;//也可以用enum<br>typedef Currency&lt;CT_RMB&gt;RMB;<br>const int CT_USD=1;<br>typedef Currency&lt;CT_USD&gt;USD;<br>const int CT_UKP=2;<br>typedef Currency&lt;CT_USD&gt;USD;<br>const int CT_JPD=3;<br>typedef Currency&lt;CT_USD&gt;USD;<br>&#8230;<br>每新增一种货币，只需定义一个值，然后typedef即可。而对于核心的Currency&lt;&gt;和操作符重载，无需做丁点改动。<br>之后，我试图将这个货币体系的代码移植到C#中去。根据试验的结果，我也写了一篇文章（也放在blog里：<a href="http://blog.csdn.net/longshanks/archive/2007/05/30/1631476.aspx">http://blog.csdn.net/longshanks/archive/2007/05/30/1631476.aspx</a>）。我和一个同事（他是使用C#开发的，对其更熟悉），用了大半个上午，终于完成了这项工作。<br>令人丧气的事，上来就碰了个钉子：C#不支持=的重载。于是只能用asign&lt;&gt;()泛型函数代替。之后，由于C#的泛型不支持非类型泛型参数，即上面C++代码中的int CurrType模板参数的泛型对等物，以及C#不支持泛型操作符重载，整个货币系统从泛型编程模式退化成了面向对象模式。当然，在我们坚持不懈的努力下，最后终于实现了和C++中一样的代码效果（除了那个赋值操作）：<br>assign(rmb_, ukp_);<br>assign(usd_, rmb_*3.7);<br>&#8230;<br>我知道，有些人会说，既然OOP可以做到，何必用GP呢？GP太复杂了。这里，我已经为这些人准备了一组统计数据：在C#代码中，我实现了3个货币，结果定义了4个类（一个基类，三个货币类）；重载30个算术操作符（和C++一样，实现10个操作符，每个类都得把10个操作符重载一遍）；6个类型转换操作符（从两种货币类到第三货币类的转换操作符）。<br>这还不是最糟的。当我增加一个货币，货币数变成4个后，数据变成了：5个类；40个算术操作符重载；12个类型转换操作符重载。<br>当货币数增加到10个后：11个类；100个算术操作符重载；90个类型转换操作符重载。<br>反观C++的实现，3个货币时：1个类模板；1个赋值操作符重载模板；10个算术操作符重载模板；外加3个const int定义，3个typedef。<br>10个货币时：1个类模板；1个赋值操作符重载模板；10个算术操作符重载模板；const int定义和typedef分别增加到10个。<br>也就是说C++版本的代码随着货币的增加，仅线性增加。而且代码行增加的系数仅是2。请注意，是代码行！不是类、函数，也不是操作符的数量。而C#版本的代码量则会以几何级数增加。几何级数！！！<br>这些数字的含义，我就不用多说了吧。无论是代码的数量、可维护性、可扩展性C++都远远好于C#版本。更不用说可用性了（那个assign函数用起来有多难看）。<br>&nbsp;&nbsp;&nbsp; 我知道，有些人还会说：货币太特殊了，在实践中这种情况毕竟少见。没错，货币是比较特殊，但是并没有特殊到独此一家的程度。我曾经做了一个读取脚本中的图形信息，并绘图输出的简单案例，以展示OOP的一些基本概念，用于培训。但如果将其细化，可以开发出一个很不错的脚本绘图引擎。其中，我使用了组合递归、多态和动态链接，以及类工厂等技术。就是那个类工厂，由于我使用了模板，使得类工厂部分的代码减少了2/3，而且没有重复代码，更易维护。关于抽象类工厂的GP优化，Alexandrescu在其《Modren C++ design》中，有更多的案例。同样的技术，还可以推广到业务模型的类系统中，优化类工厂的代码。<br>如果还不满意，那么就去看看boost。boost的很多库实现了几乎不可想象的功能，比如lambda表达式、BGL的命名参数等等。它为我们很多优化软件代码新思路，很多技术和方法可以促进我们大幅优化代码，降低开发成本。<br>&nbsp;&nbsp;&nbsp; 最后，如果你认为C#的最大的优势在于.net平台，那我可以告诉你，这个世界上还有一种东西叫C++/CLI，完全可以满足.net的开发，而且更好，足以擦干净.net那肮脏的屁股。不过，这将会是另外一个故事了&#8230;<br></p>
<img src ="http://www.cppblog.com/andxie99/aggbug/26396.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-06-15 20:41 <a href="http://www.cppblog.com/andxie99/archive/2007/06/15/26396.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个简单的不依靠MFC的面向对象的Windows程序</title><link>http://www.cppblog.com/andxie99/archive/2007/06/02/25315.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Sat, 02 Jun 2007 04:36:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/06/02/25315.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/25315.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/06/02/25315.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/25315.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/25315.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;&nbsp; 闲时顺手翻了翻《Windows Graphics Programming》，发现里面的示例代码很不错，对设计应用程序框架和理解现有的应用程序框架很有帮助（尤其是MFC）。先来看一个很简单的用面向对象的思想包装API函数的KWindow类。示例代码贴出来，申明一下，代码不是我写的，但有可能做一些改动，加了很多罗嗦的注释，只是想节约以后阅读的时间。&nbsp;&n...&nbsp;&nbsp;<a href='http://www.cppblog.com/andxie99/archive/2007/06/02/25315.html'>阅读全文</a><img src ="http://www.cppblog.com/andxie99/aggbug/25315.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-06-02 12:36 <a href="http://www.cppblog.com/andxie99/archive/2007/06/02/25315.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>什么是高级C++？</title><link>http://www.cppblog.com/andxie99/archive/2007/04/22/22600.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Sun, 22 Apr 2007 11:50:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/04/22/22600.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/22600.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/04/22/22600.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/22600.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/22600.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 整理资料时，发现了《什么是高级C++》这个ppt。这是一个C++发展方向的介绍，个人觉得很不错，把内容贴了出来，同是也可以<a href="http://www.cppblog.com/Files/andxie99/《什么是高级C++》.rar">点击下载</a>。<br><br></p>
<p align=center><strong>什么是高级C++？</strong></p>
<p align=center>——软件工业化时代的C++价值观<br>孟岩<br>《程序员》杂志社</p>
<p><br><strong>开门见山</strong></p>
<p>主要论点：<br>&nbsp;&nbsp;&nbsp; 1. C++本质上是一种重&#8220;创新&#8221;而轻&#8220;生产&#8221;的语言，到目前为止仍然是主流语言中最适合技术创新的一个；<br>&nbsp;&nbsp;&nbsp; 2. 1995年之前，整个软件产业处于&#8220;创新为王&#8221;的阶段，C++是最适合这个阶段的语言，这是C++红极一时的大背景和根本原因。<br>&nbsp;&nbsp;&nbsp; 3. 1995年发生了一系列影响深远的事件，软件产业整体上转向工业化，为了支持工业化，创新的重点由技术创新转向体系创新。然而C++没有能够迅速适应这一变化。<br>&nbsp;&nbsp;&nbsp; 4. 今天，C++应当准确定位，弥补不足，有针对性地发展，它将仍然是最重要的几种工业级语言之一。</p>
<p><br><strong>从一本书说起</strong><br>James Coplien，Advanced C++ Programming Styles and Idioms, Addison Wesley, 1991<br>—— 市面上唯一一本名副其实的&#8220;高级&#8221;C++书（Scott Meyers）<br>&nbsp;●面向对象特性的运用和把握<br>&nbsp;●面向对象的程序风格<br>&nbsp;●动态特征的运用和超越<br>&nbsp;●符号语言模拟<br>&nbsp;●设计模式</p>
<p>&nbsp;&nbsp;&nbsp; 这本书代表了当时专家们对于&#8220;高级C++&#8221;的理解，换句话说代表了当时C++社群的一个审美价值取向。我们看到了什么？技术、技巧、风格、模式，但没有与工程相关的东西。更有意思的事情是，这本书的中文版12年后被剽窃出版，此时书中对于C++面向对象能力发挥到了我当时没有想到的程度。这说明即使在template被广泛应用之前，C++语言的技巧性就达到了如此的高度。然而耐人寻味的是，书中最高深的技巧从来就没有在C++实践中流行过。</p>
<p><strong>另一本书...</strong><br>Scott Meyers, Effective C++ ，1991年第1版，1998年第二版，2005年第三版。<br>&nbsp;●来自教学经验<br>&nbsp;●最初想开发一个代码扫描工具<br>&nbsp;●包含实际工程建议<br>&nbsp;●历史上最重要的C++著作之一</p>
<p>&nbsp;&nbsp;&nbsp; 这本书出版的同时，还有一本在C++历史上影响更大的书问世——Scott Meyers的Effective C++。这本书并没有过多地探索语言技巧，而是探讨实践中应当遵循的规则，或者换句话说，探讨怎样在应用这种语言的同时保持软件的质量，提高开发效率。这本书的内容被整个C++社群熟知并吸收，至今仍在翻新，影响着更多的人。</p>
<p><strong>还是在1991年...</strong><br>&nbsp;●&#8220;按照1991年3月C++程序员增长的速度计算，到1996年5月，全世界每一个人都将成为C++程序员。此后我们将不得不教外星人学习C++。&#8221;<br>&nbsp;●问题：当时人们为什么如此疯狂地学习一种新语言？<br>&nbsp;&nbsp;&nbsp; 答案很有趣：大部分人是盲从。但他们所追随的人并非等闲之辈，几乎所有在AT&amp;T Bell Labs、Sun、Borland、IBM、Microsoft的C语言大师都转向C++（Brain Kernighan，Jon Bentley，Peter van der Linden）。而这些人转向C++，不是因为他们知道Effective C++，而是因为他们知道Advanced C++。什么意思呢？就是说人们转向C++，是因为C++充满了令人兴奋的新技巧和未知的创新空间。<br></p>
<p><br><strong>1991年...</strong><br>&nbsp;●5000行C代码可以写一个完整的应用程序，获得数万$的回报；<br>&nbsp;●一个TSR式的Help程序可以以shareware的方式通过磁盘发行，开发者银行户头里会收到大量汇款；<br>&nbsp;●John Carmark和Michael Abrash正在各自擅长的方向上不断创新。Doom发行后，id获得收入一度超过微软销售额。</p>
<p><strong>C++历史选择中&#8220;创新&#8221;压倒&#8220;生产&#8221;</strong><br>&#8220;相信程序员&#8221;；<br>Be an enable language;<br>Zero overhead；<br>STL投票的通过；<br>偏特化的引入<br>多继承<br>Generic/Generated/Meta<br>IOStream库的设计<br>Loki/Boost<br><br><span style="COLOR: red">counted_ptr被否决<br>可选GC方案被否决<br>加入类似delegate的对象方法指针提议未引起关注；<br>virtual关键字<br>exception机制<br>缺乏Thread, Network, Regex, DB...等标准库<br>没有ABI规范<br>孱弱的RTTI</span></p>
<p>&nbsp;&nbsp;&nbsp; 并不是事后诸葛亮式的谴责，这就是C++的历史选择，无所谓对错。</p>
<p>&nbsp;&nbsp;&nbsp; C++重创新轻生产，重技巧轻规范，语言上的创新试验直到1996年ANSI C++标准草案落地才结束。直到2001年Modern C++ Design出版，人们还不断地发现新的语言运用技巧。我们每个人都经历过这个阶段，在实践中发现一个问题，想方设法用尽各种语言技巧来克服它，成则欣喜，败不气馁。我们都曾经相信，C++中一切问题都可以优雅地解决，只有想不到，没有做不到。问题是，从Advanced C++到Modern C++ Design，许许多多令人第一眼看上去无比惊喜的技术，最后在实践中被大范围推广运用的少之又少。C++大师们说这是教育问题，真的是这样吗？</p>
<p><strong>C++社群的价值观</strong><br>&nbsp;●用优雅的技巧解决复杂问题<br>&nbsp;●自己动手，丰衣足食<br>&nbsp;●决不让运行时效率蒙受半点损失<br>&nbsp;●妙者为王<br>&nbsp;&nbsp;&nbsp; &#8220;管理一群C++程序员就像放牧一群骄傲的猫。&#8221;——B. Moo<br>&nbsp;&nbsp;&nbsp; &#8220;C++程序员是高速公路上穿着短皮茄克，带着墨镜，抽着雪茄，挥舞着铁链的英勇无畏的摩托骑士。&#8221; ——VC产品经理</p>
<p><strong>1995年：转折点<br></strong>&nbsp;●Windows 95问世：GUI时代、保护模式操作系统时代、多线程时代的到来，是推动软硬件规模迅速膨胀；<br>&nbsp;●Netscape Navigator vs. Internet Explorer: Web的兴起将人类一下子拖入互联网时代, 个人与企业应用软件网络化；<br>&nbsp;●Java诞生：提供了网络时代、跨平台时代优于C++的企业应用软件开发语言；<br>&nbsp;●COM时代到来<br>&nbsp;●Delphi诞生：创新与工程原则平衡的典范；</p>
<p><br><strong>1995年：C++全盛时代</strong><br>&nbsp;●C++标准草案接近完成，语言基本稳定；<br>&nbsp;●C++工具大战结束：来自商业竞争的动力消失，MFC获胜；<br>&nbsp;●很多主流软件厂商转向C++，C++开始在大范围内被用于大规模软件开发；<br>&nbsp;●一切迹象表明，软件产业的重点将有创新转向生产。但是：C++社群在指导思想上并没有发生相应的变化。</p>
<p>&nbsp;<br><strong>我们的历史失误</strong><br>&nbsp;●C++社群从来没有联合起来支持任何一个跨平台的二进制组件标准（如COM/SOM/CCM）和基础库（如Apache APR、ACE OS Wrapper）；<br>&nbsp;●C++社群从来没有联合起来支持任何一个跨平台的C++虚拟机、解释器、内存检测工具和错误录像工具，也从来没有促成过一个安全的库；<br>&nbsp;●Boost出现于1999-2000年，而在此之前的跨平台C++库都没有获得广泛的支持；<br>&nbsp;●钟情于用C++语法（无论多么复杂和稀奇古怪）完成所有的任务，却丢掉了老祖宗C语言的看家法宝——Little Language；<br>&nbsp;●对于风格争论不休，对于明显的技术进步拒不接受，对于很多后来被证明并不实用的技巧趋之若鹜。</p>
<p>&nbsp;&nbsp;&nbsp; 没有跨平台的基础库，就没有跨平台的动态模块加载机制；<br>&nbsp;&nbsp;&nbsp; John Spencer夭折的书《The Art of C Programming》，GoF的Interpreter模式；Little Language实际上具有反映计算机本质的一些东西，现在却成了很少为C++程序员所采用和熟悉的工具。</p>
<p>&nbsp;</p>
<p><strong>2005年，C++的现实处境</strong><br>&nbsp;●在系统编程领域仍然强势；<br>&nbsp;●套装软件主流开发语言之一；<br>&nbsp;●嵌入式开发领域进展较快；<br>&nbsp;●游戏引擎开发主力；<br>&nbsp;●科学计算方面略有一席之地<br>&nbsp;●遗留项目的维护；<br>&nbsp;●在企业应用开发领域快速收缩；<br>&nbsp;●Web开发中的影子语言；<br>&nbsp;●从高校主流教学中退潮；<br>&nbsp;●整体水平仍然不高，很多企业急于摆脱；<br>&nbsp;●最致命的：真正了解和熟练掌握C++的人太少；</p>
<p>案例：1. 国外一家公司花高薪聘人，要么能维护目前百万行规模的代码，要么把它转成Java；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. IBM Workplace，项目一开始C++/Java并重，之后C++比重越来越小；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. 微软与中国电信合作一个项目，客户端软件本来要用C++写，后来赶到产品化周期太长，改用C#，后发先至。&nbsp;</p>
<p><br><strong>问题何在<br></strong>&nbsp;●当前的软件产业发展的主要矛盾——各行各业对软件生产标准化、规模化、高质量要求与慢节奏、低效率、低质量的软件开发之间的矛盾。<br>&nbsp;●解决这个矛盾的关键：组件化体系，成熟的软件生产工具和环境，不断的创新精神。<br>&nbsp;●C++在外部环境已经发生根本变化的近十年时间里，没有抓住这个主要矛盾。</p>
<p><br><strong>重新评估我们的C++价值取向</strong><br>&nbsp;&nbsp;&nbsp; 重新评估&#8220;高级C++&#8221;的现实含义：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 简洁有效优于惊世骇俗；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 开放灵活优于保守固执；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 帮助他人优于凸现自己；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 领域创新优于卖弄技巧；</p>
<p>&nbsp;<br><strong>六个建议<br></strong>&nbsp;●学会与现实和谐共处；<br>&nbsp;●尽快面向不同领域建立跨平台构件标准；<br>&nbsp;●支持各领域已经形成的基础库不断完善；<br>&nbsp;●支持相关工具厂商，迅速完善工具链；<br>&nbsp;●支持动态语言的发展；<br>&nbsp;●面向产业挑战创新发展；</p>
<p>&nbsp;</p>
<p><strong>与现实和谐共处<br></strong>&nbsp;●承认C++只适合这个世界的一部分工作，快乐地与其他语言共同协作；<br>&nbsp;●告别妄自尊大和保守傲慢；<br>&nbsp;●尊重其他社群的专业能力和成绩；<br>&nbsp;●坦率承认C++在很多场合并非理想选择；<br>&nbsp;●在C++擅长的领域保持锐意。</p>
<p><br><strong>跨平台构件标准<br></strong>&nbsp;●C++迈向未来的关键技术步骤；<br>&nbsp;●尽可能支持现有的成熟方案；<br>&nbsp;●在不同尺度的平台上可能需要不同的标准；</p>
<p>&nbsp;</p>
<p><strong>支持成熟的基础库<br></strong>&nbsp;●基本组件：STL和Boost（部分）<br>&nbsp;●网络和系统编程：ACE<br>&nbsp;●分布式计算：ICE<br>&nbsp;●GUI：Qt<br>&nbsp;●Windows：MFC/ATL/WTL<br>&nbsp;●科学计算：MTL</p>
<p>&nbsp;</p>
<p><strong>完善工具链<br></strong>&nbsp;●C++用的GC；<br>&nbsp;●Code Review工具；<br>&nbsp;●内存错误排查工具；<br>&nbsp;●测试工具；<br>&nbsp;●MDA工具；<br>&nbsp;●文档工具；<br>&nbsp;●持续集成工具；<br>&nbsp;●运行录像工具。</p>
<p><br><strong>支持动态语言<br></strong>&nbsp;●动态语言是软件技术发展的一个重要方向，几年后会成为主流。<br>&nbsp;●目前几个流行动态语言天生与C/C++具有亲缘关系；<br>&nbsp;●加强对动态语言的友好性，是C++未来发展的一项重要任务；<br>&nbsp;●从这个角度来看待C++/CLI，我们应该持积极态度；<br>&nbsp;●Little Language问题；</p>
<p><br><strong>迎接产业新挑战</strong><br>&nbsp;●多核CPU带来根本性挑战，C++有责任挺身而出，为其他语言铺平前进道路；<br>&nbsp;●安全性问题，C/C++实际上是给整个产业拖了后腿，对此我们应当充分关注，积极改进；<br>&nbsp;●将STL思想精华发扬光大。<br></p>
<img src ="http://www.cppblog.com/andxie99/aggbug/22600.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-04-22 19:50 <a href="http://www.cppblog.com/andxie99/archive/2007/04/22/22600.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruminations on C++ 中的代理类Demo</title><link>http://www.cppblog.com/andxie99/archive/2007/03/29/20899.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Thu, 29 Mar 2007 14:44:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/03/29/20899.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/20899.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/03/29/20899.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/20899.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/20899.html</trackback:ping><description><![CDATA[看Ruminations on C++ 的时候照着写的，简单的框架，留作备份吧。<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;代理类&nbsp;Demo<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;将继承和容器共用，迫使我们要处理两个问题：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;控制内存分配和把不同类型的对象放入同一个容器中。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;代理类的每个对象都代表另一个对象，该对象可以是<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;位于一个完整继承层次中的任何类的对象。通过在容器中<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;用代理对象而不是对象本身来解决以上两个问题</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">process.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;system()</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;std;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;所有交通工具的基类</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Vehicle<br><img id=Codehighlighter1_250_365_Open_Image onclick="this.style.display='none'; Codehighlighter1_250_365_Open_Text.style.display='none'; Codehighlighter1_250_365_Closed_Image.style.display='inline'; Codehighlighter1_250_365_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_250_365_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_250_365_Closed_Text.style.display='none'; Codehighlighter1_250_365_Open_Image.style.display='inline'; Codehighlighter1_250_365_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_250_365_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_250_365_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;start()&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;动态复制</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;Vehicle</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;copy()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;虚析构函数</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_362_363_Open_Image onclick="this.style.display='none'; Codehighlighter1_362_363_Open_Text.style.display='none'; Codehighlighter1_362_363_Closed_Image.style.display='inline'; Codehighlighter1_362_363_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_362_363_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_362_363_Closed_Text.style.display='none'; Codehighlighter1_362_363_Open_Image.style.display='inline'; Codehighlighter1_362_363_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Vehicle()&nbsp;</span><span id=Codehighlighter1_362_363_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_362_363_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;交通工具的代理类</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;VehicleSurrogate<br><img id=Codehighlighter1_404_694_Open_Image onclick="this.style.display='none'; Codehighlighter1_404_694_Open_Text.style.display='none'; Codehighlighter1_404_694_Closed_Image.style.display='inline'; Codehighlighter1_404_694_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_404_694_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_404_694_Closed_Text.style.display='none'; Codehighlighter1_404_694_Open_Image.style.display='inline'; Codehighlighter1_404_694_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_404_694_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_404_694_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;无参构造函数，用于创建数组</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;VehicleSurrogate();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;用Vehicle&nbsp;及其派生类构造</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;VehicleSurrogate(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;Vehicle</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">VehicleSurrogate();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;拷贝及赋值</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;VehicleSurrogate(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;VehicleSurrogate</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;VehicleSurrogate</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;VehicleSurrogate</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Vehicle&nbsp;的方法</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;start();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Vehicle</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;p;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img id=Codehighlighter1_742_743_Open_Image onclick="this.style.display='none'; Codehighlighter1_742_743_Open_Text.style.display='none'; Codehighlighter1_742_743_Closed_Image.style.display='inline'; Codehighlighter1_742_743_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_742_743_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_742_743_Closed_Text.style.display='none'; Codehighlighter1_742_743_Open_Image.style.display='inline'; Codehighlighter1_742_743_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>VehicleSurrogate::VehicleSurrogate()&nbsp;:&nbsp;p(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;</span><span id=Codehighlighter1_742_743_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_742_743_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img id=Codehighlighter1_813_814_Open_Image onclick="this.style.display='none'; Codehighlighter1_813_814_Open_Text.style.display='none'; Codehighlighter1_813_814_Closed_Image.style.display='inline'; Codehighlighter1_813_814_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_813_814_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_813_814_Closed_Text.style.display='none'; Codehighlighter1_813_814_Open_Image.style.display='inline'; Codehighlighter1_813_814_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>VehicleSurrogate::VehicleSurrogate(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;Vehicle</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;v)&nbsp;:&nbsp;p(v.copy())&nbsp;</span><span id=Codehighlighter1_813_814_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_813_814_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>VehicleSurrogate::VehicleSurrogate(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;VehicleSurrogate</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;vs)&nbsp;<br><img id=Codehighlighter1_910_911_Open_Image onclick="this.style.display='none'; Codehighlighter1_910_911_Open_Text.style.display='none'; Codehighlighter1_910_911_Closed_Image.style.display='inline'; Codehighlighter1_910_911_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_910_911_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_910_911_Closed_Text.style.display='none'; Codehighlighter1_910_911_Open_Image.style.display='inline'; Codehighlighter1_910_911_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>:&nbsp;p(vs.p&nbsp;</span><span style="COLOR: #000000">?</span><span style="COLOR: #000000">&nbsp;vs.p</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">copy()&nbsp;:&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;</span><span id=Codehighlighter1_910_911_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_910_911_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>VehicleSurrogate&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;VehicleSurrogate::</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;VehicleSurrogate</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;vs)<br><img id=Codehighlighter1_990_1072_Open_Image onclick="this.style.display='none'; Codehighlighter1_990_1072_Open_Text.style.display='none'; Codehighlighter1_990_1072_Closed_Image.style.display='inline'; Codehighlighter1_990_1072_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_990_1072_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_990_1072_Closed_Text.style.display='none'; Codehighlighter1_990_1072_Open_Image.style.display='inline'; Codehighlighter1_990_1072_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_990_1072_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_990_1072_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(p&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;vs.p)<br><img id=Codehighlighter1_1009_1055_Open_Image onclick="this.style.display='none'; Codehighlighter1_1009_1055_Open_Text.style.display='none'; Codehighlighter1_1009_1055_Closed_Image.style.display='inline'; Codehighlighter1_1009_1055_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1009_1055_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1009_1055_Closed_Text.style.display='none'; Codehighlighter1_1009_1055_Open_Image.style.display='inline'; Codehighlighter1_1009_1055_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1009_1055_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1009_1055_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;p;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;vs.p&nbsp;</span><span style="COLOR: #000000">?</span><span style="COLOR: #000000">&nbsp;vs.p</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">copy()&nbsp;:&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img id=Codehighlighter1_1113_1125_Open_Image onclick="this.style.display='none'; Codehighlighter1_1113_1125_Open_Text.style.display='none'; Codehighlighter1_1113_1125_Closed_Image.style.display='inline'; Codehighlighter1_1113_1125_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_1113_1125_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1113_1125_Closed_Text.style.display='none'; Codehighlighter1_1113_1125_Open_Image.style.display='inline'; Codehighlighter1_1113_1125_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>VehicleSurrogate::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">VehicleSurrogate()&nbsp;</span><span id=Codehighlighter1_1113_1125_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1113_1125_Open_Text><span style="COLOR: #000000">{&nbsp;delete&nbsp;p;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;VehicleSurrogate::start()<br><img id=Codehighlighter1_1159_1216_Open_Image onclick="this.style.display='none'; Codehighlighter1_1159_1216_Open_Text.style.display='none'; Codehighlighter1_1159_1216_Closed_Image.style.display='inline'; Codehighlighter1_1159_1216_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_1159_1216_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1159_1216_Closed_Text.style.display='none'; Codehighlighter1_1159_1216_Open_Image.style.display='inline'; Codehighlighter1_1159_1216_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_1159_1216_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1159_1216_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(p)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">start();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Error</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;endl;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;RoadVehicle&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;Vehicle<br><img id=Codehighlighter1_1254_1420_Open_Image onclick="this.style.display='none'; Codehighlighter1_1254_1420_Open_Text.style.display='none'; Codehighlighter1_1254_1420_Closed_Image.style.display='inline'; Codehighlighter1_1254_1420_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_1254_1420_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1254_1420_Closed_Text.style.display='none'; Codehighlighter1_1254_1420_Open_Image.style.display='inline'; Codehighlighter1_1254_1420_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_1254_1420_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1254_1420_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;start()<br><img id=Codehighlighter1_1280_1323_Open_Image onclick="this.style.display='none'; Codehighlighter1_1280_1323_Open_Text.style.display='none'; Codehighlighter1_1280_1323_Closed_Image.style.display='inline'; Codehighlighter1_1280_1323_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1280_1323_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1280_1323_Closed_Text.style.display='none'; Codehighlighter1_1280_1323_Open_Image.style.display='inline'; Codehighlighter1_1280_1323_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1280_1323_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1280_1323_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">RoadVehicle&nbsp;start.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;endl;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Vehicle</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;copy()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_1349_1396_Open_Image onclick="this.style.display='none'; Codehighlighter1_1349_1396_Open_Text.style.display='none'; Codehighlighter1_1349_1396_Closed_Image.style.display='inline'; Codehighlighter1_1349_1396_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1349_1396_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1349_1396_Closed_Text.style.display='none'; Codehighlighter1_1349_1396_Open_Image.style.display='inline'; Codehighlighter1_1349_1396_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1349_1396_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1349_1396_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;(Vehicle</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;RoadVehicle(</span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">RoadVehicle()<br><img id=Codehighlighter1_1415_1418_Open_Image onclick="this.style.display='none'; Codehighlighter1_1415_1418_Open_Text.style.display='none'; Codehighlighter1_1415_1418_Closed_Image.style.display='inline'; Codehighlighter1_1415_1418_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1415_1418_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1415_1418_Closed_Text.style.display='none'; Codehighlighter1_1415_1418_Open_Image.style.display='inline'; Codehighlighter1_1415_1418_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1415_1418_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1415_1418_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;AutoVehicle&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;RoadVehicle<br><img id=Codehighlighter1_1463_1629_Open_Image onclick="this.style.display='none'; Codehighlighter1_1463_1629_Open_Text.style.display='none'; Codehighlighter1_1463_1629_Closed_Image.style.display='inline'; Codehighlighter1_1463_1629_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_1463_1629_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1463_1629_Closed_Text.style.display='none'; Codehighlighter1_1463_1629_Open_Image.style.display='inline'; Codehighlighter1_1463_1629_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_1463_1629_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1463_1629_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;start()<br><img id=Codehighlighter1_1489_1532_Open_Image onclick="this.style.display='none'; Codehighlighter1_1489_1532_Open_Text.style.display='none'; Codehighlighter1_1489_1532_Closed_Image.style.display='inline'; Codehighlighter1_1489_1532_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1489_1532_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1489_1532_Closed_Text.style.display='none'; Codehighlighter1_1489_1532_Open_Image.style.display='inline'; Codehighlighter1_1489_1532_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1489_1532_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1489_1532_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">AutoVehicle&nbsp;start.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;endl;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Vehicle</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;copy()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_1558_1605_Open_Image onclick="this.style.display='none'; Codehighlighter1_1558_1605_Open_Text.style.display='none'; Codehighlighter1_1558_1605_Closed_Image.style.display='inline'; Codehighlighter1_1558_1605_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1558_1605_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1558_1605_Closed_Text.style.display='none'; Codehighlighter1_1558_1605_Open_Image.style.display='inline'; Codehighlighter1_1558_1605_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1558_1605_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1558_1605_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;(Vehicle</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;AutoVehicle(</span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">AutoVehicle()<br><img id=Codehighlighter1_1624_1627_Open_Image onclick="this.style.display='none'; Codehighlighter1_1624_1627_Open_Text.style.display='none'; Codehighlighter1_1624_1627_Closed_Image.style.display='inline'; Codehighlighter1_1624_1627_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1624_1627_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1624_1627_Closed_Text.style.display='none'; Codehighlighter1_1624_1627_Open_Image.style.display='inline'; Codehighlighter1_1624_1627_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1624_1627_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1624_1627_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_1645_1853_Open_Image onclick="this.style.display='none'; Codehighlighter1_1645_1853_Open_Text.style.display='none'; Codehighlighter1_1645_1853_Closed_Image.style.display='inline'; Codehighlighter1_1645_1853_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_1645_1853_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1645_1853_Closed_Text.style.display='none'; Codehighlighter1_1645_1853_Open_Image.style.display='inline'; Codehighlighter1_1645_1853_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_1645_1853_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1645_1853_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;VehicleSurrogate&nbsp;pa[</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;RoadVehicle</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;prv&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;RoadVehicle();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pa[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">prv;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;prv;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pa[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AutoVehicle();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pa[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;RoadVehicle();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pa[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">].start();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pa[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">].start();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pa[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">].start();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pause</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<img src ="http://www.cppblog.com/andxie99/aggbug/20899.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-03-29 22:44 <a href="http://www.cppblog.com/andxie99/archive/2007/03/29/20899.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类厂和COM类的关系</title><link>http://www.cppblog.com/andxie99/archive/2007/03/07/19341.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 07 Mar 2007 02:24:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/03/07/19341.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/19341.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/03/07/19341.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/19341.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/19341.html</trackback:ping><description><![CDATA[读过《COM技术内幕》，理一下用类厂创建COM类的过程以及之间的关系。<br><br>类厂用来抽象组件的create过程，客户不需要知道组件的详细情况，也不需要知道类厂的详细情况，只要知道CoCreateInstance可以创建组件即可。而CoCreateInstance内部调用DllGetClassObject来生成该组件的类厂，由于类厂有组件的作者撰写，所以对组件类可谓知根知底，由类厂来生成组件完全行得通，这样客户和组件就进一步划分，客户只能查询该组件是否支持某接口，而对组件的其他情况一无所知，这样的划分可以使组件和客户间的耦合更小。<br>组件如果将某接口的全部方法都实现了，就称该组件支持某接口，com并没有规定组件和接口之间是虚函数继承的关系，只是在c++中以这种方法来实现最好而已。 &nbsp; <br>&nbsp; IClassFactory说穿了就是专门构造组件的类，这样做是为了抽象，因为客户没有必要知道组件是什么，如果由客户直接构造组件，客户势必要知道组件的信息，com就失去了它的意义了，所以，规定了一个类厂（支持IClassFactory接口），每个组件的类厂都很清楚并且也只清楚该组件的信息，而客户只需要调用com库函数CoCreateInstance就可以了。&nbsp;&nbsp;&nbsp;<br>&nbsp; 创建流程图： &nbsp; <br>&nbsp; CoCreateInstance &nbsp; --&gt;&gt; &nbsp; CoGetClassObject &nbsp; --&gt;&gt; &nbsp; DllGetClassObject &nbsp; --&gt;&gt; &nbsp; new &nbsp; ClassFactory&nbsp;&nbsp;&nbsp; --&gt;&gt;IClassFactory::CreateInstance() &nbsp; --&gt;&gt; &nbsp; new &nbsp; Component 
<img src ="http://www.cppblog.com/andxie99/aggbug/19341.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-03-07 10:24 <a href="http://www.cppblog.com/andxie99/archive/2007/03/07/19341.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用IDropTarget接口同时支持文本和文件拖放（转）</title><link>http://www.cppblog.com/andxie99/archive/2007/03/05/19228.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Mon, 05 Mar 2007 04:52:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2007/03/05/19228.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/19228.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2007/03/05/19228.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/19228.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/19228.html</trackback:ping><description><![CDATA[<p align=justify>&nbsp;最近在写Shell Extension方面的东西，看到了这篇文章，抄在这里。<br>原文地址<a href="http://blog.csdn.net/vcbear/archive/2002/01/25/5990.aspx">http://blog.csdn.net/vcbear/archive/2002/01/25/5990.aspx</a><br>同时也找到了一个与Drag and Drop有关的例子，地址：<a href="http://www.codeproject.com/useritems/NSExtDragDrop.asp">http://www.codeproject.com/useritems/NSExtDragDrop.asp</a></p>
<font lang=ZH-CN face=宋体 size=3>
<p align=justify></p>
</font><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#118;&#99;&#98;&#101;&#97;&#114;&#64;&#49;&#54;&#51;&#46;&#99;&#111;&#109;"><font face="宋体, MS Song" size=4>vcbear</font> </a><font lang=ZH-CN face=宋体>
<p align=justify>关于</p>
</font><font face="宋体, MS Song">Windows</font> <font lang=ZH-CN face=宋体>的外壳扩展编程，拖放是比较简单的一种，在网上可以找到不少介绍这个技巧的文章。大部分是介绍使用</font> <font face="宋体, MS Song">MFC</font> <font lang=ZH-CN face=宋体>的</font> <font face="宋体, MS Song">COleDropTarget</font> <font lang=ZH-CN face=宋体>实现的，我觉得一般使用</font> <font face="宋体, MS Song">COleDropTarget</font> <font lang=ZH-CN face=宋体>已经很好了，但是我习惯在一些程序模块中，完全的不使用</font> <font face="宋体, MS Song">MFC,</font> <font lang=ZH-CN face=宋体>比如纯</font> <font face="宋体, MS Song">SDK</font> <font lang=ZH-CN face=宋体>编程</font> <font face="宋体, MS Song">,</font> <font lang=ZH-CN face=宋体>还有用在</font> <font face="宋体, MS Song">ATL</font> <font lang=ZH-CN face=宋体>的时候</font> <font face="宋体, MS Song">,MFC</font> <font lang=ZH-CN face=宋体>是相当累赘的。所以</font> <font face="宋体, MS Song">COleDropTarget</font> <font lang=ZH-CN face=宋体>在这个意义上讲不够完美。
<p align=justify>参考了</p>
</font><font face="宋体, MS Song">MSDN</font> <font lang=ZH-CN face=宋体>以及</font> <a href="http://www.codeproject.com/"><font face="宋体, MS Song">www.CodeProject.com</font> </a><font lang=ZH-CN face=宋体>的相关文章和代码（</font> <strong><font face="宋体, MS Song">by Thomas Blenkers</font> </strong><font lang=ZH-CN face=宋体>）之后，我发现拖放实际上主要使用了</font> <font face="宋体, MS Song">IDropTarget</font> <font lang=ZH-CN face=宋体>的接口方法，非常简单，不妨直接面对原始</font> <font face="宋体, MS Song">IDropTarget</font> <font lang=ZH-CN face=宋体>实现自己的拖放类。
<p align=justify>作为学习笔记，就有了这么一篇文字,以抛砖引玉：</p>
</font><strong><font color=#0000ff>
<p align=justify>IDropTarget</p>
</font></strong><font lang=ZH-CN face=宋体>是系统留给支持拖放的客户程序的一个纯虚接口，事先没有对接口的任何函数进行实现，而是让用户通过实现接口函数来接管拖放的结果。</font>IDropTarget<font lang=ZH-CN face=宋体>接口有以下成员函数：
<ul>
    <p align=justify></p>
    <li>基本</li>
</ul>
</font><font face="宋体, MS Song">COM</font><font lang=ZH-CN face=宋体>成员函数
<p>&#160;</p>
<dir>
<dir></dir></dir></font><strong><font color=#0000ff>
<p align=justify>QueryInterface </p>
<p align=justify>AddRef </p>
<p align=justify>Release </p>
<ul></ul>
    </font></strong><font lang=ZH-CN face=宋体>
    <p align=justify></p>
    <li>接管拖放事件的成员函数：
    <p>&#160;</p>
    <dir>
    <dir></dir></dir></font><strong><font color=#0000ff>
    <p align=justify>DragEnter</p>
    <p align=justify>DragOver</p>
    <p align=justify>DragLeave</p>
    <p align=justify>Drop</p>
    </font></strong><font lang=ZH-CN face=宋体>
    <p align=justify>也就是说，要在客户程序里实现以上</p>
    </font><font face="宋体, MS Song">7</font><font lang=ZH-CN face=宋体>个函数的实体。
    <p align=justify>系统在检测到拖放发生的时候，会在合适的时候依次调用客户程序里实现的</p>
    </font><font face="宋体, MS Song">IDropTarget</font><font lang=ZH-CN face=宋体>接口相应函数，检查用户在这些函数里返回的标志，决定鼠标外观表现和拖放结果。</font><font lang=ZH-CN face=宋体 size=3>
    <p>&#160;</p>
    <hr>
    <p>&#160;</p>
    </font><strong><font lang=ZH-CN face=宋体>
    <p align=justify>　</p>
    <p align=justify>实现</p>
    </font><font face="宋体, MS Song">IDropTarget</font><font lang=ZH-CN face=宋体>接口</font></strong><br>为此建立一个基类为<font face="宋体, MS Song">IDropTarget</font><font lang=ZH-CN face=宋体>的类：</font><strong><font face="宋体, MS Song"></font>
    <p align=justify>class CDropTargetEx : public IDropTarget </p>
    </strong>
    <p align=justify>IDropTarget<font lang=ZH-CN face=宋体>接口在</font>OLEIDL.h<font lang=ZH-CN face=宋体>里定义，为纯虚接口。</font></p>
    <p align=justify>在<font face="宋体, MS Song">CDropTargetEx</font><font lang=ZH-CN face=宋体>里依次声明接口所包含的</font><font face="宋体, MS Song">7</font><font lang=ZH-CN face=宋体>个函数，原形为：</font></p>
    <font color=#0000ff>
    <p align=justify>HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject);</p>
    <p align=justify>ULONG STDMETHODCALLTYPE AddRef(void);</p>
    <p align=justify>ULONG STDMETHODCALLTYPE Release(void);</p>
    <p align=justify>HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, </p>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <p align=justify>POINTL pt, </p>
    <p align=justify>DWORD *pdwEffect);</p>
    </dir></dir></dir></dir></dir></dir></dir></dir>
    <p align=justify>HRESULT STDMETHODCALLTYPE DragEnter(IDataObject * pDataObject, </p>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <p align=justify>DWORD grfKeyState, POINTL pt, </p>
    <p align=justify>DWORD * pdwEffect);</p>
    </dir></dir></dir></dir></dir></dir></dir></dir>
    <p align=justify>HRESULT STDMETHODCALLTYPE DragLeave(void);</p>
    <p align=justify>HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, </p>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <p align=justify>DWORD grfKeyState, </p>
    <p align=justify>POINTL pt, </p>
    <p align=justify>DWORD __RPC_FAR *pdwEffect);</p>
    </dir></dir></dir></dir></dir></dir></dir></dir></font>
    <p align=justify>(<font lang=ZH-CN face=宋体>为了实现</font>Addref<font lang=ZH-CN face=宋体>计数，还有一个</font><strong>ULONG tb_RefCount</strong><font lang=ZH-CN face=宋体>成员变量是必须的。</font><strong>QueryInterface<font lang=ZH-CN face=宋体>，</font>AddRef,Release</strong><font lang=ZH-CN face=宋体>这</font>3<font lang=ZH-CN face=宋体>个函数的实现是</font>COM<font lang=ZH-CN face=宋体>知识中最基本的，请参见附例</font>)</p>
    <font lang=ZH-CN face=宋体>
    <p align=justify>在讲解</p>
    </font><font face="宋体, MS Song">IDropTarget</font><font lang=ZH-CN face=宋体>其他函数的具体实现之前，有必要介绍一下一个你可能永远不会直接调用但是确实存在的函数：</font><strong><font color=#0000ff><font face="宋体, MS Song">DoDragDrop</font></font></strong><font lang=ZH-CN face=宋体>函数.此函数在某数据源的数据被拖动的时候就被调用，它负责
    <ul>
        <p align=justify></p>
        <li>检测目标窗口是否支持拖放，发现目标窗口的</li>
    </ul>
    </font><font face="宋体, MS Song">IDropTarget</font><font lang=ZH-CN face=宋体>接口
    <p>&#160;</p>
    <p align=justify></p>
    <li>随时跟踪鼠标和键盘的状态，根据状态决定调用其</font><font face="宋体, MS Song">DrageEnter,DragMove,Drop</font><font lang=ZH-CN face=宋体>或</font><font face="宋体, MS Song">DragLeave</font><font lang=ZH-CN face=宋体>接口
    <p>&#160;</p>
    <p align=justify></p>
    <li>从这些接口获取客户程序的返回值，根据这些值和用户界面以及数据源进行交互。
    <p>&#160;</p>
    <p align=justify>可以说</p>
    </font><font face="宋体, MS Song">DoDragDrop</font><font lang=ZH-CN face=宋体>控制拖放的整个过程，我们要做的，只是将这个过程里发生的事件，接管下来并得到相应的信息，和</font><strong><font face="宋体, MS Song">DoDragDrop</font></strong><font lang=ZH-CN face=宋体>进行交互而已。了解了这一点有助于我们理解为什么通过区区一个接口</font><font face="宋体, MS Song">4</font><font lang=ZH-CN face=宋体>个函数就可以实现了拖放的效果，因为系统为我们已经做了很多。
    <p align=justify>另一个非常重要的</p>
    </font><font face="宋体, MS Song">API</font><font lang=ZH-CN face=宋体>是</font><strong><font color=#0000ff><font face="宋体, MS Song">RegisterDragDrop</font></font></strong><font lang=ZH-CN face=宋体>，这个函数的原形是这样的：</font><font color=#0000ff>
    <p align=justify>WINOLEAPI RegisterDragDrop(</p>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <dir>
    <p align=justify>HWND hwnd, </p>
    <p align=justify>IDropTarget * pDropTarget</p>
    <p align=justify>);</p>
    </dir></dir></dir></dir></dir></dir></font><font lang=ZH-CN face=宋体>
    <p align=justify>不用被</p>
    </font><font face="宋体, MS Song">WINOLEAPI</font><font lang=ZH-CN face=宋体>吓到，这是一个宏:</font><strong><font color=#0000ff>
    <p align=justify>#define STDAPI EXTERN_C HRESULT STDAPICALLTYPE</p>
    </font></strong><font lang=ZH-CN face=宋体>
    <p align=justify>也就是表示一个标准的</p>
    </font><font face="宋体, MS Song">WIN API</font><font lang=ZH-CN face=宋体>函数，返回一个</font><font face="宋体, MS Song">HRESULT</font><font lang=ZH-CN face=宋体>的值。
    <p align=justify>函数</p>
    </font><strong><font face="宋体, MS Song">RegisterDragDrop</font></strong><font lang=ZH-CN face=宋体>的作用是告诉系统:某个窗口（</font><font face="宋体, MS Song">hwnd</font><font lang=ZH-CN face=宋体>参数指定）可以接受拖放，接管拖放的接口是</font><font face="宋体, MS Song">pDropTarget</font><font lang=ZH-CN face=宋体>。
    <p align=justify>记住在调用</p>
    </font><font face="宋体, MS Song">RegisterDragDrop</font><font lang=ZH-CN face=宋体>之前，一定要先调用</font><strong><font color=#0000ff><font face="宋体, MS Song">OleInitialize</font></font></strong><font lang=ZH-CN face=宋体>初始化</font><font face="宋体, MS Song">OLE</font><font lang=ZH-CN face=宋体>环境。
    <p align=justify>在类</p>
    </font><font face="宋体, MS Song">CDropTargetEx</font><font lang=ZH-CN face=宋体>里设计了一个函数</font><font color=#0000ff>
    <p align=justify>BOOL CDropTargetEx::DragDropRegister(HWND hWnd,</p>
    <p align=justify>DWORD AcceptKeyState=|MK_LBUTTON)</p>
    <p align=justify>{</p>
    </font><font lang=ZH-CN face=宋体 color=#0000ff>
    <p align=justify></p>
    </font><font color=#0000ff><font face="宋体, MS Song">if(!IsWindow(hWnd))return false;</font>
    <p align=justify>HRESULT s = ::RegisterDragDrop (hWnd,this);</p>
    <p align=justify>if(SUCCEEDED(s))</p>
    <p align=justify>{</p>
    <p align=justify>m_hTargetWnd = hWnd;</p>
    <p align=justify>m_AcceptKeyState = AcceptKeyState;</p>
    <p align=justify>return true;</p>
    <p align=justify>}</p>
    <p align=justify>else { return false; }</p>
    <p align=justify>}</p>
    </font><font lang=ZH-CN face=宋体>
    <p align=justify>在这个函数里调用</p>
    </font><font face="宋体, MS Song">RegisterDragDrop,</font><font lang=ZH-CN face=宋体>将</font><font face="宋体, MS Song">this</font><font lang=ZH-CN face=宋体>指针传入，表示本类实现了</font><font face="宋体, MS Song">IDropTarget.</font><font lang=ZH-CN face=宋体>，由本类接管拖放事件。另外顺便定义了一下拖放鼠标和键盘特性常数，对这个类来说，我希望默认的只接受鼠标左键的拖放，所以，默认的</font><font face="宋体, MS Song">AcceptKeyState</font><font lang=ZH-CN face=宋体>值是</font><strong><font face="宋体, MS Song">MK_LBUTTON</font></strong><font lang=ZH-CN face=宋体>。相关的键盘鼠标常数还有</font><strong><font face="宋体, MS Song">MK_SHIFT,MK_ALT,MK_RBOTTON,MK_MBUTTON,MK_BOTTON</font></strong><font lang=ZH-CN face=宋体>等几个，我想这个几个常数从字面上就可以理解它的意思了。这些常数可以用&#8220;位与&#8221;的操作组合。
    <p align=justify>以下具体讨论</p>
    </font><font face="宋体, MS Song">IDropTarget</font><font lang=ZH-CN face=宋体>的拖放相关接口函数（</font><font face="宋体, MS Song">4</font><font lang=ZH-CN face=宋体>个），这里的拖放对象以文本和文件为主。</font><font lang=ZH-CN face=宋体 size=3>
    <p>&#160;</p>
    <hr>
    <p>&#160;</p>
    <ul></ul>
        </font><strong><font color=#ff0000 size=4>
        <p align=justify></p>
        <li>DragEnter
        <p>&#160;</p>
        <dir></dir></font></strong><font lang=ZH-CN face=宋体>
        <p align=justify>当你用鼠标选中了某一个文件或一段文本，并且将鼠标移到某个可以接受拖放（已经调用过</p>
        </font><font face="宋体, MS Song">RegisterDragDrop</font><font lang=ZH-CN face=宋体>）的窗口里，</font><font face="宋体, MS Song">DragEnter</font><font lang=ZH-CN face=宋体>将第一时间被调用。再看一下其原形：</font><strong><font color=#0000ff>
        <p align=justify>HRESULT DragEnter( IDataObject * pDataObject,</p>
        <dir>
        <dir>
        <dir>
        <p align=justify>&nbsp;&nbsp; &nbsp; DWORD grfKeyState,</p>
        <p align=justify>&nbsp;&nbsp;&nbsp; &nbsp;POINTL pt, </p>
        <p align=justify>&nbsp;&nbsp; &nbsp;&nbsp; DWORD * pdwEffect&nbsp;&nbsp; )</p>
        </dir></dir></dir></font>
        <p align=justify>pDataobject </p>
        </strong><font lang=ZH-CN face=宋体>是从拖放的原数据中传递过来的一个</font>IDataObject<font lang=ZH-CN face=宋体>接口实例，包含数据对象的一些相关方法，可以通过此接口获得数据。</font><strong>
        <p align=justify>grfKeyState </p>
        </strong><font lang=ZH-CN face=宋体>为</font>DragEnter<font lang=ZH-CN face=宋体>被调用时当前的键盘和鼠标的状态，包含上面介绍过的键盘鼠标状态常数。</font><strong>
        <p align=justify>pt</p>
        </strong><font lang=ZH-CN face=宋体>表示鼠标所在的点。是以整个屏幕为参考坐标的。</font><strong>
        <p align=justify>pdwEffect</p>
        </strong><font lang=ZH-CN face=宋体>是</font>DoDragDrop<font lang=ZH-CN face=宋体>提供的一个</font>DWORD<font lang=ZH-CN face=宋体>指针，客户程序通过这个指针给</font>DoDragDrop<font lang=ZH-CN face=宋体>返回特定的状态。有效的状态包括：</font>
        <p align=justify>DROPEFFECT_NONE=0 <font lang=ZH-CN face=宋体>表示此窗口不能接受拖放。</font></p>
        <p align=justify>DROPEFFECT_MOVE=1 <font lang=ZH-CN face=宋体>表示拖放的结果将使源对象被删除</font></p>
        <p align=justify>DROPEFFECT_COPY=2 <font lang=ZH-CN face=宋体>表示拖放将引起源对象的复制。</font></p>
        <p align=justify>DROPEFFECT_LINK =4 <font lang=ZH-CN face=宋体>表示拖放源对象创建了一个对自己的连接</font></p>
        <p align=justify>DROPEFFECT_SCROLL=0x80000000<font lang=ZH-CN face=宋体>表示拖放目标窗口正在或将要进行卷滚。此标志可以和其他几个合用</font></p>
        <p align=justify>对于拖放对象来说，一般只要使用<strong><font face="宋体, MS Song">DROPEFFECT_NONE</font></strong><font lang=ZH-CN face=宋体>和</font><strong><font face="宋体, MS Song">DROPEFFECT_COPY</font></strong><font lang=ZH-CN face=宋体>即可。</font></p>
        <p align=justify>在<font face="宋体, MS Song">DragEnter</font><font lang=ZH-CN face=宋体>里要做什么呢？主要是告知拖放已经进入窗口区域，并判断是否支持某具体类型的拖放。</font></p>
        <p align=justify>首先<font face="宋体, MS Song">,</font><font lang=ZH-CN face=宋体>要判断键盘的状态。在调用</font><font face="宋体, MS Song">DragDropRegister</font><font lang=ZH-CN face=宋体>时我传入了一个</font><strong><font face="宋体, MS Song">AcceptKeyState</font></strong><font lang=ZH-CN face=宋体>并将其保存在</font><strong><font face="宋体, MS Song">m_AcceptKeyState</font></strong><font lang=ZH-CN face=宋体>成员变量里，现在可以拿它跟这里得到的</font><font face="宋体, MS Song">grfKeyState</font><font lang=ZH-CN face=宋体>比较：</font></p>
        <font color=#0000ff>
        <p align=justify>if(grfKeyState!=m_AcceptKeyState )</p>
        <p align=justify>{</p>
        <p align=justify>*pdwEffect = DROPEFFECT_NONE;</p>
        <p align=justify>return S_OK;</p>
        <p align=justify>}</p>
        </font><font lang=ZH-CN face=宋体>
        <p align=justify>如果键盘和鼠标的状态和我期望的不一样，那么</p>
        </font><font face="宋体, MS Song">pdwEffect</font><font lang=ZH-CN face=宋体>里返回</font><strong><font face="宋体, MS Song">DROPEFFECT_NONE</font></strong><font lang=ZH-CN face=宋体>表示不接受拖放。
        <p align=justify>然后</p>
        </font><font face="宋体, MS Song">,</font><font lang=ZH-CN face=宋体>判断拖放过来的</font><font face="宋体, MS Song">IDataObject</font><font lang=ZH-CN face=宋体>对象里有没有我感兴趣的数据。
        <p align=justify>这里要介绍的是两个关键的结构体</p>
        </font><font face="宋体, MS Song">FORMATETC</font><font lang=ZH-CN face=宋体>和</font><font face="宋体, MS Song">STDMEDIUM</font><strong>
        <p align=justify>FORMATETC</p>
        </strong><font lang=ZH-CN face=宋体>是</font>OLE<font lang=ZH-CN face=宋体>数据交换的一个关键结构，对某种设备，数据，和相关媒体做了格式上的描述。
        <p align=justify>其定义为</p>
        </font><font color=#0000ff>
        <p align=justify>typedef struct tagFORMATETC </p>
        <p align=justify>{ </p>
        <dir>
        <dir>
        <p align=justify>CLIPFORMAT cfFormat; </p>
        <p align=justify>DVTARGETDEVICE *ptd; </p>
        <p align=justify>DWORD dwAspect; </p>
        <p align=justify>LONG lindex; </p>
        <p align=justify>DWORD tymed; </p>
        </dir></dir></font><font lang=ZH-CN face=宋体 color=#0000ff>
        <p align=justify>}</p>
        </font><font color=#0000ff><font face="宋体, MS Song">FORMATETC, *LPFORMATETC;</font></font><font lang=ZH-CN face=宋体>
        <p align=justify>在这里我们最感兴趣的是</p>
        </font><strong><font face="宋体, MS Song">cfFormat</font></strong><font lang=ZH-CN face=宋体>和</font><strong><font face="宋体, MS Song">tymed</font></strong><font lang=ZH-CN face=宋体>两个数据。</font><strong><font face="宋体, MS Song">cfFormat</font></strong><font lang=ZH-CN face=宋体>是标准的&#8220;粘帖板&#8221;数据类型比如</font><strong><font face="宋体, MS Song">CF_TEXT</font></strong><font lang=ZH-CN face=宋体>之类。</font><font face="宋体, MS Song">tymed</font><font lang=ZH-CN face=宋体>表示数据所依附的媒介，比如内存，磁盘文件，存储对象等等。其他的成员可以参见</font><font face="宋体, MS Song">MSDN</font><font lang=ZH-CN face=宋体>。
        <p align=justify>一个典型的</p>
        </font><font face="宋体, MS Song">FORMATETC</font><font lang=ZH-CN face=宋体>结构变量定义如下：</font><strong>
        <p align=justify>FORMATETC cFmt = {(CLIPFORMAT) CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};</p>
        </strong>
        <p align=justify>IDataObject<font lang=ZH-CN face=宋体>提供了一个</font>GetData<font lang=ZH-CN face=宋体>接口来获取其实例里包含的数据，比如：</font></p>
        <font color=#0000ff>
        <p align=justify>STGMEDIUM stgMedium;</p>
        <p align=justify>ret = pDataObject-&gt;GetData(&amp;cFmt, &amp;stgMedium);</p>
        </font>
        <p align=justify>GetData<font lang=ZH-CN face=宋体>传入</font>cFmt<font lang=ZH-CN face=宋体>，以指出所感兴趣的数据，并将返回在</font><strong>stgMedium</strong><font lang=ZH-CN face=宋体>结构里。</font></p>
        <strong>
        <p align=justify>STGMEDIUM</p>
        </strong><font lang=ZH-CN face=宋体>的定义如下1</font><font color=#0000ff>
        <p align=justify>typedef struct tagSTGMEDIUM </p>
        <p align=justify>{ </p>
        <p align=justify>DWORD tymed; </p>
        <p align=justify>[switch_type(DWORD), switch_is((DWORD) tymed)] </p>
        <p align=justify>union { </p>
        <p align=justify>[case(TYMED_GDI)] HBITMAP hBitmap; </p>
        <p align=justify>[case(TYMED_MFPICT)] HMETAFILEPICT hMetaFilePict; </p>
        <p align=justify>[case(TYMED_ENHMF)] HENHMETAFILE hEnhMetaFile; </p>
        <p align=justify>[case(TYMED_HGLOBAL)] HGLOBAL hGlobal; </p>
        <p align=justify>[case(TYMED_FILE)] LPWSTR lpszFileName; </p>
        <p align=justify>[case(TYMED_ISTREAM)] IStream *pstm; </p>
        <p align=justify>[case(TYMED_ISTORAGE)] IStorage *pstg; </p>
        <p align=justify>[default] ; </p>
        <p align=justify>}; </p>
        <p align=justify>[unique] IUnknown *pUnkForRelease; </p>
        <p align=justify>}STGMEDIUM; </p>
        <p align=justify>typedef STGMEDIUM *LPSTGMEDIUM; </p>
        </font><font lang=ZH-CN face=宋体>
        <p align=justify>看起来颇为复杂，其实主要是一系列句柄或数据对象接口的联合，根据数据具体的类型，使用其中之一即可。</p>
        </font><font face="宋体, MS Song" color=#0000ff>tymed</font><font lang=ZH-CN face=宋体>和</font><font face="宋体, MS Song">FORMATETC</font><font lang=ZH-CN face=宋体>里一样，指出数据的载体类型（遗憾的是它不能指出具体的标准类型比如</font><font face="宋体, MS Song">CF_TEXT</font><font lang=ZH-CN face=宋体>或者其他）。至于</font><font face="宋体, MS Song" color=#0000ff>pUnkForRelease,</font><font lang=ZH-CN face=宋体>是源数据指定的一个接口，用来传递给</font><font face="宋体, MS Song">ReleaseStgMedium</font><font lang=ZH-CN face=宋体>函数，如果它不为</font><font face="宋体, MS Song">NULL</font><font lang=ZH-CN face=宋体>，则</font><font face="宋体, MS Song">ReleaseStgMedium</font><font lang=ZH-CN face=宋体>函数使用这个接口释放数据。如果为</font><font face="宋体, MS Song">NULL,</font><font lang=ZH-CN face=宋体>则</font><font face="宋体, MS Song">ReleaseStgMedium</font><font lang=ZH-CN face=宋体>函数使用默认的</font><font face="宋体, MS Song">IUnknown</font><font lang=ZH-CN face=宋体>接口。对于常规的拖放来说，这个对象指针应该为</font><font face="宋体, MS Song">NULL.</font><font lang=ZH-CN face=宋体>
        <p align=justify>得到了句柄或数据对象接口，也相当于得到了拖放的数据。</p>
        <p align=justify>定义一个特定的</p>
        </font><strong><font face="宋体, MS Song">FORMATETC</font></strong><font lang=ZH-CN face=宋体>结构实例传递给</font><font face="宋体, MS Song">IDataObject</font><font lang=ZH-CN face=宋体>的</font><font face="宋体, MS Song">GetData</font><font lang=ZH-CN face=宋体>，可以直接询问和获取某一种特定的数据。如果我们对我们想要的数据是非常确定的，这是比较有效率的方法。但是如果我们期望能够对拖放的对象进行自适应的话，我们可以采取枚举</font><font face="宋体, MS Song">IDataObject</font><font lang=ZH-CN face=宋体>里包含的所有数据类型的方案。这就要用到</font><strong><font face="宋体, MS Song"><font color=#0000ff>IEnumFORMATETC</font></font></strong><font lang=ZH-CN face=宋体>接口了。</font>
        <p align=justify>IEnumFORMATETC<font lang=ZH-CN face=宋体>接口从</font>IDataObject<font lang=ZH-CN face=宋体>接口里获取：</font></p>
        <dir>
        <dir><font color=#0000ff>
        <p align=justify>IEnumFormatETC *pEnumFmt = NULL;</p>
        <p align=justify>ret = pDataObject-&gt;EnumFormatEtc (DATADIR_GET,&amp;pEnumFmt);</p>
        </font></dir></dir><font lang=ZH-CN face=宋体>
        <p align=justify>如果获取成功，则可以通过</p>
        </font><font face="宋体, MS Song">IEnumFORMATETC</font><font lang=ZH-CN face=宋体>接口的</font><font face="宋体, MS Song">Next</font><font lang=ZH-CN face=宋体>方法，来枚举所有的数据格式：</font><font lang=ZH-CN face=宋体 color=#0000ff>
        <p align=justify>pEnumFmt-&gt;Reset (); </p>
        <p align=justify>HRESULT Ret=S_OK</p>
        <p align=justify>while(Ret!=S_OK)</p>
        <dir>
        <dir>
        <p align=justify>{</p>
        </dir></dir></font><font color=#0000ff>
        <p align=justify>Ret</p>
        </font><strong>=</strong><font color=#0000ff>pEnumFmt-&gt;Next(1,&amp;cFmt,&amp;Fetched);
        <p align=justify>if(SUCCEEDED(ret))</p>
        <p align=justify>if( cFmt.cfFormat == CF_TEXT</p>
        <p align=justify>||cFmt.cfFormat == CF_HDROP)</p>
        <p align=justify>{</p>
        <p align=justify></p>
        <p align=justify>if(GetDragData(pDataObject,cFmt)) </p>
        <p align=justify>EnterResult = true;</p>
        <p align=justify>}</p>
        <p align=justify>}</p>
        </font><font lang=ZH-CN face=宋体>
        <p align=justify>第一个参数表示一次获取的</p>
        </font><font face="宋体, MS Song">FORMATETC</font><font lang=ZH-CN face=宋体>结构数据的数量，</font><font face="宋体, MS Song">cFmt</font><font lang=ZH-CN face=宋体>是一个</font><font face="宋体, MS Song">FORMATETC</font><font lang=ZH-CN face=宋体>指针，指向一个数据缓冲，用来返回</font><font face="宋体, MS Song">FORMATETC</font><font lang=ZH-CN face=宋体>数据。</font><font face="宋体, MS Song">,Fetched</font><font lang=ZH-CN face=宋体>是</font><font face="宋体, MS Song">Next</font><font lang=ZH-CN face=宋体>调用后得到的</font><font face="宋体, MS Song">FORMATETC</font><font lang=ZH-CN face=宋体>数据个数。一般一次获取一个，直到Next返回不为S_OK。
        <p align=justify>我们可以对每个得到</p>
        </font><font face="宋体, MS Song">cFmt</font><font lang=ZH-CN face=宋体>调用</font><font face="宋体, MS Song">IDataObject-&gt;GetData</font><font lang=ZH-CN face=宋体>方法，但是一般来说，一个数据对象包含的数据不止一种，而且一般有一些自定义的数据类型（关于自定义数据类型，参见：</font><strong><font face="宋体, MS Song">RegisterClipboardFormat</font></strong><font lang=ZH-CN face=宋体>，如果要自己实现</font><font face="宋体, MS Song">Drag/Drop</font><font lang=ZH-CN face=宋体>源数据，这个函数是有用的），对此我们不感兴趣，因为这里只要求处理文本和文件的拖动，为此，只处理</font><font face="宋体, MS Song">cfFormat</font><font lang=ZH-CN face=宋体>为</font><font face="宋体, MS Song">CF_TEXT</font><font lang=ZH-CN face=宋体>和</font><font face="宋体, MS Song">CF_HROP</font><font lang=ZH-CN face=宋体>的数据：</font><strong>
        <p align=justify>GetDragData</p>
        </strong><font lang=ZH-CN face=宋体>为</font>CDropTargetEx<font lang=ZH-CN face=宋体>类的一个成员函数：</font><strong>
        <p align=justify>///////////////////////////////////////////////////</p>
        </strong><font color=#0000ff>
        <p align=justify>//Get The DragData from IDataObject ,save in HANDEL</p>
        <p align=justify>BOOL CDropTargetEx::GetDragData(IDataObject *pDataObject,FORMATETC cFmt)</p>
        <p align=justify>{</p>
        <p align=justify>HRESULT ret=S_OK;</p>
        <p align=justify>STGMEDIUM stgMedium;</p>
        <p align=justify>ret = pDataObject-&gt;GetData(&amp;cFmt, &amp;stgMedium);//GetData(CF_TEXT, &amp;stgMedium);</p>
        <p align=justify>if (FAILED(ret))</p>
        <p align=justify>{</p>
        <p align=justify>return FALSE;</p>
        <p align=justify>}</p>
        <p align=justify></p>
        <p align=justify>if (stgMedium.pUnkForRelease != NULL)</p>
        <p align=justify>{</p>
        <p align=justify>return FALSE;</p>
        <p align=justify>}</p>
        <p align=justify>///////////////////////////////////////////</p>
        <p align=justify>switch (stgMedium.tymed)</p>
        <p align=justify>{</p>
        <p align=justify>case TYMED_HGLOBAL:</p>
        <p align=justify>{</p>
        <p align=justify>LPDRAGDATA pData = new DRAGDATA;</p>
        <p align=justify>pData-&gt;cfFormat = cFmt.cfFormat ;</p>
        <p align=justify>memcpy(&amp;pData-&gt;stgMedium,&amp;stgMedium,sizeof(STGMEDIUM));</p>
        <p align=justify>m_Array.push_back(pData);</p>
        <p align=justify>return true;</p>
        <p align=justify>break;</p>
        <p align=justify>}</p>
        <p align=justify>default:</p>
        <p align=justify>// type not supported, so return error</p>
        <p align=justify>{</p>
        <p align=justify>::ReleaseStgMedium(&amp;stgMedium);</p>
        <p align=justify>}</p>
        <p align=justify>break;</p>
        <p align=justify>}</p>
        <p align=justify>return false;</p>
        <p align=justify>}</p>
        </font><font lang=ZH-CN face=宋体>
        <p align=justify>在这个成员函数里，根据</p>
        </font><font face="宋体, MS Song">cFmt</font><font lang=ZH-CN face=宋体>，调用</font><font face="宋体, MS Song">IDataObject-&gt;GetData</font><font lang=ZH-CN face=宋体>函数获得数据（对于</font><font face="宋体, MS Song">CF_TEXT</font><font lang=ZH-CN face=宋体>和</font><font face="宋体, MS Song">CF_HROP</font><font lang=ZH-CN face=宋体>来说，数据的媒介载体</font><font face="宋体, MS Song">tymed</font><font lang=ZH-CN face=宋体>都是</font><strong><font face="宋体, MS Song">HGLOBAL</font></strong><font lang=ZH-CN face=宋体>类型的）。
        <p align=justify>在具体实现的时候，我定义了一个结构：</p>
        </font><font color=#0000ff>
        <p align=justify>typedef struct _DRAGDATA</p>
        <p align=justify>{</p>
        <dir>
        <dir>
        <p align=justify>int cfFormat;</p>
        </dir></dir></font><font lang=ZH-CN face=宋体 color=#0000ff>
        <p align=justify></p>
        </font><font color=#0000ff><font face="宋体, MS Song">STGMEDIUM stgMedium;</font>
        <p align=justify>}DRAGDATA,*LPDRAGDATA;</p>
        </font><font lang=ZH-CN face=宋体>
        <p align=justify>　</p>
        <p align=justify>将</p>
        </font><strong><font face="宋体, MS Song">STGMEDIUM</font></strong><font lang=ZH-CN face=宋体>和数据类型（比如</font><font face="宋体, MS Song">CF_TEXT,</font><font lang=ZH-CN face=宋体>记录在</font><font face="宋体, MS Song">cfFormat</font><font lang=ZH-CN face=宋体>）都记录在DRAGDATA里。并且使用了一个</font><font face="宋体, MS Song">vector</font><font lang=ZH-CN face=宋体>数组，将这个结构保存在数组里。对于不是我们想要的</font><font face="宋体, MS Song">STGMEDIUM</font><font lang=ZH-CN face=宋体>数据，我们马上调用</font><font face="宋体, MS Song">ReleaseStgMedium</font><font lang=ZH-CN face=宋体>函数进行释放，免得造成内存泄露。
        <p align=justify>这样，</p>
        </font><font face="宋体, MS Song">DragEnter</font><font lang=ZH-CN face=宋体>的工作就基本完成了，最后需要做的就是给</font><font face="宋体, MS Song">DoDragDrop</font><font lang=ZH-CN face=宋体>返回相应的状态：如果我们获得了想要的数据就给</font><font face="宋体, MS Song">* pdwEffect</font><font lang=ZH-CN face=宋体>赋值为</font><strong><font face="宋体, MS Song">DROPEFFECT_COPY</font></strong><font lang=ZH-CN face=宋体>，否则，就是</font><strong><font face="宋体, MS Song">DROPEFFECT_NONE</font></strong><font lang=ZH-CN face=宋体>；
        <p align=justify>如果支持拖放，鼠标形状将变成一个有接受意义的图标，否则，是一个拒绝意义的图标。</p>
        </font><font lang=ZH-CN face=宋体 size=3>
        <p>&#160;</p>
        <hr>
        <p>&#160;</p>
        <ul></ul>
            </font><strong><font color=#ff0000 size=4>
            <p align=justify></p>
            <li>DragOver
            <p>&#160;</p>
            </font></strong><font lang=ZH-CN face=宋体>
            <p align=justify>鼠标拖动对象进入窗口之后，将会在窗口范围内移动，这时</p>
            </font><font face="宋体, MS Song">DoDragDrop</font><font lang=ZH-CN face=宋体>就会调用</font><font face="宋体, MS Song">IDropTarget</font><font lang=ZH-CN face=宋体>的</font><font face="宋体, MS Song">DragOver</font><font lang=ZH-CN face=宋体>接口。其原形为：</font><font color=#0000ff>
            <p align=justify>HRESULT DragOver(</p>
            <p align=justify>DWORD grfKeyState</p>
            <p align=justify>POINTL pt, </p>
            </font><font lang=ZH-CN face=宋体 color=#0000ff>
            <p align=justify></p>
            </font><font color=#0000ff><font face="宋体, MS Song">DWORD * pdwEffect </font></font><font lang=ZH-CN color=#0000ff>
            <p align=justify></p>
            </font><font color=#0000ff><font face="宋体, MS Song">)</font></font><font lang=ZH-CN face=宋体>
            <p align=justify>相对来说对于这个接口方法的实现可以简单的多：只要根据</p>
            </font><font face="宋体, MS Song">grfKeyState</font><font lang=ZH-CN face=宋体>判断键盘和鼠标的状态是否符合要求，根据</font><font face="宋体, MS Song">pt</font><font lang=ZH-CN face=宋体>传入的鼠标点判断该点是否支持拖放（比如将拖放区域限制在窗口的一部分的话），然后为</font><strong><font face="宋体, MS Song">*pdwEffect</font></strong><font lang=ZH-CN face=宋体>赋值为</font><strong><font face="宋体, MS Song">DROPEFFECT_COPY</font></strong><font lang=ZH-CN face=宋体>或</font><strong><font face="宋体, MS Song">DROPEFFECT_NONE.</font></strong><font lang=ZH-CN face=宋体>当然，还可以做一些你喜欢的事情，比如把鼠标坐标打印到屏幕上。不过为了性能和安全起见，建议不要做延时明显的操作。</font><font lang=ZH-CN face=宋体 size=3>
            <p>&#160;</p>
            <hr>
            <p>&#160;</p>
            <ul></ul>
                </font><strong><font color=#ff0000 size=4>
                <p align=justify></p>
                <li>DragLeave:
                <p>&#160;</p>
                </font></strong><font lang=ZH-CN face=宋体>
                <p align=justify>这个方法没有传入参数，相当简单。</p>
                <p>当拖动的鼠标离开了窗口区域，这个方法将被调用，你可以在这里写一些清理内存的代码。在</p>
                </font><font face="宋体, MS Song">CDropTargetEx</font><font lang=ZH-CN face=宋体>类里，由于在</font><font face="宋体, MS Song">DragEnter</font><font lang=ZH-CN face=宋体>里</font><font face="宋体, MS Song">new</font><font lang=ZH-CN face=宋体>了一些数据结构，并加到一个指针数组里，所以我必须在这里对此数据进行清理，对此结构里的</font><font face="宋体, MS Song">STDMEDIUM</font><font lang=ZH-CN face=宋体>调用</font><font face="宋体, MS Song">ReleaseStgMedium</font><font lang=ZH-CN face=宋体>然后</font><font face="宋体, MS Song">Delete</font><font lang=ZH-CN face=宋体>该结构。
                <p>另外，如果需要的话，可以通知用户鼠标指针已经离开了拖放区域。</p>
                </font><font lang=ZH-CN face=宋体 size=3>
                <p>&#160;</p>
                <hr>
                <p>&#160;</p>
                <ul></ul>
                    </font><strong><font color=#ff0000 size=4>
                    <li>Drop</font></strong><font lang=ZH-CN face=宋体>
                    <p>如果鼠标没有离开窗口，而是在窗口内释放按纽，那么拖放时间的&#8220;放&#8221;就在这时发生，</p>
                    </font><font face="宋体, MS Song">IDropTarget</font><font lang=ZH-CN face=宋体>接口的</font><font face="宋体, MS Song">Drop</font><font lang=ZH-CN face=宋体>方法被调用。其原形为</font><strong>
                    <p>HRESULT Drop(</p>
                    <p>IDataObject * pDataObject, </p>
                    <font lang=ZH-CN face=宋体>
                    <p>&#160;</p>
                    </font><font face="宋体, MS Song">DWORD grfKeyState, </font>
                    <p>POINTL pt, </p>
                    <font lang=ZH-CN face=宋体>
                    <p>&#160;</p>
                    </font><font face="宋体, MS Song">DWORD * pdwEffect </font><font lang=ZH-CN>
                    <p>&#160;</p>
                    </font><font face="宋体, MS Song">)</font></strong><font lang=ZH-CN face=宋体>
                    <p>有些资料建议在这里才调用</p>
                    </font><strong><font face="宋体, MS Song">pDataObject-&gt;GetData</font></strong><font lang=ZH-CN face=宋体>方法获取数据，在</font><font face="宋体, MS Song">CDropTargetEx</font><font lang=ZH-CN face=宋体>类里，数据实际上已经在</font><strong><font face="宋体, MS Song">DragEnter</font></strong><font lang=ZH-CN face=宋体>里获取了。这样做的理由是我希望一开始就获得数据，从它本身进行判断是否支持拖放</font><font face="宋体, MS Song">,</font><font lang=ZH-CN face=宋体>而不是在&#8220;放&#8221;的时候才判断是否合法数据。
                    <p>既然数据已经获得，那么我就可以从保存数据的指针数组里提取出</p>
                    </font><strong><font face="宋体, MS Song">STGMEDIUM</font></strong><font lang=ZH-CN face=宋体>数据来，并根据数据的具体格式进行处理（最后一定要记住对</font><font face="宋体, MS Song">STGMEDIUM</font><font lang=ZH-CN face=宋体>进行</font><strong><font face="宋体, MS Song">ReleaseStgMedium</font></strong><font lang=ZH-CN face=宋体>）
                    <p>对于</p>
                    </font><font face="宋体, MS Song">CF_TEXT</font><font lang=ZH-CN face=宋体>类型的数据，</font><font face="宋体, MS Song">STGMEDIUM</font><font lang=ZH-CN face=宋体>的成员</font><font face="宋体, MS Song">hGlobal</font><font lang=ZH-CN face=宋体>里包含的是一段全局内存数据。获取这些数据的方法是：
                    <dir>
                    <dir></dir></dir></font><font color=#0000ff>
                    <p>TCHAR *pBuff = NULL;</p>
                    <p>pBuff=(LPSTR)GlobalLock(hText);</p>
                    <p>GlobalUnlock(hText);</p>
                    </font><font lang=ZH-CN face=宋体>
                    <p>则得到一个指向内存数据的指针pBuff。在我这个例子里一般是一段</p>
                    </font><font face="宋体, MS Song">"\0"</font><font lang=ZH-CN face=宋体>结尾的文本字符串。这样就实现了文本的拖放。
                    <p>对于</p>
                    </font><font face="宋体, MS Song">CF_HDROP</font><font lang=ZH-CN face=宋体>类型的数据，</font><font face="宋体, MS Song">STGMEDIUM</font><font lang=ZH-CN face=宋体>成员</font><font face="宋体, MS Song">hGlobal</font><font lang=ZH-CN face=宋体>是一个</font><font face="宋体, MS Song">HDROP</font><font lang=ZH-CN face=宋体>类型的句柄。通过这个句柄，可以获得拖放的文件列表。如：</font><font color=#0000ff>
                    <p>BOOL CDropTargetEx::ProcessDrop(HDROP hDrop)</p>
                    <p>{</p>
                    <p>UINT iFiles,ich =0;</p>
                    <p>TCHAR Buffer[MAX_PATH]="";</p>
                    <p>memset(&amp;iFiles,0xff,sizeof(iFiles));</p>
                    <dir>
                    <dir>
                    <p>int Count = ::DragQueryFile(hDrop,iFiles,Buffer,0); //Get the Drag _Files Number.</p>
                    </dir></dir></font><font lang=ZH-CN face=宋体 color=#0000ff>
                    <p>&#160;</p>
                    </font><font color=#0000ff><font face="宋体, MS Song">if(Count)</font>
                    <p>for (int i=0;i&lt;Count;i++)</p>
                    <p>{</p>
                    <p>if(::DragQueryFile(hDrop,i,Buffer,sizeof(Buffer)))</p>
                    <p>{</p>
                    <dir>
                    <dir>
                    <dir>
                    <dir>
                    <dir>
                    <dir>
                    <dir>
                    <dir>
                    <p>//Got the FileName in Buffer</p>
                    </dir></dir></dir></dir></dir></dir></dir></dir></font><font lang=ZH-CN face=宋体 color=#0000ff>
                    <p>}</p>
                    <p>}</p>
                    <p>&#160;</p>
                    </font><font color=#0000ff><font face="宋体, MS Song">::DragFinish(hDrop);</font>
                    <dir>
                    <dir>
                    <p>return true; </p>
                    </dir></dir></font><font lang=ZH-CN face=宋体 color=#0000ff>
                    <p>}</p>
                    </font><font lang=ZH-CN face=宋体>
                    <p>获得的</p>
                    </font><font face="宋体, MS Song">Buffer</font><font lang=ZH-CN face=宋体>是就是拖放的文件名，如果拖放的是多个文件，在</font><font face="宋体, MS Song">for</font><font lang=ZH-CN face=宋体>循环里可以依次获取这些文件的文件名。这样就实现了文件的拖放。</font><font lang=ZH-CN face=宋体 size=3>
                    <p>&#160;</p>
                    <hr>
                    <p>&#160;</p>
                    </font><font lang=ZH-CN face=宋体>
                    <p align=justify>　</p>
                    </font><strong>
                    <p align=justify>CDropTargetEx</p>
                    </strong><font lang=ZH-CN face=宋体>类使用非常简单:
                    <p align=justify>在客户窗口的相关文件中，定义一个</p>
                    </font><font face="宋体, MS Song">CDropTargetEx</font><font lang=ZH-CN face=宋体>实例：</font><strong><font face="宋体, MS Song">CDropTargetEx DropTarget;</font></strong><font lang=ZH-CN face=宋体>
                    <p align=justify>在窗口创建之后，将窗口句柄进行拖放注册： </p>
                    </font><strong>
                    <p align=justify>DropTarget.DragDropRegister(hWnd);</p>
                    </strong><font lang=ZH-CN face=宋体>
                    <p align=justify>或者 </p>
                    </font><strong>
                    <p align=justify>DropTarget.DragDropRegister(hWnd<font lang=ZH-CN face=宋体>，</font>MK_CONTROL|MK_LBUTTON);</p>
                    </strong><font lang=ZH-CN face=宋体>
                    <p align=justify>表示鼠标左键按下并且按住</p>
                    </font><font face="宋体, MS Song">Ctrl</font><font lang=ZH-CN face=宋体>键的拖放有效</font><font face="宋体, MS Song">;</font><font lang=ZH-CN face=宋体>
                    <p align=justify>对于获取拖放的结果，我使用的是回调函数方式：</p>
                    <p align=justify>回调原形</p>
                    </font><strong><font face="宋体, MS Song">typedef VOID (_stdcall *DROPCALLBACK)(LPCSTR Buffer,int type);</font></strong><font lang=ZH-CN face=宋体>
                    <p align=justify>在适当的地方（比如窗口的实现</p>
                    </font><font face="宋体, MS Song">CPP</font><font lang=ZH-CN face=宋体>里）定义函数</font><font face="宋体, MS Song">DropCallback</font><font lang=ZH-CN face=宋体>：</font><strong>
                    <p align=justify>void _stdcall DropCallBack(LPCSTR Buffer,int type)</p>
                    </strong><font lang=ZH-CN face=宋体>
                    <p align=justify>并且将其地址赋于</p>
                    </font><font face="宋体, MS Song">DropTarget</font><font lang=ZH-CN face=宋体>实例：</font><strong>
                    <p align=justify>DropTarget.SetCallBack(DropCallBack);</p>
                    </strong><font lang=ZH-CN face=宋体>
                    <p align=justify>这样，拖放文本到客户窗口，回调函数将被调用，参数</p>
                    </font><strong><font face="宋体, MS Song">Buffer</font></strong><font lang=ZH-CN face=宋体>为拖放的文本，</font><strong><font face="宋体, MS Song">format</font></strong><font lang=ZH-CN face=宋体>为</font><font face="宋体, MS Song">CF_TEXT</font><font lang=ZH-CN face=宋体>。而拖放文件的时候，对每个被拖放的文件都调用一次回调函数，参数</font><strong><font face="宋体, MS Song">Buffer</font></strong><font lang=ZH-CN face=宋体>为文件全路径名，</font><strong><font face="宋体, MS Song">format</font></strong><font lang=ZH-CN face=宋体>为</font><strong><font face="宋体, MS Song">CF_HDROP</font></strong><font lang=ZH-CN face=宋体>。
                    <p align=justify>示例的</p>
                    </font><font face="宋体, MS Song">DropCallBack</font><font lang=ZH-CN face=宋体>代码为：</font><font color=#0000ff>
                    <p align=justify>void _stdcall DropCallBack(LPCSTR Buffer,int format)</p>
                    <p align=justify>{</p>
                    <p align=justify>switch(format)</p>
                    <p align=justify>{</p>
                    <p align=justify>case CF_TEXT:</p>
                    <p align=justify>{</p>
                    <p align=justify>SetWindowText(hEdit,Buffer);</p>
                    <p align=justify>break;</p>
                    <p align=justify>}</p>
                    <p align=justify>case CF_HDROP:</p>
                    <p align=justify>{</p>
                    <p align=justify>TCHAR Buf[2048]="";</p>
                    <p align=justify>sprintf(Buf,"File : &lt;%s&gt; is Drag and Drop to this Windows ,Open it?",Buffer);</p>
                    <p align=justify>if(MessageBox(hMainWnd,Buf,"Question",MB_YESNO)==IDYES)</p>
                    <p align=justify>{</p>
                    <p align=justify>ShellExecute(0,"open",Buffer,"","",SW_SHOW);</p>
                    <p align=justify>}</p>
                    <p align=justify>}</p>
                    <p align=justify>default:</p>
                    <dir>
                    <dir>
                    <dir>
                    <dir>
                    <p align=justify>break;</p>
                    </dir></dir></dir></dir></font><font lang=ZH-CN face=宋体 color=#0000ff>
                    <p align=justify>}</p>
                    <p align=justify>}</p>
                    </font><font lang=ZH-CN face=宋体>
                    <p align=justify>　</p>
                    <strong>
                    <p align=justify>总结</p>
                    </strong>：使用</font><font face="宋体, MS Song">IDropTarget</font><font lang=ZH-CN face=宋体>实现通用的拖放，只要实现其</font><font face="宋体, MS Song">7</font><font lang=ZH-CN face=宋体>个接口，并且对得到的</font><font face="宋体, MS Song">IDataObject</font><font lang=ZH-CN face=宋体>用正确的格式（</font><font face="宋体, MS Song">FORMATETC</font><font lang=ZH-CN face=宋体>）调用正确的</font><font face="宋体, MS Song">GetData</font><font lang=ZH-CN face=宋体>获取数据，返回</font><strong><font face="宋体, MS Song">DROPEFFECT</font></strong><font lang=ZH-CN face=宋体>决定拖放的特征和结果，并处理拖放结果即可。
                    <p align=justify>要注意的小问题是：</p>
                    <ul>
                        <p align=justify></p>
                        <li>要调用<strong>OleInitialize</strong>而不是CoInitialize或CoInitializeEx对COM进行初始，否则<strong>RegisterDragDrop</strong>将不会成功，返回的错误是E_OUTOFMEMORY--内存不够，无法进行该操作。
                        <p>&#160;</p>
                        <p align=justify></p>
                        <li>调用ReleaseStgMedium释放STGMEDIUM里的数据，而不是直接对其hGlobal成员调用CloseHandle.
                        <p>&#160;</p>
                        <p align=justify></p>
                        <li>拖放操作关系到两个进程的数据交换，会将两个进程都堵塞，直到拖放完成为止，所以，在接管拖放的接口方法中，不要进行过于耗时的运算。
                        <p>&#160;</p>
                        </li>
                    </ul>
                    <p align=justify>这个例子相当简单，还可以简化，比如取消</p>
                    </font><font face="宋体, MS Song">vector,</font><font lang=ZH-CN face=宋体>将获得</font><font face="宋体, MS Song">HGLOBAL</font><font lang=ZH-CN face=宋体>句柄作为成员变量存储，或者将获取数据的操作全部放到</font><font face="宋体, MS Song">Drop</font><font lang=ZH-CN face=宋体>方法里。
                    <p align=justify>对于拖放文件，还有一个更简单的方法：响应</p>
                    </font><font face="宋体, MS Song"><strong>WM_DROPFILES</strong></font><font lang=ZH-CN face=宋体>消息。步骤是：
                    <ul>
                        <p align=justify></p>
                        <li>对客户窗口调用</li>
                    </ul>
                    </font><font face="宋体, MS Song"><strong>DropAccepFiles</strong>,</font><font lang=ZH-CN face=宋体>使该窗口可以接受文件拖放。
                    <p>&#160;</p>
                    <p align=justify></p>
                    <li>响应</font><font face="宋体, MS Song">WM_DROPFILES</font><font lang=ZH-CN face=宋体>消息，其</font><font face="宋体, MS Song">wParam</font><font lang=ZH-CN face=宋体>就是</font><font face="宋体, MS Song">HDROP</font><font lang=ZH-CN face=宋体>句柄
                    <p>&#160;</p>
                    <p align=justify></p>
                    <li>对此句柄调用</font><font face="宋体, MS Song">DropQueryFiles</font><font lang=ZH-CN face=宋体>获取拖放文件列表并结束拖放，参见上面关于</font><strong><font face="宋体, MS Song">ProcessDrop</font></strong><font lang=ZH-CN face=宋体>的代码
                    <p>&#160;</p>
                    <p align=justify>对于拖放的全面阐述，请参见</p>
                    </font><strong><font face="宋体, MS Song">MSDN-&gt;PlatformSDK Document-&gt;User Interface Services-&gt;Windows Shell</font></strong><font lang=ZH-CN face=宋体>里关于<strong>&#8220;</strong></font><font face="宋体, MS Song">Transferring Shell Objects with Drag-and-Drop and the Clipboard</font><font lang=ZH-CN face=宋体>&#8221;一章。</font><font face="宋体, MS Song">Windows Shell</font><font lang=ZH-CN face=宋体>系统提供了很多接口，让用户利用和扩充这些接口，很方便的开发和使用丰富的</font><font face="宋体, MS Song">shell</font><font lang=ZH-CN face=宋体>服务，确实是一种很聪明的设计。
                    <dir>
                    <p align=justify>　</p>
                    <p align=justify></p>
                    </dir><strong>
                    <p align=justify>附</p>
                    </strong></font><a href="http://www.mapinfo.com.cn/upload/downfile.asp?fileid=61"><strong><u><font lang=ZH-CN face=宋体 color=#0000ff size=3>例子和代码</font></u></strong></a> </li>
<img src ="http://www.cppblog.com/andxie99/aggbug/19228.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2007-03-05 12:52 <a href="http://www.cppblog.com/andxie99/archive/2007/03/05/19228.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从MFC与ATL的男女关系说起</title><link>http://www.cppblog.com/andxie99/archive/2006/11/16/15196.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Thu, 16 Nov 2006 01:15:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/11/16/15196.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/15196.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/11/16/15196.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/15196.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/15196.html</trackback:ping><description><![CDATA[
		<div class="arcTitle">
				<h3>
						<a href="http://tech.163.com/06/0704/11/2L6CBCLN00091LRC.html#" target="_blank">
						</a> </h3>
		</div>
		<div id="endText">
				<p style="TEXT-INDENT: 2em">
				</p>
				<p style="TEXT-INDENT: 2em">
						<strong>
						</strong>
				</p>如果从哲学的观点来看，这大概要说是一种辩证关系了!<p style="TEXT-INDENT: 2em">首先谈谈男人。男人与男孩的区别在于责任，对于一个男人来说，他的肩膀永远有负担，他要解决生活中遇到的所有问题，可以为妻儿带来幸福生活，可以赡养父母，可以做一些成就来创一番事业。所以男人不要轻生，因为你垮下就意味着你的负担没有了支撑，也就是你不负责任。男人的这种责任体现了一种刚性，打不倒压不垮，坎坎坷坷一路走来即使没有扬名立万但是肩膀上的负担始终没有落下。铮铮铁骨、铁血男儿、阳刚之美都是对男人的赞美，一个家庭男人是顶梁柱，这就是责任。</p><p style="TEXT-INDENT: 2em">再谈谈女人。女人与女孩的区别在于柔情，少了撒娇和任性，多了体贴和温柔。女人是生活的调剂品，少了她尽管可以填抱肚皮、补充营养但食之无味。女人天生就是善于交际的，这本身体现的就是一种柔性，就像太极一样，以柔克刚，借助刚性体现柔美。</p><p style="TEXT-INDENT: 2em">用建筑来形容男女关系，男人就像钢筋水泥搭建起来的框架承受着外力，女人则是对框架填补装修使其美观，不同的男人有着不同的建筑风格，不同的女人可以使建筑呈现不同的美。成功的男人背后都有一个女人，钢筋水泥加上精心装饰让人体会到设计之美，至于谁重要次要，谁表谁里都不是关键，关键的是刚柔的结合。</p><p style="TEXT-INDENT: 2em">MFC</p><p style="TEXT-INDENT: 2em">MFC是一个男人，从Microsoft C/C++ version 7.0到Visual Stduio.net 2005一直承担着软件框架设计的角色，风风雨雨路不回头，屹立在软件设计大道，为开发者提供便利，著名的BCG库和XTREME库都是在MFC源码基础上的改进。它大而繁杂，曲折通幽，粗旷豪放。它必须承担责任，提供软件设计的一套解决方案，而且背负着历史包袱，所以难免带有一些成熟男人的深邃而不被人理解。如果你还一味的去批判它，那只能说你不懂男人的心，不理解一个男人难言之苦。 ATL</p><p style="TEXT-INDENT: 2em">ATL是一个女人，小巧灵活讨人喜爱，它作为COM思想的实现而拿出来解决软件协作的问题。它可以不具体实现功能而只留出一些接口，接口两端相通并且随时拔插，多么完美一个女人!为一个C++对象配备一个ATL对象你可以想象有什么结果嘛?</p><p style="TEXT-INDENT: 2em">软件设计中的MFC与ATL</p><p style="TEXT-INDENT: 2em">以前我一直以为ATL就是做控件、构造插件接口体系的，而MFC就是用来做界面功能。它们属于不同体系，在功能级别上存在差异，所以只是在纵向上结合而没有尝试横向的结合。人类社会是自然的，软件社会也应该是自然的。自然代表一种随和，亲近，协调。</p><p style="TEXT-INDENT: 2em">提到MFC，八九不离十就涉及到软件界面开发。目前来说软件复用需求越来越高，而软件功能的不确定因素越来越大，一个特定的界面行为可能不确定。MFC是一个男人，用它可以做任何想做的界面，这就是它的刚性。但是我们到底是要去做什么还是告诉别人我们可以做什么呢?如果我们一味的做，那我们充其量只是一个莽夫，是吕布有勇无谋。我告诉你我有一个MFC对象，还告诉你它可以做什么，这样不就够了。</p><p style="TEXT-INDENT: 2em">MFC是男人天生缺乏沟通能力，所以无法告知外界它自身的行为，只有它自己知道。这时候就需要一个管子插到对象内部去了解它，而ATL刚好提供了一个接口，将其一段插入MFC对象内部而露出另一端以便告知外界MFC对象内部的行为。这样的界面是可解释的界面，它具有做事情的能力，但是它不去做，而成为可复用界面。</p></div>
<img src ="http://www.cppblog.com/andxie99/aggbug/15196.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-11-16 09:15 <a href="http://www.cppblog.com/andxie99/archive/2006/11/16/15196.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sizeof终极无惑</title><link>http://www.cppblog.com/andxie99/archive/2006/10/26/14230.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Thu, 26 Oct 2006 03:59:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/10/26/14230.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/14230.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/10/26/14230.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/14230.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/14230.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">1. 定义：<br />sizeof是C/C++中的一个操作符（operator），简单的说其作用就是返回一个对象或者类型所占的内存字节数。<br />MSDN上的解释为：<br />The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). <br />This keyword returns a value of type size_t.<br />其返回值类型为size_t，在头文件stddef.h中定义。这是一个依赖于编译系统的值，一般定义为<br />typedef unsigned int size_t;<br />世上编译器林林总总，但作为一个规范，它们都会保证char、signed char和unsigned char的sizeof值为1，毕竟char是我们编程能用的最小数据类型。 </font>
		</p>
		<p>
				<font size="2">
				</font> </p>
		<p>
				<font size="2">2. 语法：<br />sizeof有三种语法形式，如下：<br />1) sizeof( object ); // sizeof( 对象 );<br />2) sizeof( type_name ); // sizeof( 类型 );<br />3) sizeof object; // sizeof 对象;<br />所以，<br />int i;<br />sizeof( i ); // ok<br />sizeof i; // ok<br />sizeof( int ); // ok<br />sizeof int; // error<br />既然写法3可以用写法1代替，为求形式统一以及减少我们大脑的负担，第3种写法，忘掉它吧！<br />实际上，sizeof计算对象的大小也是转换成对对象类型的计算，也就是说，同种类型的不同对象其sizeof值都是一致的。这里，对象可以进一步延伸至表达式，即sizeof可以对一个表达式求值，编译器根据表达式的最终结果类型来确定大小，一般不会对表达式进行计算。如：<br />sizeof( 2 );// 2的类型为int，所以等价于 sizeof( int );<br />sizeof( 2 + 3.14 ); // 3.14的类型为double，2也会被提升成double类型，所以等价于 sizeof( double );<br />sizeof也可以对一个函数调用求值，其结果是函数返回类型的大小，函数并不会被调用，我们来看一个完整的例子：<br />char foo()<br />{<br /> printf("foo() has been called.\n");<br />    return 'a';<br />}<br />int main()<br />{<br />size_t sz = sizeof( foo() ); // foo() 的返回值类型为char，所以sz = sizeof( char )，foo()并不会被调用<br />printf("sizeof( foo() ) = %d\n", sz); <br />}<br />C99标准规定，函数、不能确定类型的表达式以及位域（bit-field）成员不能被计算sizeof值，即下面这些写法都是错误的：<br />sizeof( foo );// error</font>
		</p>
		<p>
				<font size="2">void foo2() { }<br />sizeof( foo2() );// error</font>
		</p>
		<p>
				<font size="2">struct S<br />{<br />unsigned int f1 : 1;<br />unsigned int f2 : 5;<br />unsigned int f3 : 12;<br />};<br />sizeof( S.f1 );// error</font>
		</p>
		<p>
				<br />
				<font size="2">3. sizeof的常量性<br />sizeof的计算发生在编译时刻，所以它可以被当作常量表达式使用，如：<br />char ary[ sizeof( int ) * 10 ]; // ok<br />最新的C99标准规定sizeof也可以在运行时刻进行计算，如下面的程序在Dev-C++中可以正确执行：<br />int n;<br />n = 10; // n动态赋值<br />char ary[n]; // C99也支持数组的动态定义<br />printf("%d\n", sizeof(ary)); // ok. 输出10<br />但在没有完全实现C99标准的编译器中就行不通了，上面的代码在VC6中就通不过编译。所以我们最好还是认为sizeof是在编译期执行的，这样不会带来错误，让程序的可移植性强些。</font>
		</p>
		<p>
				<br />
				<font size="2">4. 基本数据类型的sizeof<br />这里的基本数据类型指short、int、long、float、double这样的简单内置数据类型，由于它们都是和系统相关的，所以在不同的系统下取值可能不同，这务必引起我们的注意，尽量不要在这方面给自己程序的移植造成麻烦。<br />一般的，在32位编译环境中，sizeof(int)的取值为4。</font>
		</p>
		<p>
				<br />
				<font size="2">5. 指针变量的sizeof<br />学过数据结构的你应该知道指针是一个很重要的概念，它记录了另一个对象的地址。既然是来存放地址的，那么它当然等于计算机内部地址总线的宽度。所以在32位计算机中，一个指针变量的返回值必定是4（注意结果是以字节为单位），可以预计，在将来的64位系统中指针变量的sizeof结果为8。<br />char* pc = "abc";<br />int* pi;<br />string* ps;<br />char** ppc = &amp;pc;<br />void (*pf)();// 函数指针<br />sizeof( pc ); // 结果为4<br />sizeof( pi ); // 结果为4<br />sizeof( ps ); // 结果为4<br />sizeof( ppc ); // 结果为4<br />sizeof( pf );// 结果为4<br />指针变量的sizeof值与指针所指的对象没有任何关系，正是由于所有的指针变量所占内存大小相等，所以MFC消息处理函数使用两个参数WPARAM、LPARAM就能传递各种复杂的消息结构（使用指向结构体的指针）。</font>
		</p>
		<p>
				<br />
				<font size="2">6. 数组的sizeof<br />数组的sizeof值等于数组所占用的内存字节数，如：<br />char a1[] = "abc";<br />int a2[3];<br />sizeof( a1 ); // 结果为4，字符串末尾还存在一个NULL终止符<br />sizeof( a2 ); // 结果为3*4=12（依赖于int）<br />一些朋友刚开始时把sizeof当作了求数组元素的个数，现在，你应该知道这是不对的，那么应该怎么求数组元素的个数呢？Easy，通常有下面两种写法：<br />int c1 = sizeof( a1 ) / sizeof( char ); // 总长度/单个元素的长度<br />int c2 = sizeof( a1 ) / sizeof( a1[0] ); // 总长度/第一个元素的长度<br />写到这里，提一问，下面的c3，c4值应该是多少呢？<br />void foo3(char a3[3])<br />{<br />int c3 = sizeof( a3 ); // c3 == ?<br />}<br />void foo4(char a4[])<br />{<br />int c4 = sizeof( a4 ); // c4 == ?<br />}也许当你试图回答c4的值时已经意识到c3答错了，是的，c3!=3。这里函数参数a3已不再是数组类型，而是蜕变成指针，相当于char* a3，为什么？仔细想想就不难明白，我们调用函数foo1时，程序会在栈上分配一个大小为3的数组吗？不会！数组是“传址”的，调用者只需将实参的地址传递过去，所以a3自然为指针类型（char*），c3的值也就为4。</font>
		</p>
		<p>
				<font size="2">7. 结构体的sizeof<br />这是初学者问得最多的一个问题，所以这里有必要多费点笔墨。让我们先看一个结构体：<br />struct S1<br />{<br />char c;<br />int i;<br />};<br />问sizeof(s1)等于多少？聪明的你开始思考了，char占1个字节，int占4个字节，那么加起来就应该是5。是这样吗？你在你机器上试过了吗？也许你是对的，但很可能你是错的！VC6中按默认设置得到的结果为8。<br />Why？为什么受伤的总是我？<br />请不要沮丧，我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数，好吧，那就让我们来看看S1的内存分配情况：<br />S1 s1 = { 'a', 0xFFFFFFFF };<br />定义上面的变量后，加上断点，运行程序，观察s1所在的内存，你发现了什么？<br />以我的VC6.0为例，s1的地址为0x0012FF78，其数据内容如下：<br />0012FF78:? 61 CC CC CC FF FF FF FF<br />发现了什么？怎么中间夹杂了3个字节的CC？看看MSDN上的说明：<br />When applied to a structure type or variable, sizeof returns the actual size, which may include padding bytes inserted for alignment.<br />原来如此，这就是传说中的字节对齐啊！一个重要的话题出现了。<br />为什么需要字节对齐？计算机组成原理教导我们这样有助于加快计算机的取数速度，否则就得多花指令周期了。为此，编译器默认会对结构体进行处理（实际上其它地方的数据变量也是如此），让宽度为2的基本数据类型（short等）都位于能被2整除的地址上，让宽度为4的基本数据类型（int等）都位于能被4整除的地址上，以此类推。这样，两个数中间就可能需要加入填充字节，所以整个结构体的sizeof值就增长了。<br />让我们交换一下S1中char与int的位置：<br />struct S2<br />{<br />int i;<br />char c;<br />};<br />看看sizeof(S2)的结果为多少，怎么还是8？再看看内存，原来成员c后面仍然有3个填充字节，这又是为什么啊？别着急，下面总结规律。<br /><br />字节对齐的细节和编译器实现相关，但一般而言，满足三个准则：<br />1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除；<br />2) 结构体每个成员相对于结构体首地址的偏移量（offset）都是成员大小的整数倍，如有需要编译器会在成员之间加上填充字节（internal adding）；<br />3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍，如有需要编译器会在最末一个成员之后加上填充字节（trailing padding）。<br />对于上面的准则，有几点需要说明：<br />1) 前面不是说结构体成员的地址是其大小的整数倍，怎么又说到偏移量了呢？因为有了第1点存在，所以我们就可以只考虑成员的偏移量，这样思考起来简单。想想为什么。<br />结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得，这个宏也在stddef.h中定义，如下：<br />#define offsetof(s,m)?? (size_t)&amp;(((s *)0)-&gt;m)<br />例如，想要获得S2中c的偏移量，方法为<br />size_t pos = offsetof(S2, c);// pos等于4<br />2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型，这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型，比如另外一个结构体，所以在寻找最宽基本类型成员时，应当包括复合类型成员的子成员，而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。<br />这里叙述起来有点拗口，思考起来也有点挠头，还是让我们看看例子吧（具体数值仍以VC6为例，以后不再说明）：<br />struct S3<br />{<br />char c1;<br />S1 s;<br />char c2<br />};<br />S1的最宽简单成员的类型为int，S3在考虑最宽简单类型成员时是将S1“打散”看的，所以S3的最宽简单类型为int，这样，通过S3定义的变量，其存储空间首地址需要被4整除，整个sizeof(S3)的值也应该被4整除。<br />c1的偏移量为0，s的偏移量呢？这时s是一个整体，它作为结构体变量也满足前面三个准则，所以其大小为8，偏移量为4，c1与s之间便需要3个填充字节，而c2与s之间就不需要了，所以c2的偏移量为12，算上c2的大小为13，13是不能被4整除的，这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。<br />通过上面的叙述，我们可以得到一个公式：<br />结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目，即：<br />sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof( trailing padding )<br /><br />到这里，朋友们应该对结构体的sizeof有了一个全新的认识，但不要高兴得太早，有一个影响sizeof的重要参量还未被提及，那便是编译器的pack指令。它是用来调整结构体对齐方式的，不同编译器名称和用法略有不同，VC6中通过#pragma pack实现，也可以直接修改/Zp编译开关。#pragma pack的基本用法为：#pragma pack( n )，n为字节对齐数，其取值为1、2、4、8、16，默认是8，如果这个值比结构体成员的sizeof值小，那么该成员的偏移量应该以此值为准，即是说，结构体成员的偏移量应该取二者的最小值，公式如下：<br />offsetof( item ) = min( n, sizeof( item ) )<br />再看示例：<br />#pragma pack(push) // 将当前pack设置压栈保存<br />#pragma pack(2)// 必须在结构体定义之前使用<br />struct S1<br />{<br />char c;<br />int i;<br />};<br />struct S3<br />{<br />char c1;<br />S1 s;<br />char c2<br />};<br />#pragma pack(pop) // 恢复先前的pack设置<br />计算sizeof(S1)时，min(2, sizeof(i))的值为2，所以i的偏移量为2，加上sizeof(i)等于6，能够被2整除，所以整个S1的大小为6。<br />同样，对于sizeof(S3)，s的偏移量为2，c2的偏移量为8，加上sizeof(c2)等于9，不能被2整除，添加一个填充字节，所以sizeof(S3)等于10。<br />现在，朋友们可以轻松的出一口气了，:)<br /><br />还有一点要注意，“空结构体”（不含数据成员）的大小不为0，而是1。试想一个“不占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢？于是，“空结构体”变量也得被存储，这样编译器也就只能为其分配一个字节的空间用于占位了。如下：<br />struct S5 { };<br />sizeof( S5 ); // 结果为1<br /></font>
		</p>
		<p>
				<font size="2">8. 含位域结构体的sizeof<br />前面已经说过，位域成员不能单独被取sizeof值，我们这里要讨论的是含有位域的结构体的sizeof，只是考虑到其特殊性而将其专门列了出来。<br />C99规定int、unsigned int和bool可以作为位域类型，但编译器几乎都对此作了扩展，允许其它类型类型的存在。<br />使用位域的主要目的是压缩存储，其大致规则为：<br />1) 如果相邻位域字段的类型相同，且其位宽之和小于类型的sizeof大小，则后面的字段将紧邻前一个字段存储，直到不能容纳为止；<br />2) 如果相邻位域字段的类型相同，但其位宽之和大于类型的sizeof大小，则后面的字段将从新的存储单元开始，其偏移量为其类型大小的整数倍；<br />3) 如果相邻的位域字段的类型不同，则各编译器的具体实现有差异，VC6采取不压缩方式，Dev-C++采取压缩方式；<br />4) 如果位域字段之间穿插着非位域字段，则不进行压缩；<br />5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。<br /><br />还是让我们来看看例子。<br />示例1：<br />struct BF1<br />{<br />char f1 : 3;<br />char f2 : 4;<br />char f3 : 5;<br />};<br />其内存布局为：<br />|_f1__|__f2__|_|____f3___|____|<br />|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|<br /><br />位域类型为char，第1个字节仅能容纳下f1和f2，所以f2被压缩到第1个字节中，而f3只能从下一个字节开始。因此sizeof(BF1)的结果为2。<br />示例2：<br />struct BF2<br />{<br />char f1 : 3;<br />short f2 : 4;<br />char f3 : 5;<br />};<br />由于相邻位域类型不同，在VC6中其sizeof为6，在Dev-C++中为2。<br />示例3：<br />struct BF3<br />{<br />char f1 : 3;<br />char f2;<br />char f3 : 5;<br />};<br />非位域字段穿插在其中，不会产生压缩，在VC6和Dev-C++中得到的大小均为3。<br /></font>
		</p>
		<p>
				<font size="2">9. 联合体的sizeof<br />结构体在内存组织上是顺序式的，联合体则是重叠式，各成员共享一段内存，所以整个联合体的sizeof也就是每个成员sizeof的最大值。结构体的成员也可以是复合类型，这里，复合类型成员是被作为整体考虑的。<br />所以，下面例子中，U的sizeof值等于sizeof(s)。<br />union U<br />{<br />int i;<br />char c;<br />S1 s;<br />};</font>
		</p>
<img src ="http://www.cppblog.com/andxie99/aggbug/14230.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-10-26 11:59 <a href="http://www.cppblog.com/andxie99/archive/2006/10/26/14230.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>重写atoi函数</title><link>http://www.cppblog.com/andxie99/archive/2006/10/24/14092.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Tue, 24 Oct 2006 08:36:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/10/24/14092.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/14092.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/10/24/14092.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/14092.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/14092.html</trackback:ping><description><![CDATA[
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> myatoi(</span>
				<span style="COLOR: #0000ff">char</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">s)  <br /><img id="Codehighlighter1_22_238_Open_Image" onclick="this.style.display='none'; Codehighlighter1_22_238_Open_Text.style.display='none'; Codehighlighter1_22_238_Closed_Image.style.display='inline'; Codehighlighter1_22_238_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_22_238_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_22_238_Closed_Text.style.display='none'; Codehighlighter1_22_238_Open_Image.style.display='inline'; Codehighlighter1_22_238_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_22_238_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_22_238_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> sign, n;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">while</span>
						<span style="COLOR: #000000">(isspace(</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">s)) <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />           </span>
						<span style="COLOR: #000000">++</span>
						<span style="COLOR: #000000">s;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  sign </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">1</span>
						<span style="COLOR: #000000">;<br /><img id="Codehighlighter1_102_152_Open_Image" onclick="this.style.display='none'; Codehighlighter1_102_152_Open_Text.style.display='none'; Codehighlighter1_102_152_Closed_Image.style.display='inline'; Codehighlighter1_102_152_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_102_152_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_102_152_Closed_Text.style.display='none'; Codehighlighter1_102_152_Open_Image.style.display='inline'; Codehighlighter1_102_152_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">switch</span>
						<span style="COLOR: #000000">(</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">s) </span>
						<span id="Codehighlighter1_102_152_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_102_152_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">case</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">'</span>
								<span style="COLOR: #000000">-</span>
								<span style="COLOR: #000000">'</span>
								<span style="COLOR: #000000">: sign </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">-</span>
								<span style="COLOR: #000000">1</span>
								<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">case</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">'</span>
								<span style="COLOR: #000000">+</span>
								<span style="COLOR: #000000">'</span>
								<span style="COLOR: #000000">: </span>
								<span style="COLOR: #000000">++</span>
								<span style="COLOR: #000000">s;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  n </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">while</span>
						<span style="COLOR: #000000">(isdigit(</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">s)) <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />           n </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">10</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">n</span>
						<span style="COLOR: #000000">+</span>
						<span style="COLOR: #000000">(</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">s</span>
						<span style="COLOR: #000000">++</span>
						<span style="COLOR: #000000">)</span>
						<span style="COLOR: #000000">-</span>
						<span style="COLOR: #000000">'</span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">'</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> (sign </span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> n);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
<img src ="http://www.cppblog.com/andxie99/aggbug/14092.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-10-24 16:36 <a href="http://www.cppblog.com/andxie99/archive/2006/10/24/14092.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>不用友元，访问类的私有成员变量的方法</title><link>http://www.cppblog.com/andxie99/archive/2006/10/24/14090.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Tue, 24 Oct 2006 07:22:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/10/24/14090.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/14090.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/10/24/14090.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/14090.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/14090.html</trackback:ping><description><![CDATA[<p><br>&nbsp;&nbsp;&nbsp; 虽然没有现实意义，但对理解C++的对象模型是很有帮助的。<br><br>&nbsp;&nbsp;&nbsp; 前几天，在论坛里看到一个帖子，内容是： &nbsp; <br>&nbsp; （原帖见：http://community.csdn.net/Expert/topic/5014/5014384.xml?temp=.3018152） &nbsp; <br>&nbsp; ======================================== &nbsp; <br>&nbsp; class &nbsp; a &nbsp; <br>&nbsp; { &nbsp; <br>&nbsp; private: &nbsp; <br>&nbsp; int &nbsp; k; &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; 要求不用友元，不在这个类里添加任何代码，去访问成员变量k。 &nbsp; <br>&nbsp; 能做出的高手，请贴出完整源码，以便大家测试。 &nbsp; <br>&nbsp; ======================================== &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 这道题目本身所要解决的问题并没有多少现实意义，但如果试着去解决它，以及比它更复杂的情况，我认为至少对理解C++的对象模型是很有帮助的。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 开始讨论之前不得不说，这道题做为一个题目存在逻辑上的重大缺陷：&#8220;不给类增加一行代码&#8221;，我实在想不出如何在验正解题人所提供方案的正确性。只有一个private，难道用解题人所提供的读出方案来验证他自己所提供的写入方案？你用你的方法读出来，然后告诉我那就是你用你的方法写进去的值——那能让人信服吗？所以我决定还是把问题改一改，并稍微具体化如下： &nbsp; <br>&nbsp; class &nbsp; Test &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; int &nbsp; get_value() &nbsp; { &nbsp; return &nbsp; value; &nbsp; } &nbsp; <br>&nbsp; private: &nbsp; <br>&nbsp; int &nbsp; value; &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; 要求不用友元，不在这个类里添加任何代码，把成员变量k的值改为100，结果自然是通过公共成员函数get_value来验证。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; &#8220;不在类里添加任何代码&#8221;，除了 &nbsp; <br>&nbsp; #define &nbsp; private &nbsp; public &nbsp; <br>&nbsp; 我实在想不出其它的&#8220;偏门&#8221;方法了。那就想想不偏门的吧，论坛里好几位朋友提供了相当于如下代码的方法（为控制篇幅，本文中所有程序段都假设已包含了&lt;iostream&gt;头文件并引入了std名字空间，必要时还有其它头文件）： &nbsp; <br>&nbsp; Test &nbsp; t; &nbsp; <br>&nbsp; *(int*)&amp;t &nbsp; = &nbsp; 100; &nbsp; <br>&nbsp; cout &nbsp; &lt;&lt; &nbsp; t.get_value() &nbsp; &lt;&lt; &nbsp; endl; &nbsp; <br>&nbsp; 这种方式利用对象内存布局的特点：整个类只有一个整型成员，没有继承或虚拟继承，也没有任何虚函数，那么这个对象的地址也就是它的第一个成员变量的地址，所以只需要把对象地址强转成整型，那么获得的就是那个成员变量的地址，然后对转换后的地址再解引用，修改即可，在VC2003中验证，结果是正确的。 &nbsp; <br>&nbsp; 但指针的强制转换总给人带来不爽，不大安全的感觉，上面那条最关键的语句相当于： &nbsp; <br>&nbsp; *reinterpret_cast&lt;int*&gt;(&amp;t) &nbsp; = &nbsp; 100; &nbsp; <br>&nbsp; 也就是说，它动用了C++语言中最&#8220;强&#8221;的指针转换方式（说它最强，是因为没有什么指针之间他不能转换的）。其实我们完全可以做得更&#8220;文明&#8221;一点，方法是再定义一个联合体，比如： &nbsp; <br>&nbsp; union &nbsp; TestInt &nbsp; { &nbsp; <br>&nbsp; Test t; &nbsp; <br>&nbsp; int i; &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; 然后再： &nbsp; <br>&nbsp; TestInt &nbsp; ti; &nbsp; <br>&nbsp; ti.i &nbsp; = &nbsp; 100; &nbsp; <br>&nbsp; cout &nbsp; &lt;&lt; &nbsp; ti.t.get_value() &nbsp; &lt;&lt; &nbsp; endl; &nbsp; <br>&nbsp; 同样达到了目的，但实质上依据的机理跟上面的指针转换是一致的。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 这个方法没啥大问题，就是有局限性，只能用于修改类的第一个成员，如果在value之前再加一个成员，比如： &nbsp; <br>&nbsp; class &nbsp; Test &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; int &nbsp; get_value() &nbsp; { &nbsp; return &nbsp; value; &nbsp; } &nbsp; <br>&nbsp; private: &nbsp; <br>&nbsp; char &nbsp; ch; &nbsp; <br>&nbsp; int &nbsp; value; &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; 这种方法就不灵了。 &nbsp; <br>&nbsp; 当然，你可以手工算，认为char占一个字节，于是会试图取对象地址再加1得到成员value的地址。但第一，这种方法无法不跨平台跨实现，char及int类型在不同的平台和编译器实现中的长度都可能是不一样的；第二，没有考虑字对齐问题，在内存中，value成员一般不会紧接着排布在ch之后，而是中间间开几个字节，最后将int类型对齐到另一个位置，比如4的倍数的地址上；而更糟糕的是，字对齐不仅跟平台相关，还跟预编译指令，甚至编译选项都会有关。所以，这种手工计算的方式还是放弃了吧。 &nbsp; <br>&nbsp; 有朋友提到了使用一种宏求出value成员相对于整个对象起始地址的偏移量，即定义一个宏： &nbsp; <br>&nbsp; #define &nbsp; OFFSET(TYPE,MEM) &nbsp; ((int)(char*)&amp;(((TYPE*)0)-&gt;MEM)) &nbsp; <br>&nbsp; 这个宏通过把0地址转换为TYPE指针类型，然后从这个指针上&#8220;取&#8221;MEM成员，而MEM成员的地址转换后结果就是MEM成员相对于整个对象的偏移量（我们既然是从0地址开始算的，就不用再减去起始地址0）。 &nbsp; <br>&nbsp; 然后同，我们通过使用这个宏作用于原来的类和目标字段，即： &nbsp; <br>&nbsp; OFFSET(Test, &nbsp; value) &nbsp; <br>&nbsp; 就可以获得value字段在Test类型对象中的偏移量，用对象的首地址加上这个偏移量，就可以得到value变量的地址，从而可以像上面一样解引用，修改。 &nbsp; <br>&nbsp; 这种方法不仅看起来难受，费解。事实上也根本行不通，因为这个宏所用到的技巧是从Test类型的指针上访问value成员——而valuee是private的！所以连编译都通不过。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 论坛里有位朋友提出了另外一种方法可以巧妙地对付这个复杂一点的类，先做一个辅助类，它跟Test类很像，唯一的不同是它的成员都是public的： &nbsp; <br>&nbsp; class &nbsp; TestTwin &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; int &nbsp; get_value() &nbsp; { &nbsp; return &nbsp; value; &nbsp; } &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; char &nbsp; ch; &nbsp; <br>&nbsp; int &nbsp; value; &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; 于是，这个TestTwin类跟原来的Test类在内存布局上不会有什么不同，通过指针转换，很容易借助于它来修改Test类对象的value成员： &nbsp; <br>&nbsp; Test &nbsp; t; &nbsp; <br>&nbsp; TestTwin* &nbsp; p &nbsp; = &nbsp; reinterpret_cast&lt;TestTwin*&gt;(&amp;t); &nbsp; <br>&nbsp; p-&gt;value &nbsp; = &nbsp; 100; &nbsp; <br>&nbsp; cout &nbsp; &lt;&lt; &nbsp; t.get_value() &nbsp; &lt;&lt; &nbsp; endl; &nbsp; <br>&nbsp; 如果你不熟悉C++的显式指针转换方式：reinterpret_cast，在这里可以认为它相当于C风格的： &nbsp; <br>&nbsp; TestTwin* &nbsp; p &nbsp; = &nbsp; (TestTwin*)&amp;t; &nbsp; <br>&nbsp; 而前述的两条语句也可以合在一起，直接写成： &nbsp; <br>&nbsp; reinterpret_cast&lt;TestTwin*&gt;(&amp;t)-&gt;value &nbsp; = &nbsp; 100; &nbsp; <br>&nbsp; 还有，厌恶指针操作的朋友仍可采用前面介绍的联合体方法来运用这个模具类，只是这次定义的联合体是这样： &nbsp; <br>&nbsp; union &nbsp; TestTestTwin &nbsp; { &nbsp; <br>&nbsp; Test t; &nbsp; <br>&nbsp; TestTwin tw; &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; 而程序是这样： &nbsp; <br>&nbsp; TestTestTwin &nbsp; ttw; &nbsp; <br>&nbsp; ttw.tw.value &nbsp; = &nbsp; 100; &nbsp; <br>&nbsp; cout &nbsp; &lt;&lt; &nbsp; ttw.t.get_value() &nbsp; &lt;&lt; &nbsp; endl; &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 问题都解决了吗？如果类更复杂一些，会不会还有局限性呢？我们再把类改一改： &nbsp; &nbsp; <br>&nbsp; class &nbsp; Test &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; int &nbsp; get_value() &nbsp; { &nbsp; return &nbsp; value; &nbsp; } &nbsp; <br>&nbsp; ~Test() &nbsp; {} &nbsp; <br>&nbsp; private: &nbsp; <br>&nbsp; char &nbsp; ch; &nbsp; <br>&nbsp; int &nbsp; value; &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; int &nbsp; a; &nbsp; <br>&nbsp; double &nbsp; b; &nbsp; <br>&nbsp; protected: &nbsp; <br>&nbsp; string &nbsp; e; &nbsp; <br>&nbsp; private: &nbsp; <br>&nbsp; short &nbsp; d; &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; 这次不仅成员多了许多，有string类型的成员（须include &nbsp; &lt;string&gt;），还弄出个虚析构函数来（我们都知道拥有虚函数的类会导致其实例中多一个虚表指针）。但后面会看到，虚函数对我们讨论的问题影响不大，我们加上它只是想证明：只要方法足够好，不怕对象更复杂。 &nbsp; <br>&nbsp; 那上面的模具办法问题出在哪里呢？为什么不能同样再搞一个类，把那个value改为public的，然后用它来&#8220;套住&#8221;原来对象中value成员呢？ &nbsp; <br>&nbsp; 原因是C++语言只保证类中同一个access &nbsp; section（即从一个访问权限修饰符public/private/protected到另一个修饰符之间的部分）中定义的非静态成员变量会按照声明时的顺序分布的内存中，但并不保证跨越了不同access &nbsp; section的所有成员变量都在内存中按声明时的顺序存放，某种编译器完全有可能把所有的private块都合成一块，甚至整个给扔到所有protected成员的后边去（虽然VC并没这么做）。 &nbsp; <br>&nbsp; 换句话说：改掉了一个成员的访问权限，就可能改变了对象的内存布局。于是，改变了的模子也就不再能够套住相应位置上的成员。 &nbsp; <br>&nbsp; 但办法还是有，只需要将原来的改进一下： &nbsp; <br>&nbsp; 在现有的C++对象模型中，为类增加一个非虚成员函数，不会改变对象的内存布局，我们可以利用这一点来写一个TestTwin： &nbsp; <br>&nbsp; class &nbsp; TestTwin &nbsp; { &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; int &nbsp; get_value() &nbsp; { &nbsp; return &nbsp; value; &nbsp; } &nbsp; <br>&nbsp; void &nbsp; set_value(int &nbsp; v) &nbsp; { &nbsp; value &nbsp; = &nbsp; v; &nbsp; } &nbsp; <br>&nbsp; ~TestTwin() &nbsp; {} &nbsp; <br>&nbsp; private: &nbsp; <br>&nbsp; char &nbsp; ch; &nbsp; <br>&nbsp; int &nbsp; value; &nbsp; <br>&nbsp; public: &nbsp; <br>&nbsp; int &nbsp; a; &nbsp; <br>&nbsp; double &nbsp; b; &nbsp; <br>&nbsp; protected: &nbsp; <br>&nbsp; float &nbsp; e; &nbsp; <br>&nbsp; private: &nbsp; <br>&nbsp; short &nbsp; d; &nbsp; <br>&nbsp; }; &nbsp; <br>&nbsp; 这个模具跟原来的Test类也是只有一点不同：增加了一个公共的，非虚的set_value方法，用来给私有成员value赋值。于是，程序可以这么写： &nbsp; <br>&nbsp; Test &nbsp; t; &nbsp; <br>&nbsp; reinterpret_cast&lt;TestTwin*&gt;(&amp;t)-&gt;set_value(100); &nbsp; <br>&nbsp; cout &nbsp; &lt;&lt; &nbsp; t.get_value() &nbsp; &lt;&lt; &nbsp; endl; &nbsp; <br>&nbsp; 验证通过。 &nbsp; <br>&nbsp; 增加的虚函数纯粹是个障眼物而已，它跟我们采用的方法几乎没有丝毫联系，所以也就丝毫不用担心虚函数对内存分布的影响会影响到这个方法的正确性。但被它一搞，那个使用联合体的方法这一次还真是不管用了，因为有了析构函数的类不能再放进联合体中了——否则当联合体实例的生命周期结束时，析构谁呢？ &nbsp; &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 想了关天，能想到的只有这么多了。 &nbsp; <br>&nbsp; 最后，不行不承认，&#8220;增加一个非虚成员函数，不会改变对象的内存布局&#8221;这句话也无法从C++标准中得到直接支持，只是对于目前大多数编译器来说，这都是没问题的。因为这种&#8220;让类的每个实例拥有一份独立的成员变量，而类的所有实例共享一份成员函数&#8221;的C++对象模型是C++之父Bjarne &nbsp; Stroustrup先生本人所提出的，其时间、空间效率都很好地符合了C++语言的设计初衷，不仅现代C++编译器没有不这么做的，就连Java/C#编译器也都这么做。所以，也算是个&#8220;相对真理&#8221;了。&nbsp;<br><br>&nbsp;&nbsp;&nbsp; 原文地址：<a href="http://community.csdn.net/Expert/topic/5039/5039857.xml?temp=.728924">http://community.csdn.net/Expert/topic/5039/5039857.xml?temp=.728924</a></p>
<img src ="http://www.cppblog.com/andxie99/aggbug/14090.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-10-24 15:22 <a href="http://www.cppblog.com/andxie99/archive/2006/10/24/14090.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows Socket API 使用小结</title><link>http://www.cppblog.com/andxie99/archive/2006/10/11/13558.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 11 Oct 2006 00:32:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/10/11/13558.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/13558.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/10/11/13558.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/13558.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/13558.html</trackback:ping><description><![CDATA[
		<br />一、WSAStartup函数<br />   int WSAStartup(<br />     WORD wVersionRequested,  <br />     LPWSADATA lpWSAData  <br />   );<br />   使用Socket的程序在使用Socket之前必须调用WSAStartup函数。该函数的第一个参数指明程序请求使用的Socket版本，其中高位字节指明副版本、低位字节指明主版本；操作系统利用第二个参数返回请求的Socket的版本信息。当一个应用程序调用WSAStartup函数时，操作系统根据请求的Socket版本来搜索相应的Socket库，然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。该函数执行成功后返回0。<br />例：假如一个程序要使用2.1版本的Socket,那么程序代码如下<br />           wVersionRequested = MAKEWORD( 2, 1 );<br />           err = WSAStartup( wVersionRequested, &amp;wsaData );<br /><br />二、WSACleanup函数<br />   int WSACleanup (void);<br />   应用程序在完成对请求的Socket库的使用后，要调用WSACleanup函数来解除与Socket库的绑定并且释放Socket库所占用的系统资源。<br /><br />三、socket函数<br />  SOCKET socket(<br />     int af,       <br />     int type,     <br />     int protocol  <br />   );<br />   应用程序调用socket函数来创建一个能够进行网络通信的套接字。第一个参数指定应用程序使用的通信协议的协议族，对于TCP/IP协议族，该参数置PF_INET;第二个参数指定要创建的套接字类型，流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM；第三个参数指定应用程序所使用的通信协议。该函数如果调用成功就返回新创建的套接字的描述符，如果失败就返回INVALID_SOCKET。套接字描述符是一个整数类型的值。每个进程的进程空间里都有一个套接字描述符表，该表中存放着套接字描述符和套接字数据结构的对应关系。该表中有一个字段存放新创建的套接字的描述符，另一个字段存放套接字数据结构的地址，因此根据套接字描述符就可以找到其对应的套接字数据结构。每个进程在自己的进程空间里都有一个套接字描述符表但是套接字数据结构都是在操作系统的内核缓冲里。下面是一个创建流套接字的例子：<br />       struct protoent *ppe;<br />       ppe=getprotobyname("tcp");<br />       SOCKET ListenSocket=socket(PF_INET,SOCK_STREAM,ppe-&gt;p_proto);<br /><br />四、closesocket函数<br />  int closesocket(<br />     SOCKET s  <br />   );<br />   closesocket函数用来关闭一个描述符为s套接字。由于每个进程中都有一个套接字描述符表，表中的每个套接字描述符都对应了一个位于操作系统缓冲区中的套接字数据结构，因此有可能有几个套接字描述符指向同一个套接字数据结构。套接字数据结构中专门有一个字段存放该结构的被引用次数，即有多少个套接字描述符指向该结构。当调用closesocket函数时，操作系统先检查套接字数据结构中的该字段的值，如果为1，就表明只有一个套接字描述符指向它，因此操作系统就先把s在套接字描述符表中对应的那条表项清除，并且释放s对应的套接字数据结构；如果该字段大于1，那么操作系统仅仅清除s在套接字描述符表中的对应表项，并且把s对应的套接字数据结构的引用次数减1。<br />closesocket函数如果执行成功就返回0，否则返回SOCKET_ERROR。<br /><br />五、send函数<br />  int send(<br />     SOCKET s,              <br />     const char FAR *buf,  <br />     int len,               <br />     int flags              <br />   );<br />   不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求，而服务器则通常用send函数来向客户程序发送应答。该函数的第一个参数指定发送端套接字描述符；第二个参数指明一个存放应用程序要发送数据的缓冲区；第三个参数指明实际要发送的数据的字节数；第四个参数一般置0。这里只描述同步Socket的send函数的执行流程。当调用该函数时，send先比较待发送数据的长度len和套接字s的发送缓冲区的长度，如果len大于s的发送缓冲区的长度，该函数返回SOCKET_ERROR；如果len小于或者等于s的发送缓冲区的长度，那么send先检查协议是否正在发送s的发送缓冲中的数据，如果是就等待协议把数据发送完，如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据，那么send就比较s的发送缓冲区的剩余空间和len，如果len大于剩余空间大小send就一直等待协议把s的发送缓冲中的数据发送完，如果len小于剩余空间大小send就仅仅把buf中的数据copy到剩余空间里（注意并不是send把s的发送缓冲中的数据传到连接的另一端的，而是协议传的，send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里）。如果send函数copy数据成功，就返回实际copy的字节数，如果send在copy数据时出现错误，那么send就返回SOCKET_ERROR；如果send在等待协议传送数据时网络断开的话，那么send函数也返回SOCKET_ERROR。要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了，但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话，那么下一个Socket函数就会返回SOCKET_ERROR。（每一个除send外的Socket函数在执行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续，如果在等待时出现网络错误，那么该Socket函数就返回SOCKET_ERROR）<br />注意：在Unix系统下，如果send在等待协议传送数据时网络断开的话，调用send的进程会接收到一个SIGPIPE信号，进程对该信号的默认处理是进程终止。<br /><br />六、recv函数<br />   int recv(<br />     SOCKET s,       <br />     char FAR *buf,  <br />     int len,        <br />     int flags       <br />   );<br />   不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符；第二个参数指明一个缓冲区，该缓冲区用来存放recv函数接收到的数据；第三个参数指明buf的长度；第四个参数一般置0。这里只描述同步Socket的recv函数的执行流程。当应用程序调用recv函数时，recv先等待s的发送缓冲中的数据被协议传送完毕，如果协议在传送s的发送缓冲中的数据时出现网络错误，那么recv函数返回SOCKET_ERROR，如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后，recv先检查套接字s的接收缓冲区，如果s接收缓冲区中没有数据或者协议正在接收数据，那么recv就一直等待，只到协议把数据接收完毕。当协议把数据接收完毕，recv函数就把s的接收缓冲中的数据copy到buf中（注意协议接收到的数据可能大于buf的长度，所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据，真正的接收数据是协议来完成的），recv函数返回其实际copy的字节数。如果recv在copy时出错，那么它返回SOCKET_ERROR；如果recv函数在等待协议接收数据时网络中断了，那么它返回0。<br />注意：在Unix系统下，如果recv函数在等待协议接收数据时网络断开了，那么调用recv的进程会接收到一个SIGPIPE信号，进程对该信号的默认处理是进程终止。<br /><br />七、bind函数<br />  int bind(<br />     SOCKET s,                          <br />     const struct sockaddr FAR *name,   <br />     int namelen                        <br />   );<br />   当创建了一个Socket以后，套接字数据结构中有一个默认的IP地址和默认的端口号。一个服务程序必须调用bind函数来给其绑定一个IP地址和一个特定的端口号。客户程序一般不必调用bind函数来为其Socket绑定IP地址和断口号。该函数的第一个参数指定待绑定的Socket描述符；第二个参数指定一个sockaddr结构，该结构是这样定义的： <br />struct sockaddr { <br />           u_short sa_family; <br />           char sa_data[14]; <br />       };<br />  sa_family指定地址族，对于TCP/IP协议族的套接字，给其置AF_INET。当对TCP/IP协议族的套接字进行绑定时，我们通常使用另一个地址结构：<br />       struct sockaddr_in {<br />           short   sin_family;<br />           u_short sin_port;<br />           struct  in_addr sin_addr;<br />           char    sin_zero[8];<br />       };<br />   其中sin_family置AF_INET；sin_port指明端口号；sin_addr结构体中只有一个唯一的字段s_addr，表示IP地址，该字段是一个整数，一般用函数inet_addr（）把字符串形式的IP地址转换成unsigned long型的整数值后再置给s_addr。有的服务器是多宿主机，至少有两个网卡，那么运行在这样的服务器上的服务程序在为其Socket绑定IP地址时可以把htonl(INADDR_ANY)置给s_addr，这样做的好处是不论哪个网段上的客户程序都能与该服务程序通信；如果只给运行在多宿主机上的服务程序的Socket绑定一个固定的IP地址，那么就只有与该IP地址处于同一个网段上的客户程序才能与该服务程序通信。我们用0来填充sin_zero数组，目的是让sockaddr_in结构的大小与sockaddr结构的大小一致。下面是一个bind函数调用的例子：<br />   struct sockaddr_in saddr；<br />   saddr.sin_family = AF_INET;<br />   saddr.sin_port = htons(8888);<br />   saddr.sin_addr.s_addr = htonl(INADDR_ANY);<br />   bind(ListenSocket,(struct sockaddr *)&amp;saddr,sizeof(saddr))；<br /><br />八、listen函数<br />   int listen( SOCKET s, int backlog );<br />   服务程序可以调用listen函数使其流套接字s处于监听状态。处于监听状态的流套接字s将维护一个客户连接请求队列，该队列最多容纳backlog个客户连接请求。假如该函数执行成功，则返回0；如果执行失败，则返回SOCKET_ERROR。<br /><br />九、accept函数<br />   SOCKET accept(<br />     SOCKET s, <br />     struct sockaddr FAR *addr,  <br />     int FAR *addrlen  <br />   );<br />   服务程序调用accept函数从处于监听状态的流套接字s的客户连接请求队列中取出排在最前的一个客户请求，并且创建一个新的套接字来与客户套接字创建连接通道，如果连接成功，就返回新创建的套接字的描述符，以后与客户套接字交换数据的是新创建的套接字；如果失败就返回INVALID_SOCKET。该函数的第一个参数指定处于监听状态的流套接字；操作系统利用第二个参数来返回新创建的套接字的地址结构；操作系统利用第三个参数来返回新创建的套接字的地址结构的长度。下面是一个调用accept的例子：<br />       struct sockaddr_in ServerSocketAddr;<br />       int addrlen;<br />       addrlen=sizeof(ServerSocketAddr);<br />       ServerSocket=accept(ListenSocket,(struct sockaddr *)&amp;ServerSocketAddr,&amp;addrlen);<br /><br />十、connect函数<br />   int connect(<br />     SOCKET s,                          <br />     const struct sockaddr FAR *name,  <br />     int namelen                        <br />   );<br />   客户程序调用connect函数来使客户Socket s与监听于name所指定的计算机的特定端口上的服务Socket进行连接。如果连接成功，connect返回0；如果失败则返回SOCKET_ERROR。下面是一个例子：<br />       struct sockaddr_in daddr;<br />       memset((void *)&amp;daddr,0,sizeof(daddr));<br />       daddr.sin_family=AF_INET;<br />       daddr.sin_port=htons(8888);<br />       daddr.sin_addr.s_addr=inet_addr("133.197.22.4");<br />       connect(ClientSocket,(struct sockaddr *)&amp;daddr,sizeof(daddr)); <br /><br /><img src ="http://www.cppblog.com/andxie99/aggbug/13558.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-10-11 08:32 <a href="http://www.cppblog.com/andxie99/archive/2006/10/11/13558.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual C++线程同步技术</title><link>http://www.cppblog.com/andxie99/archive/2006/10/10/13517.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Tue, 10 Oct 2006 08:14:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/10/10/13517.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/13517.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/10/10/13517.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/13517.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/13517.html</trackback:ping><description><![CDATA[
		<p>线程同步的方式有：<br />　　临界区<br />　　管理事件内核对象<br />　　信号量内核对象<br />　　互斥内核对象<br />分别介绍如下：<br /><br /><strong>使线程同步<br /><br /></strong>　　在程序中使用多线程时，一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作，而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在其处理任务完成后进行。<br /><br />　　如果不采取适当的措施，其他线程往往会在线程处理任务结束前就去访问处理结果，这就很有可能得到有关处理结果的错误了解。例如，多个线程同时访问同一个全局变量，如果都是读取操作，则不会出现问题。如果一个线程负责改变此变量的值，而其他线程负责同时读取变量内容，则不能保证读取到的数据是经过写线程修改后的。<br /><br />　　为了确保读线程读取到的是经过修改的变量，就必须在向变量写入数据时禁止其他线程对其的任何访问，直至赋值过程结束后再解除对其他线程的访问限制。象这种保证线程能了解其他线程任务处理结束后的处理结果而采取的保护措施即为线程同步。<br /><br />　　线程同步是一个非常大的话题，包括方方面面的内容。从大的方面讲，线程的同步可分用户模式的线程同步和内核对象的线程同步两大类。用户模式中线程的同步方法主要有原子访问和临界区等方法。其特点是同步速度特别快，适合于对线程运行速度有严格要求的场合。<br /><br />　　内核对象的线程同步则主要由事件、等待定时器、信号量以及信号灯等内核对象构成。由于这种同步机制使用了内核对象，使用时必须将线程从用户模式切换到内核模式，而这种转换一般要耗费近千个CPU周期，因此同步速度较慢，但在适用性上却要远优于用户模式的线程同步方式。<br /><br /><strong>临界区<br /><br /></strong>　　临界区（Critical Section）是一段独占对某些共享资源访问的代码，在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区，那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起，并一直持续到进入临界区的线程离开。临界区在被释放后，其他线程可以继续抢占，并以此达到用原子方式操作共享资源的目的。<br /><br />　　临界区在使用时以CRITICAL_SECTION结构对象保护共享资源，并分别用EnterCriticalSection（）和LeaveCriticalSection（）函数去标识和释放一个临界区。所用到的CRITICAL_SECTION结构对象必须经过InitializeCriticalSection（）的初始化后才能使用，而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用，共享资源依然有被破坏的可能。<br /><br /><img height="87" alt="thread01.jpg" src="http://www.cppblog.com/images/cppblog_com/andxie99/thread01.jpg" width="178" border="0" /><br />图1 使用临界区保持线程同步<br /><br />　　下面通过一段代码展示了临界区在保护多线程访问的共享资源中的作用。通过两个线程来分别对全局变量g_cArray[10]进行写入操作，用临界区结构对象g_cs来保持线程的同步，并在开启线程前对其进行初始化。为了使实验效果更加明显，体现出临界区的作用，在线程函数对共享资源g_cArray[10]的写入时，以Sleep（）函数延迟1毫秒，使其他线程同其抢占CPU的可能性增大。如果不使用临界区对其进行保护，则共享资源数据将被破坏（参见图1（a）所示计算结果），而使用临界区对线程保持同步后则可以得到正确的结果（参见图1（b）所示计算结果）。代码实现清单附下：<br /><br /></p>
		<p>
		</p>
		<p>
		</p>
		<table width="100%" bgcolor="#ffffff">
				<tbody>
						<tr>
								<td>// 临界区结构对象<br />CRITICAL_SECTION g_cs;<br />// 共享资源 <br />char g_cArray[10];<br />UINT ThreadProc10(LPVOID pParam)<br />{<br />　// 进入临界区<br />　EnterCriticalSection(&amp;g_cs);<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[i] = 'a';<br />　　Sleep(1);<br />　}<br />　// 离开临界区<br />　LeaveCriticalSection(&amp;g_cs);<br />　return 0;<br />}<br />UINT ThreadProc11(LPVOID pParam)<br />{<br />　// 进入临界区<br />　EnterCriticalSection(&amp;g_cs);<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[10 - i - 1] = 'b';<br />　　Sleep(1);<br />　}<br />　// 离开临界区<br />　LeaveCriticalSection(&amp;g_cs);<br />　return 0;<br />}<br />……<br />void CSample08View::OnCriticalSection() <br />{<br />　// 初始化临界区<br />　InitializeCriticalSection(&amp;g_cs);<br />　// 启动线程<br />　AfxBeginThread(ThreadProc10, NULL);<br />　AfxBeginThread(ThreadProc11, NULL);<br />　// 等待计算完毕<br />　Sleep(300);<br />　// 报告计算结果<br />　CString sResult = CString(g_cArray);<br />　AfxMessageBox(sResult);<br />}</td>
						</tr>
				</tbody>
		</table>
		<br />　　在使用临界区时，一般不允许其运行时间过长，只要进入临界区的线程还没有离开，其他所有试图进入此临界区的线程都会被挂起而进入到等待状态，并会在一定程度上影响。程序的运行性能。尤其需要注意的是不要将等待用户输入或是其他一些外界干预的操作包含到临界区。如果进入了临界区却一直没有释放，同样也会引起其他线程的长时间等待。换句话说，在执行了EnterCriticalSection（）语句进入临界区后无论发生什么，必须确保与之匹配的LeaveCriticalSection（）都能够被执行到。可以通过添加结构化异常处理代码来确保LeaveCriticalSection（）语句的执行。虽然临界区同步速度很快，但却只能用来同步本进程内的线程，而不可用来同步多个进程中的线程。<br /><br />　　MFC为临界区提供有一个CCriticalSection类，使用该类进行线程同步处理是非常简单的，只需在线程函数中用CCriticalSection类成员函数Lock（）和UnLock（）标定出被保护代码片段即可。对于上述代码，可通过CCriticalSection类将其改写如下：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>// MFC临界区类对象<br />CCriticalSection g_clsCriticalSection;<br />// 共享资源 <br />char g_cArray[10];<br />UINT ThreadProc20(LPVOID pParam)<br />{<br />　// 进入临界区<br />　g_clsCriticalSection.Lock();<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[i] = 'a';<br />　　Sleep(1);<br />　}<br />　// 离开临界区<br />　g_clsCriticalSection.Unlock();<br />　return 0;<br />}<br />UINT ThreadProc21(LPVOID pParam)<br />{<br />　// 进入临界区<br />　g_clsCriticalSection.Lock();<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[10 - i - 1] = 'b';<br />　　Sleep(1);<br />　}<br />　// 离开临界区<br />　g_clsCriticalSection.Unlock();<br />　return 0;<br />}<br />……<br />void CSample08View::OnCriticalSectionMfc() <br />{<br />　// 启动线程<br />　AfxBeginThread(ThreadProc20, NULL);<br />　AfxBeginThread(ThreadProc21, NULL);<br />　// 等待计算完毕<br />　Sleep(300);<br />　// 报告计算结果<br />　CString sResult = CString(g_cArray);<br />　AfxMessageBox(sResult);<br />}</td></tr></tbody></table><br /><strong>管理事件内核对象<br /><br /></strong>　　在前面讲述线程通信时曾使用过事件内核对象来进行线程间的通信，除此之外，事件内核对象也可以通过通知操作的方式来保持线程的同步。对于前面那段使用临界区保持线程同步的代码可用事件对象的线程同步方法改写如下：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>// 事件句柄<br />HANDLE hEvent = NULL;<br />// 共享资源 <br />char g_cArray[10];<br />……<br />UINT ThreadProc12(LPVOID pParam)<br />{<br />　// 等待事件置位<br />　WaitForSingleObject(hEvent, INFINITE);<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[i] = 'a';<br />　　Sleep(1);<br />　}<br />　// 处理完成后即将事件对象置位<br />　SetEvent(hEvent);<br />　return 0;<br />}<br />UINT ThreadProc13(LPVOID pParam)<br />{<br />　// 等待事件置位<br />　WaitForSingleObject(hEvent, INFINITE);<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[10 - i - 1] = 'b';<br />　　Sleep(1);<br />　}<br />　// 处理完成后即将事件对象置位<br />　SetEvent(hEvent);<br />　return 0;<br />}<br />……<br />void CSample08View::OnEvent() <br />{<br />　// 创建事件<br />　hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);<br />　// 事件置位<br />　SetEvent(hEvent);<br />　// 启动线程<br />　AfxBeginThread(ThreadProc12, NULL);<br />　AfxBeginThread(ThreadProc13, NULL);<br />　// 等待计算完毕<br />　Sleep(300);<br />　// 报告计算结果<br />　CString sResult = CString(g_cArray);<br />　AfxMessageBox(sResult);<br />}</td></tr></tbody></table><br />　　在创建线程前，首先创建一个可以自动复位的事件内核对象hEvent，而线程函数则通过WaitForSingleObject（）等待函数无限等待hEvent的置位，只有在事件置位时WaitForSingleObject（）才会返回，被保护的代码将得以执行。对于以自动复位方式创建的事件对象，在其置位后一被WaitForSingleObject（）等待到就会立即复位，也就是说在执行ThreadProc12（）中的受保护代码时，事件对象已经是复位状态的，这时即使有ThreadProc13（）对CPU的抢占，也会由于WaitForSingleObject（）没有hEvent的置位而不能继续执行，也就没有可能破坏受保护的共享资源。在ThreadProc12（）中的处理完成后可以通过SetEvent（）对hEvent的置位而允许ThreadProc13（）对共享资源g_cArray的处理。这里SetEvent（）所起的作用可以看作是对某项特定任务完成的通知。<br /><br />　　使用临界区只能同步同一进程中的线程，而使用事件内核对象则可以对进程外的线程进行同步，其前提是得到对此事件对象的访问权。可以通过OpenEvent（）函数获取得到，其函数原型为：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>HANDLE OpenEvent(<br />　DWORD dwDesiredAccess, // 访问标志<br />　BOOL bInheritHandle, // 继承标志<br />　LPCTSTR lpName // 指向事件对象名的指针<br />);</td></tr></tbody></table><br />　　如果事件对象已创建（在创建事件时需要指定事件名），函数将返回指定事件的句柄。对于那些在创建事件时没有指定事件名的事件内核对象，可以通过使用内核对象的继承性或是调用DuplicateHandle（）函数来调用CreateEvent（）以获得对指定事件对象的访问权。在获取到访问权后所进行的同步操作与在同一个进程中所进行的线程同步操作是一样的。<br /><br />　　如果需要在一个线程中等待多个事件，则用WaitForMultipleObjects（）来等待。WaitForMultipleObjects（）与WaitForSingleObject（）类似，同时监视位于句柄数组中的所有句柄。这些被监视对象的句柄享有平等的优先权，任何一个句柄都不可能比其他句柄具有更高的优先权。WaitForMultipleObjects（）的函数原型为：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>DWORD WaitForMultipleObjects(<br />　DWORD nCount, // 等待句柄数<br />　CONST HANDLE *lpHandles, // 句柄数组首地址<br />　BOOL fWaitAll, // 等待标志<br />　DWORD dwMilliseconds // 等待时间间隔<br />);</td></tr></tbody></table><br />　　参数nCount指定了要等待的内核对象的数目，存放这些内核对象的数组由lpHandles来指向。fWaitAll对指定的这nCount个内核对象的两种等待方式进行了指定，为TRUE时当所有对象都被通知时函数才会返回，为FALSE则只要其中任何一个得到通知就可以返回。dwMilliseconds在这里的作用与在WaitForSingleObject（）中的作用是完全一致的。如果等待超时，函数将返回WAIT_TIMEOUT。如果返回WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1中的某个值，则说明所有指定对象的状态均为已通知状态（当fWaitAll为TRUE时）或是用以减去WAIT_OBJECT_0而得到发生通知的对象的索引（当fWaitAll为FALSE时）。如果返回值在WAIT_ABANDONED_0与WAIT_ABANDONED_0+nCount-1之间，则表示所有指定对象的状态均为已通知，且其中至少有一个对象是被丢弃的互斥对象（当fWaitAll为TRUE时），或是用以减去WAIT_OBJECT_0表示一个等待正常结束的互斥对象的索引（当fWaitAll为FALSE时）。 下面给出的代码主要展示了对WaitForMultipleObjects（）函数的使用。通过对两个事件内核对象的等待来控制线程任务的执行与中途退出：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>// 存放事件句柄的数组<br />HANDLE hEvents[2];<br />UINT ThreadProc14(LPVOID pParam)<br />{ <br />　// 等待开启事件<br />　DWORD dwRet1 = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);<br />　// 如果开启事件到达则线程开始执行任务<br />　if (dwRet1 == WAIT_OBJECT_0)<br />　{<br />　　AfxMessageBox("线程开始工作!");<br />　　while (true)<br />　　{<br />　　　for (int i = 0; i &lt; 10000; i++);<br />　　　// 在任务处理过程中等待结束事件 <br />　　　DWORD dwRet2 = WaitForMultipleObjects(2, hEvents, FALSE, 0);<br />　　　// 如果结束事件置位则立即终止任务的执行<br />　　　if (dwRet2 == WAIT_OBJECT_0 + 1)<br />　　　　break;<br />　　}<br />　}<br />　AfxMessageBox("线程退出!");<br />　return 0;<br />}<br />……<br />void CSample08View::OnStartEvent() <br />{<br />　// 创建线程<br />　for (int i = 0; i &lt; 2; i++)<br />　　hEvents[i] = CreateEvent(NULL, FALSE, FALSE, NULL);<br />　　// 开启线程<br />　　AfxBeginThread(ThreadProc14, NULL);<br />　　// 设置事件0(开启事件)<br />　　SetEvent(hEvents[0]);<br />}<br />void CSample08View::OnEndevent() <br />{<br />　// 设置事件1(结束事件)<br />　SetEvent(hEvents[1]);<br />}</td></tr></tbody></table><br />　　MFC为事件相关处理也提供了一个CEvent类，共包含有除构造函数外的4个成员函数PulseEvent（）、ResetEvent（）、SetEvent（）和UnLock（）。在功能上分别相当与Win32 API的PulseEvent（）、ResetEvent（）、SetEvent（）和CloseHandle（）等函数。而构造函数则履行了原CreateEvent（）函数创建事件对象的职责，其函数原型为：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );</td></tr></tbody></table><br />　　按照此缺省设置将创建一个自动复位、初始状态为复位状态的没有名字的事件对象。封装后的CEvent类使用起来更加方便，图2即展示了CEvent类对A、B两线程的同步过程：<br /><br /><img height="97" alt="Thread02.jpg" src="http://www.cppblog.com/images/cppblog_com/andxie99/Thread02.jpg" width="329" border="0" /><br />图2 CEvent类对线程的同步过程示意<br /><br />　　B线程在执行到CEvent类成员函数Lock（）时将会发生阻塞，而A线程此时则可以在没有B线程干扰的情况下对共享资源进行处理，并在处理完成后通过成员函数SetEvent（）向B发出事件，使其被释放，得以对A先前已处理完毕的共享资源进行操作。可见，使用CEvent类对线程的同步方法与通过API函数进行线程同步的处理方法是基本一致的。前面的API处理代码可用CEvent类将其改写为：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>// MFC事件类对象<br />CEvent g_clsEvent;<br />UINT ThreadProc22(LPVOID pParam)<br />{<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[i] = 'a';<br />　　Sleep(1);<br />　}<br />　// 事件置位<br />　g_clsEvent.SetEvent();<br />　return 0;<br />}<br />UINT ThreadProc23(LPVOID pParam)<br />{<br />　// 等待事件<br />　g_clsEvent.Lock();<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[10 - i - 1] = 'b';<br />　　Sleep(1);<br />　}<br />　return 0;<br />}<br />……<br />void CSample08View::OnEventMfc() <br />{<br />　// 启动线程<br />　AfxBeginThread(ThreadProc22, NULL);<br />　AfxBeginThread(ThreadProc23, NULL);<br />　// 等待计算完毕<br />　Sleep(300);<br />　// 报告计算结果<br />　CString sResult = CString(g_cArray);<br />　AfxMessageBox(sResult);<br />}</td></tr></tbody></table><br /><strong>信号量内核对象<br /><br /></strong>　　信号量（Semaphore）内核对象对线程的同步方式与前面几种方法不同，它允许多个线程在同一时刻访问同一资源，但是需要限制在同一时刻访问此资源的最大线程数目。在用CreateSemaphore（）创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数，每增加一个线程对共享资源的访问，当前可用资源计数就会减1，只要当前可用资源计数是大于0的，就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目，不能在允许其他线程的进入，此时的信号量信号将无法发出。线程在处理完共享资源后，应在离开的同时通过ReleaseSemaphore（）函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。<br /><br /><img height="82" alt="thread03.jpg" src="http://www.cppblog.com/images/cppblog_com/andxie99/thread03.jpg" width="308" border="0" /><br />图3 使用信号量对象控制资源<br /><br />　　下面结合图例3来演示信号量对象对资源的控制。在图3中，以箭头和白色箭头表示共享资源所允许的最大资源计数和当前可用资源计数。初始如图（a）所示，最大资源计数和当前可用资源计数均为4，此后每增加一个对资源进行访问的线程（用黑色箭头表示）当前资源计数就会相应减1，图（b）即表示的在3个线程对共享资源进行访问时的状态。当进入线程数达到4个时，将如图（c）所示，此时已达到最大资源计数，而当前可用资源计数也已减到0，其他线程无法对共享资源进行访问。在当前占有资源的线程处理完毕而退出后，将会释放出空间，图（d）已有两个线程退出对资源的占有，当前可用计数为2，可以再允许2个线程进入到对资源的处理。可以看出，信号量是通过计数来对线程访问资源进行控制的，而实际上信号量确实也被称作Dijkstra计数器。<br /><br />　　使用信号量内核对象进行线程同步主要会用到CreateSemaphore（）、OpenSemaphore（）、ReleaseSemaphore（）、WaitForSingleObject（）和WaitForMultipleObjects（）等函数。其中，CreateSemaphore（）用来创建一个信号量内核对象，其函数原型为：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>HANDLE CreateSemaphore(<br />　LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // 安全属性指针<br />　LONG lInitialCount, // 初始计数<br />　LONG lMaximumCount, // 最大计数<br />　LPCTSTR lpName // 对象名指针<br />); </td></tr></tbody></table><br />　　参数lMaximumCount是一个有符号32位值，定义了允许的最大资源计数，最大取值不能超过4294967295。lpName参数可以为创建的信号量定义一个名字，由于其创建的是一个内核对象，因此在其他进程中可以通过该名字而得到此信号量。OpenSemaphore（）函数即可用来根据信号量名打开在其他进程中创建的信号量，函数原型如下：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>HANDLE OpenSemaphore(<br />　DWORD dwDesiredAccess, // 访问标志<br />　BOOL bInheritHandle, // 继承标志<br />　LPCTSTR lpName // 信号量名<br />);</td></tr></tbody></table><br />　　在线程离开对共享资源的处理时，必须通过ReleaseSemaphore（）来增加当前可用资源计数。否则将会出现当前正在处理共享资源的实际线程数并没有达到要限制的数值，而其他线程却因为当前可用资源计数为0而仍无法进入的情况。ReleaseSemaphore（）的函数原型为：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>BOOL ReleaseSemaphore(<br />　HANDLE hSemaphore, // 信号量句柄<br />　LONG lReleaseCount, // 计数递增数量<br />　LPLONG lpPreviousCount // 先前计数<br />);</td></tr></tbody></table><br />　　该函数将lReleaseCount中的值添加给信号量的当前资源计数，一般将lReleaseCount设置为1，如果需要也可以设置其他的值。WaitForSingleObject（）和WaitForMultipleObjects（）主要用在试图进入共享资源的线程函数入口处，主要用来判断信号量的当前可用资源计数是否允许本线程的进入。只有在当前可用资源计数值大于0时，被监视的信号量内核对象才会得到通知。<br /><br />　　信号量的使用特点使其更适用于对Socket（套接字）程序中线程的同步。例如，网络上的HTTP服务器要对同一时间内访问同一页面的用户数加以限制，这时可以为没一个用户对服务器的页面请求设置一个线程，而页面则是待保护的共享资源，通过使用信号量对线程的同步作用可以确保在任一时刻无论有多少用户对某一页面进行访问，只有不大于设定的最大用户数目的线程能够进行访问，而其他的访问企图则被挂起，只有在有用户退出对此页面的访问后才有可能进入。下面给出的示例代码即展示了类似的处理过程：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>// 信号量对象句柄<br />HANDLE hSemaphore;<br />UINT ThreadProc15(LPVOID pParam)<br />{ <br />　// 试图进入信号量关口<br />　WaitForSingleObject(hSemaphore, INFINITE);<br />　// 线程任务处理<br />　AfxMessageBox("线程一正在执行!");<br />　// 释放信号量计数<br />　ReleaseSemaphore(hSemaphore, 1, NULL);<br />　return 0;<br />}<br />UINT ThreadProc16(LPVOID pParam)<br />{ <br />　// 试图进入信号量关口<br />　WaitForSingleObject(hSemaphore, INFINITE);<br />　// 线程任务处理<br />　AfxMessageBox("线程二正在执行!");<br />　// 释放信号量计数<br />　ReleaseSemaphore(hSemaphore, 1, NULL);<br />　return 0;<br />}<br />UINT ThreadProc17(LPVOID pParam)<br />{ <br />　// 试图进入信号量关口<br />　WaitForSingleObject(hSemaphore, INFINITE);<br />　// 线程任务处理<br />　AfxMessageBox("线程三正在执行!");<br />　// 释放信号量计数<br />　ReleaseSemaphore(hSemaphore, 1, NULL);<br />　return 0;<br />}<br />……<br />void CSample08View::OnSemaphore() <br />{<br />　// 创建信号量对象<br />　hSemaphore = CreateSemaphore(NULL, 2, 2, NULL);<br />　// 开启线程<br />　AfxBeginThread(ThreadProc15, NULL);<br />　AfxBeginThread(ThreadProc16, NULL);<br />　AfxBeginThread(ThreadProc17, NULL);<br />}</td></tr></tbody></table><br /><img height="152" alt="thread04.jpg" src="http://www.cppblog.com/images/cppblog_com/andxie99/thread04.jpg" width="242" border="0" /><br />图4 开始进入的两个线程<br /><br /><img height="152" alt="thread05.jpg" src="http://www.cppblog.com/images/cppblog_com/andxie99/thread05.jpg" width="242" border="0" /><br />图5 线程二退出后线程三才得以进入<br /><br />　　上述代码在开启线程前首先创建了一个初始计数和最大资源计数均为2的信号量对象hSemaphore。即在同一时刻只允许2个线程进入由hSemaphore保护的共享资源。随后开启的三个线程均试图访问此共享资源，在前两个线程试图访问共享资源时，由于hSemaphore的当前可用资源计数分别为2和1，此时的hSemaphore是可以得到通知的，也就是说位于线程入口处的WaitForSingleObject（）将立即返回，而在前两个线程进入到保护区域后，hSemaphore的当前资源计数减少到0，hSemaphore将不再得到通知，WaitForSingleObject（）将线程挂起。直到此前进入到保护区的线程退出后才能得以进入。图4和图5为上述代脉的运行结果。从实验结果可以看出，信号量始终保持了同一时刻不超过2个线程的进入。<br /><br />　　在MFC中，通过CSemaphore类对信号量作了表述。该类只具有一个构造函数，可以构造一个信号量对象，并对初始资源计数、最大资源计数、对象名和安全属性等进行初始化，其原型如下：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>CSemaphore( LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL );</td></tr></tbody></table><br />　　在构造了CSemaphore类对象后，任何一个访问受保护共享资源的线程都必须通过CSemaphore从父类CSyncObject类继承得到的Lock（）和UnLock（）成员函数来访问或释放CSemaphore对象。与前面介绍的几种通过MFC类保持线程同步的方法类似，通过CSemaphore类也可以将前面的线程同步代码进行改写，这两种使用信号量的线程同步方法无论是在实现原理上还是从实现结果上都是完全一致的。下面给出经MFC改写后的信号量线程同步代码：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>// MFC信号量类对象<br />CSemaphore g_clsSemaphore(2, 2);<br />UINT ThreadProc24(LPVOID pParam)<br />{ <br />　// 试图进入信号量关口<br />　g_clsSemaphore.Lock();<br />　// 线程任务处理<br />　AfxMessageBox("线程一正在执行!");<br />　// 释放信号量计数<br />　g_clsSemaphore.Unlock();<br />　return 0;<br />}<br />UINT ThreadProc25(LPVOID pParam)<br />{<br />　// 试图进入信号量关口<br />　g_clsSemaphore.Lock();<br />　// 线程任务处理<br />　AfxMessageBox("线程二正在执行!");<br />　// 释放信号量计数<br />　g_clsSemaphore.Unlock();<br />　return 0;<br />}<br />UINT ThreadProc26(LPVOID pParam)<br />{<br />　// 试图进入信号量关口<br />　g_clsSemaphore.Lock();<br />　// 线程任务处理<br />　AfxMessageBox("线程三正在执行!");<br />　// 释放信号量计数<br />　g_clsSemaphore.Unlock();<br />　return 0;<br />}<br />……<br />void CSample08View::OnSemaphoreMfc() <br />{<br />　// 开启线程<br />　AfxBeginThread(ThreadProc24, NULL);<br />　AfxBeginThread(ThreadProc25, NULL);<br />　AfxBeginThread(ThreadProc26, NULL);<br />}</td></tr></tbody></table><br /><br /><strong>互斥内核对象<br /><br /></strong>　　互斥（Mutex）是一种用途非常广泛的内核对象。能够保证多个线程对同一共享资源的互斥访问。同临界区有些类似，只有拥有互斥对象的线程才具有访问资源的权限，由于互斥对象只有一个，因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出，以便其他线程在获得后得以访问资源。与其他几种内核对象不同，互斥对象在操作系统中拥有特殊代码，并由操作系统来管理，操作系统甚至还允许其进行一些其他内核对象所不能进行的非常规操作。为便于理解，可参照图6给出的互斥内核对象的工作模型：<br /><br /><img height="78" alt="thread06.jpg" src="http://www.cppblog.com/images/cppblog_com/andxie99/thread06.jpg" width="401" border="0" /><br />图6 使用互斥内核对象对共享资源的保护<br /><br />　　图（a）中的箭头为要访问资源（矩形框）的线程，但只有第二个线程拥有互斥对象（黑点）并得以进入到共享资源，而其他线程则会被排斥在外（如图（b）所示）。当此线程处理完共享资源并准备离开此区域时将把其所拥有的互斥对象交出（如图（c）所示），其他任何一个试图访问此资源的线程都有机会得到此互斥对象。<br /><br />　　以互斥内核对象来保持线程同步可能用到的函数主要有CreateMutex（）、OpenMutex（）、ReleaseMutex（）、WaitForSingleObject（）和WaitForMultipleObjects（）等。在使用互斥对象前，首先要通过CreateMutex（）或OpenMutex（）创建或打开一个互斥对象。CreateMutex（）函数原型为：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>HANDLE CreateMutex(<br />　LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性指针<br />　BOOL bInitialOwner, // 初始拥有者<br />　LPCTSTR lpName // 互斥对象名<br />);</td></tr></tbody></table><br />　　参数bInitialOwner主要用来控制互斥对象的初始状态。一般多将其设置为FALSE，以表明互斥对象在创建时并没有为任何线程所占有。如果在创建互斥对象时指定了对象名，那么可以在本进程其他地方或是在其他进程通过OpenMutex（）函数得到此互斥对象的句柄。OpenMutex（）函数原型为：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>HANDLE OpenMutex(<br />　DWORD dwDesiredAccess, // 访问标志<br />　BOOL bInheritHandle, // 继承标志<br />　LPCTSTR lpName // 互斥对象名<br />); </td></tr></tbody></table><br />　　当目前对资源具有访问权的线程不再需要访问此资源而要离开时，必须通过ReleaseMutex（）函数来释放其拥有的互斥对象，其函数原型为：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>BOOL ReleaseMutex(HANDLE hMutex);</td></tr></tbody></table><br />　　其唯一的参数hMutex为待释放的互斥对象句柄。至于WaitForSingleObject（）和WaitForMultipleObjects（）等待函数在互斥对象保持线程同步中所起的作用与在其他内核对象中的作用是基本一致的，也是等待互斥内核对象的通知。但是这里需要特别指出的是：在互斥对象通知引起调用等待函数返回时，等待函数的返回值不再是通常的WAIT_OBJECT_0（对于WaitForSingleObject（）函数）或是在WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1之间的一个值（对于WaitForMultipleObjects（）函数），而是将返回一个WAIT_ABANDONED_0（对于WaitForSingleObject（）函数）或是在WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1之间的一个值（对于WaitForMultipleObjects（）函数）。以此来表明线程正在等待的互斥对象由另外一个线程所拥有，而此线程却在使用完共享资源前就已经终止。除此之外，使用互斥对象的方法在等待线程的可调度性上同使用其他几种内核对象的方法也有所不同，其他内核对象在没有得到通知时，受调用等待函数的作用，线程将会挂起，同时失去可调度性，而使用互斥的方法却可以在等待的同时仍具有可调度性，这也正是互斥对象所能完成的非常规操作之一。<br /><br />　　在编写程序时，互斥对象多用在对那些为多个线程所访问的内存块的保护上，可以确保任何线程在处理此内存块时都对其拥有可靠的独占访问权。下面给出的示例代码即通过互斥内核对象hMutex对共享内存快g_cArray[]进行线程的独占访问保护。下面给出实现代码清单：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>// 互斥对象<br />HANDLE hMutex = NULL;<br />char g_cArray[10];<br />UINT ThreadProc18(LPVOID pParam)<br />{<br />　// 等待互斥对象通知<br />　WaitForSingleObject(hMutex, INFINITE);<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[i] = 'a';<br />　　Sleep(1);<br />　}<br />　// 释放互斥对象<br />　ReleaseMutex(hMutex);<br />　return 0;<br />}<br />UINT ThreadProc19(LPVOID pParam)<br />{<br />　// 等待互斥对象通知<br />　WaitForSingleObject(hMutex, INFINITE);<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[10 - i - 1] = 'b';<br />　　Sleep(1);<br />　}<br />　// 释放互斥对象<br />　ReleaseMutex(hMutex);<br />　return 0;<br />}<br />……<br />void CSample08View::OnMutex() <br />{<br />　// 创建互斥对象<br />　hMutex = CreateMutex(NULL, FALSE, NULL);<br />　// 启动线程<br />　AfxBeginThread(ThreadProc18, NULL);<br />　AfxBeginThread(ThreadProc19, NULL);<br />　// 等待计算完毕<br />　Sleep(300);<br />　// 报告计算结果<br />　CString sResult = CString(g_cArray);<br />　AfxMessageBox(sResult);<br />} </td></tr></tbody></table><br />　　互斥对象在MFC中通过CMutex类进行表述。使用CMutex类的方法非常简单，在构造CMutex类对象的同时可以指明待查询的互斥对象的名字，在构造函数返回后即可访问此互斥变量。CMutex类也是只含有构造函数这唯一的成员函数，当完成对互斥对象保护资源的访问后，可通过调用从父类CSyncObject继承的UnLock（）函数完成对互斥对象的释放。CMutex类构造函数原型为：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );</td></tr></tbody></table><br />　　该类的适用范围和实现原理与API方式创建的互斥内核对象是完全类似的，但要简洁的多，下面给出就是对前面的示例代码经CMutex类改写后的程序实现清单：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>// MFC互斥类对象<br />CMutex g_clsMutex(FALSE, NULL);<br />UINT ThreadProc27(LPVOID pParam)<br />{<br />　// 等待互斥对象通知<br />　g_clsMutex.Lock();<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[i] = 'a';<br />　　Sleep(1);<br />　}<br />　// 释放互斥对象<br />　g_clsMutex.Unlock();<br />　return 0;<br />}<br />UINT ThreadProc28(LPVOID pParam)<br />{<br />　// 等待互斥对象通知<br />　g_clsMutex.Lock();<br />　// 对共享资源进行写入操作<br />　for (int i = 0; i &lt; 10; i++)<br />　{<br />　　g_cArray[10 - i - 1] = 'b';<br />　　Sleep(1);<br />　}<br />　// 释放互斥对象<br />　g_clsMutex.Unlock();<br />　return 0;<br />}<br />……<br />void CSample08View::OnMutexMfc() <br />{<br />　// 启动线程<br />　AfxBeginThread(ThreadProc27, NULL);<br />　AfxBeginThread(ThreadProc28, NULL);<br />　// 等待计算完毕<br />　Sleep(300);<br />　// 报告计算结果<br />　CString sResult = CString(g_cArray);<br />　AfxMessageBox(sResult);<br />}</td></tr></tbody></table><br />　　<b>小结</b><br /><br />　　线程的使用使程序处理更够更加灵活，而这种灵活同样也会带来各种不确定性的可能。尤其是在多个线程对同一公共变量进行访问时。虽然未使用线程同步的程序代码在逻辑上或许没有什么问题，但为了确保程序的正确、可靠运行，必须在适当的场合采取线程同步措施。<br /><img src ="http://www.cppblog.com/andxie99/aggbug/13517.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-10-10 16:14 <a href="http://www.cppblog.com/andxie99/archive/2006/10/10/13517.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大、小写字母相互转换 </title><link>http://www.cppblog.com/andxie99/archive/2006/10/09/13485.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Mon, 09 Oct 2006 05:31:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/10/09/13485.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/13485.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/10/09/13485.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/13485.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/13485.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="5" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<font color="#18188c" size="4">
												<strong>
												</strong>
										</font>
								</td>
						</tr>
						<tr>
								<td>
										<p>其实主要是围绕着大、小写字母之间那个32的关系（小写字母减去32得到对应的大写字母，相反，大写字母加上32得到对应的小写字母）。</p>
										<p>    通常方法：</p>
										<p>if(ch&gt;='a'&amp;&amp;ch&lt;='z')<br />   ch=ch-32;<br />else if(ch&gt;='A'&amp;&amp;ch&lt;='Z')<br />        ch=ch+32;</p>
										<p>   上面的方法都有点罗嗦，采用异或运算：<br /><br />   if(isalpha(ch))   //库函数isalpha用来测试参数是否为英文字母<br />      ch=ch^32;    //异或运算</p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/andxie99/aggbug/13485.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-10-09 13:31 <a href="http://www.cppblog.com/andxie99/archive/2006/10/09/13485.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>杨辉三角</title><link>http://www.cppblog.com/andxie99/archive/2006/10/09/13479.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Mon, 09 Oct 2006 03:06:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/10/09/13479.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/13479.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/10/09/13479.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/13479.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/13479.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="5" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<font color="#18188c" size="4">
												<strong>
												</strong>
										</font>
								</td>
						</tr>
						<tr>
								<td>
										<p>杨辉三角具有以下形式，规律为除两侧的元素均为1以外，其余每个位置上数值都等于其左上角元素与右上角元素之和：</p>
										<p>            1<br />          1   1<br />        1   2   1<br />      1   3   3   1<br />    1   4   6   4   1<br />  1   5   10  10   5  1</p>
										<p>上面的形式不适于用程序实现，往往都改写成下面的形式，规律为除两侧元素均为1以外，其余每个位置上的元素值为其正上方元素与左上角元素之和，用数组来描述则为a[i][j]=a[i-1][j]+a[i-1][j-1]：</p>
										<p>1<br />1   1<br />1   2   1<br />1   3   3   1<br />1   4   6   4   1<br />1   5  10  10  5  1</p>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> 杨辉三角的C++实现<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> 未判断 int 溢出<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> VS2005下编译通过</span>
				<span style="COLOR: #008000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">iostream</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">iomanip</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">using</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">namespace</span>
				<span style="COLOR: #000000"> std;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> prompt()<br /><img id="Codehighlighter1_119_267_Open_Image" onclick="this.style.display='none'; Codehighlighter1_119_267_Open_Text.style.display='none'; Codehighlighter1_119_267_Closed_Image.style.display='inline'; Codehighlighter1_119_267_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_119_267_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_119_267_Closed_Text.style.display='none'; Codehighlighter1_119_267_Open_Image.style.display='inline'; Codehighlighter1_119_267_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_119_267_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_119_267_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> n;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    cout</span>
						<span style="COLOR: #000000">&lt;&lt;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Input a positive number,</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">&lt;&lt;</span>
						<span style="COLOR: #000000"> endl<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
						<span style="COLOR: #000000">&lt;&lt;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">nonpositive will quit!</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">&lt;&lt;</span>
						<span style="COLOR: #000000"> endl<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
						<span style="COLOR: #000000">&lt;&lt;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">&gt;</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000"> ;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    cin </span>
						<span style="COLOR: #000000">&gt;&gt;</span>
						<span style="COLOR: #000000"> n;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> n;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> main()<br /><img id="Codehighlighter1_282_815_Open_Image" onclick="this.style.display='none'; Codehighlighter1_282_815_Open_Text.style.display='none'; Codehighlighter1_282_815_Closed_Image.style.display='inline'; Codehighlighter1_282_815_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_282_815_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_282_815_Closed_Text.style.display='none'; Codehighlighter1_282_815_Open_Image.style.display='inline'; Codehighlighter1_282_815_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_282_815_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_282_815_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> i, j, n;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">while</span>
						<span style="COLOR: #000000">((n </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> prompt()) </span>
						<span style="COLOR: #000000">&gt;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">)<br /><img id="Codehighlighter1_336_813_Open_Image" onclick="this.style.display='none'; Codehighlighter1_336_813_Open_Text.style.display='none'; Codehighlighter1_336_813_Closed_Image.style.display='inline'; Codehighlighter1_336_813_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_336_813_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_336_813_Closed_Text.style.display='none'; Codehighlighter1_336_813_Open_Image.style.display='inline'; Codehighlighter1_336_813_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_336_813_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_336_813_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
								<span style="COLOR: #0000ff">int</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">**</span>
								<span style="COLOR: #000000">a </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">new</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">int</span>
								<span style="COLOR: #000000">*</span>
								<span style="COLOR: #000000">[n];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
								<span style="COLOR: #0000ff">for</span>
								<span style="COLOR: #000000">(i</span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000">0</span>
								<span style="COLOR: #000000">; i</span>
								<span style="COLOR: #000000">&lt;</span>
								<span style="COLOR: #000000">n; i</span>
								<span style="COLOR: #000000">++</span>
								<span style="COLOR: #000000">)<br /><img id="Codehighlighter1_405_607_Open_Image" onclick="this.style.display='none'; Codehighlighter1_405_607_Open_Text.style.display='none'; Codehighlighter1_405_607_Closed_Image.style.display='inline'; Codehighlighter1_405_607_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_405_607_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_405_607_Closed_Text.style.display='none'; Codehighlighter1_405_607_Open_Image.style.display='inline'; Codehighlighter1_405_607_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span>
								<span id="Codehighlighter1_405_607_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.cppblog.com/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_405_607_Open_Text">
										<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            a[i] </span>
										<span style="COLOR: #000000">=</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #0000ff">new</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #0000ff">int</span>
										<span style="COLOR: #000000">[i</span>
										<span style="COLOR: #000000">+</span>
										<span style="COLOR: #000000">1</span>
										<span style="COLOR: #000000">];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            </span>
										<span style="COLOR: #008000">//</span>
										<span style="COLOR: #008000"> 两侧元素均为1</span>
										<span style="COLOR: #008000">
												<br />
												<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
										</span>
										<span style="COLOR: #000000">            a[i][i] </span>
										<span style="COLOR: #000000">=</span>
										<span style="COLOR: #000000"> a[i][</span>
										<span style="COLOR: #000000">0</span>
										<span style="COLOR: #000000">] </span>
										<span style="COLOR: #000000">=</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">1</span>
										<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            </span>
										<span style="COLOR: #0000ff">for</span>
										<span style="COLOR: #000000">(j</span>
										<span style="COLOR: #000000">=</span>
										<span style="COLOR: #000000">1</span>
										<span style="COLOR: #000000">; j</span>
										<span style="COLOR: #000000">&lt;</span>
										<span style="COLOR: #000000">i; j</span>
										<span style="COLOR: #000000">++</span>
										<span style="COLOR: #000000">)<br /><img id="Codehighlighter1_532_597_Open_Image" onclick="this.style.display='none'; Codehighlighter1_532_597_Open_Text.style.display='none'; Codehighlighter1_532_597_Closed_Image.style.display='inline'; Codehighlighter1_532_597_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_532_597_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_532_597_Closed_Text.style.display='none'; Codehighlighter1_532_597_Open_Image.style.display='inline'; Codehighlighter1_532_597_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />            </span>
										<span id="Codehighlighter1_532_597_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
												<img src="http://www.cppblog.com/images/dot.gif" />
										</span>
										<span id="Codehighlighter1_532_597_Open_Text">
												<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />                a[i][j] </span>
												<span style="COLOR: #000000">=</span>
												<span style="COLOR: #000000"> a[i</span>
												<span style="COLOR: #000000">-</span>
												<span style="COLOR: #000000">1</span>
												<span style="COLOR: #000000">][j] </span>
												<span style="COLOR: #000000">+</span>
												<span style="COLOR: #000000"> a[i</span>
												<span style="COLOR: #000000">-</span>
												<span style="COLOR: #000000">1</span>
												<span style="COLOR: #000000">][j</span>
												<span style="COLOR: #000000">-</span>
												<span style="COLOR: #000000">1</span>
												<span style="COLOR: #000000">];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />            }</span>
										</span>
										<span style="COLOR: #000000">
												<br />
												<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
								<span style="COLOR: #0000ff">for</span>
								<span style="COLOR: #000000"> (i</span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000">0</span>
								<span style="COLOR: #000000">; i</span>
								<span style="COLOR: #000000">&lt;</span>
								<span style="COLOR: #000000">n; i</span>
								<span style="COLOR: #000000">++</span>
								<span style="COLOR: #000000">)<br /><img id="Codehighlighter1_645_787_Open_Image" onclick="this.style.display='none'; Codehighlighter1_645_787_Open_Text.style.display='none'; Codehighlighter1_645_787_Closed_Image.style.display='inline'; Codehighlighter1_645_787_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_645_787_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_645_787_Closed_Text.style.display='none'; Codehighlighter1_645_787_Open_Image.style.display='inline'; Codehighlighter1_645_787_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span>
								<span id="Codehighlighter1_645_787_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.cppblog.com/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_645_787_Open_Text">
										<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            </span>
										<span style="COLOR: #0000ff">for</span>
										<span style="COLOR: #000000">(j</span>
										<span style="COLOR: #000000">=</span>
										<span style="COLOR: #000000">0</span>
										<span style="COLOR: #000000">; j</span>
										<span style="COLOR: #000000">&lt;=</span>
										<span style="COLOR: #000000">i; j</span>
										<span style="COLOR: #000000">++</span>
										<span style="COLOR: #000000">)<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />                cout </span>
										<span style="COLOR: #000000">&lt;&lt;</span>
										<span style="COLOR: #000000"> setw(</span>
										<span style="COLOR: #000000">80</span>
										<span style="COLOR: #000000">/</span>
										<span style="COLOR: #000000">n) </span>
										<span style="COLOR: #000000">&lt;&lt;</span>
										<span style="COLOR: #000000"> a[i][j];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            cout </span>
										<span style="COLOR: #000000">&lt;&lt;</span>
										<span style="COLOR: #000000"> endl;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            delete[] a[i];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        delete []a;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
<img src ="http://www.cppblog.com/andxie99/aggbug/13479.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-10-09 11:06 <a href="http://www.cppblog.com/andxie99/archive/2006/10/09/13479.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>将动态二维数组的函数模板封成了类</title><link>http://www.cppblog.com/andxie99/archive/2006/09/28/13117.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Thu, 28 Sep 2006 07:44:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/09/28/13117.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/13117.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/09/28/13117.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/13117.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/13117.html</trackback:ping><description><![CDATA[
		<p>将上一篇的动态数组的函数模板封成了类，但没有错误处理等。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">iostream</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">string</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">using</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">namespace</span>
				<span style="COLOR: #000000"> std;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> TDArray<br /><img id="Codehighlighter1_93_325_Open_Image" onclick="this.style.display='none'; Codehighlighter1_93_325_Open_Text.style.display='none'; Codehighlighter1_93_325_Closed_Image.style.display='inline'; Codehighlighter1_93_325_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_93_325_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_93_325_Closed_Text.style.display='none'; Codehighlighter1_93_325_Open_Image.style.display='inline'; Codehighlighter1_93_325_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_93_325_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_93_325_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    TDArray(</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> rows, </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> cols);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #000000">~</span>
						<span style="COLOR: #000000">TDArray();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    template</span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #0000ff">class</span>
						<span style="COLOR: #000000"> Tt</span>
						<span style="COLOR: #000000">&gt;</span>
						<span style="COLOR: #000000"> friend ostream</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">operator</span>
						<span style="COLOR: #000000">&lt;&lt;</span>
						<span style="COLOR: #000000">( ostream</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000"> output, </span>
						<span style="COLOR: #0000ff">const</span>
						<span style="COLOR: #000000"> TDArray</span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000">Tt</span>
						<span style="COLOR: #000000">&gt;&amp;</span>
						<span style="COLOR: #000000"> tdArray );<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    T</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">operator</span>
						<span style="COLOR: #000000">[](</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> rows);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span>
						<span style="COLOR: #0000ff">private</span>
						<span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> Init();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    T </span>
						<span style="COLOR: #000000">**</span>
						<span style="COLOR: #000000">p;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> m_rows;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> m_cols;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />TDArray</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">::TDArray(</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> rows, </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> cols)<br /><img id="Codehighlighter1_387_536_Open_Image" onclick="this.style.display='none'; Codehighlighter1_387_536_Open_Text.style.display='none'; Codehighlighter1_387_536_Closed_Image.style.display='inline'; Codehighlighter1_387_536_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_387_536_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_387_536_Closed_Text.style.display='none'; Codehighlighter1_387_536_Open_Image.style.display='inline'; Codehighlighter1_387_536_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_387_536_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_387_536_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    m_rows </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> rows;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    m_cols </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> cols;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> 创建行指针</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #000000">    p </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">new</span>
						<span style="COLOR: #000000"> T</span>
						<span style="COLOR: #000000">*</span>
						<span style="COLOR: #000000">[rows];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> 为每一行分配空间</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #000000">    </span>
						<span style="COLOR: #0000ff">for</span>
						<span style="COLOR: #000000"> (</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> i</span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">; i</span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000">rows; </span>
						<span style="COLOR: #000000">++</span>
						<span style="COLOR: #000000">i)<br /><img id="Codehighlighter1_492_517_Open_Image" onclick="this.style.display='none'; Codehighlighter1_492_517_Open_Text.style.display='none'; Codehighlighter1_492_517_Closed_Image.style.display='inline'; Codehighlighter1_492_517_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_492_517_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_492_517_Closed_Text.style.display='none'; Codehighlighter1_492_517_Open_Image.style.display='inline'; Codehighlighter1_492_517_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_492_517_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_492_517_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        p[i] </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">new</span>
								<span style="COLOR: #000000"> T[cols];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> 初始化</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #000000">    Init();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />TDArray</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">::</span>
				<span style="COLOR: #000000">~</span>
				<span style="COLOR: #000000">TDArray()<br /><img id="Codehighlighter1_580_656_Open_Image" onclick="this.style.display='none'; Codehighlighter1_580_656_Open_Text.style.display='none'; Codehighlighter1_580_656_Closed_Image.style.display='inline'; Codehighlighter1_580_656_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_580_656_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_580_656_Closed_Text.style.display='none'; Codehighlighter1_580_656_Open_Image.style.display='inline'; Codehighlighter1_580_656_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_580_656_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_580_656_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">for</span>
						<span style="COLOR: #000000"> (</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> x</span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">; x</span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000">m_rows; </span>
						<span style="COLOR: #000000">++</span>
						<span style="COLOR: #000000">x)<br /><img id="Codehighlighter1_613_633_Open_Image" onclick="this.style.display='none'; Codehighlighter1_613_633_Open_Text.style.display='none'; Codehighlighter1_613_633_Closed_Image.style.display='inline'; Codehighlighter1_613_633_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_613_633_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_613_633_Closed_Text.style.display='none'; Codehighlighter1_613_633_Open_Image.style.display='inline'; Codehighlighter1_613_633_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_613_633_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_613_633_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        delete[] p[x];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    delete[] p;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    p </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />inline </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> TDArray</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">::Init()<br /><img id="Codehighlighter1_708_803_Open_Image" onclick="this.style.display='none'; Codehighlighter1_708_803_Open_Text.style.display='none'; Codehighlighter1_708_803_Closed_Image.style.display='inline'; Codehighlighter1_708_803_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_708_803_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_708_803_Closed_Text.style.display='none'; Codehighlighter1_708_803_Open_Image.style.display='inline'; Codehighlighter1_708_803_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_708_803_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_708_803_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">for</span>
						<span style="COLOR: #000000"> (</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> x</span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">; x</span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000">m_rows; </span>
						<span style="COLOR: #000000">++</span>
						<span style="COLOR: #000000">x)<br /><img id="Codehighlighter1_741_801_Open_Image" onclick="this.style.display='none'; Codehighlighter1_741_801_Open_Text.style.display='none'; Codehighlighter1_741_801_Closed_Image.style.display='inline'; Codehighlighter1_741_801_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_741_801_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_741_801_Closed_Text.style.display='none'; Codehighlighter1_741_801_Open_Image.style.display='inline'; Codehighlighter1_741_801_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_741_801_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_741_801_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
								<span style="COLOR: #0000ff">for</span>
								<span style="COLOR: #000000"> (</span>
								<span style="COLOR: #0000ff">int</span>
								<span style="COLOR: #000000"> y</span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000">0</span>
								<span style="COLOR: #000000">; y</span>
								<span style="COLOR: #000000">&lt;</span>
								<span style="COLOR: #000000">m_cols; </span>
								<span style="COLOR: #000000">++</span>
								<span style="COLOR: #000000">y)<br /><img id="Codehighlighter1_776_798_Open_Image" onclick="this.style.display='none'; Codehighlighter1_776_798_Open_Text.style.display='none'; Codehighlighter1_776_798_Closed_Image.style.display='inline'; Codehighlighter1_776_798_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_776_798_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_776_798_Closed_Text.style.display='none'; Codehighlighter1_776_798_Open_Image.style.display='inline'; Codehighlighter1_776_798_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span>
								<span id="Codehighlighter1_776_798_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.cppblog.com/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_776_798_Open_Text">
										<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            p[x][y] </span>
										<span style="COLOR: #000000">=</span>
										<span style="COLOR: #000000"> T();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />ostream</span>
				<span style="COLOR: #000000">&amp;</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">operator</span>
				<span style="COLOR: #000000">&lt;&lt;</span>
				<span style="COLOR: #000000">( ostream</span>
				<span style="COLOR: #000000">&amp;</span>
				<span style="COLOR: #000000"> output, </span>
				<span style="COLOR: #0000ff">const</span>
				<span style="COLOR: #000000"> TDArray</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">T</span>
				<span style="COLOR: #000000">&gt;&amp;</span>
				<span style="COLOR: #000000"> tdArray )<br /><img id="Codehighlighter1_890_1086_Open_Image" onclick="this.style.display='none'; Codehighlighter1_890_1086_Open_Text.style.display='none'; Codehighlighter1_890_1086_Closed_Image.style.display='inline'; Codehighlighter1_890_1086_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_890_1086_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_890_1086_Closed_Text.style.display='none'; Codehighlighter1_890_1086_Open_Image.style.display='inline'; Codehighlighter1_890_1086_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_890_1086_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_890_1086_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">for</span>
						<span style="COLOR: #000000"> (</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> x</span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">; x</span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000">tdArray.m_rows; </span>
						<span style="COLOR: #000000">++</span>
						<span style="COLOR: #000000">x)<br /><img id="Codehighlighter1_931_1068_Open_Image" onclick="this.style.display='none'; Codehighlighter1_931_1068_Open_Text.style.display='none'; Codehighlighter1_931_1068_Closed_Image.style.display='inline'; Codehighlighter1_931_1068_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_931_1068_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_931_1068_Closed_Text.style.display='none'; Codehighlighter1_931_1068_Open_Image.style.display='inline'; Codehighlighter1_931_1068_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_931_1068_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_931_1068_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
								<span style="COLOR: #0000ff">for</span>
								<span style="COLOR: #000000"> (</span>
								<span style="COLOR: #0000ff">int</span>
								<span style="COLOR: #000000"> y</span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000">0</span>
								<span style="COLOR: #000000">; y</span>
								<span style="COLOR: #000000">&lt;</span>
								<span style="COLOR: #000000">tdArray.m_cols; </span>
								<span style="COLOR: #000000">++</span>
								<span style="COLOR: #000000">y)<br /><img id="Codehighlighter1_974_1047_Open_Image" onclick="this.style.display='none'; Codehighlighter1_974_1047_Open_Text.style.display='none'; Codehighlighter1_974_1047_Closed_Image.style.display='inline'; Codehighlighter1_974_1047_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_974_1047_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_974_1047_Closed_Text.style.display='none'; Codehighlighter1_974_1047_Open_Image.style.display='inline'; Codehighlighter1_974_1047_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span>
								<span id="Codehighlighter1_974_1047_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.cppblog.com/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_974_1047_Open_Text">
										<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            output </span>
										<span style="COLOR: #000000">&lt;&lt;</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">"</span>
										<span style="COLOR: #000000">[</span>
										<span style="COLOR: #000000">"</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">&lt;&lt;</span>
										<span style="COLOR: #000000"> x </span>
										<span style="COLOR: #000000">&lt;&lt;</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">"</span>
										<span style="COLOR: #000000">][</span>
										<span style="COLOR: #000000">"</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">&lt;&lt;</span>
										<span style="COLOR: #000000"> y </span>
										<span style="COLOR: #000000">&lt;&lt;</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">"</span>
										<span style="COLOR: #000000">]</span>
										<span style="COLOR: #000000">"</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">&lt;&lt;</span>
										<span style="COLOR: #000000"> tdArray.p[x][y] </span>
										<span style="COLOR: #000000">&lt;&lt;</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">"</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">"</span>
										<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        output </span>
								<span style="COLOR: #000000">&lt;&lt;</span>
								<span style="COLOR: #000000"> endl;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> output;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />inline T</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> TDArray</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">::</span>
				<span style="COLOR: #0000ff">operator</span>
				<span style="COLOR: #000000">[](</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> rows)<br /><img id="Codehighlighter1_1150_1169_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1150_1169_Open_Text.style.display='none'; Codehighlighter1_1150_1169_Closed_Image.style.display='inline'; Codehighlighter1_1150_1169_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_1150_1169_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1150_1169_Closed_Text.style.display='none'; Codehighlighter1_1150_1169_Open_Image.style.display='inline'; Codehighlighter1_1150_1169_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_1150_1169_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_1150_1169_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> p[rows];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> main(</span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000">)<br /><img id="Codehighlighter1_1186_1299_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1186_1299_Open_Text.style.display='none'; Codehighlighter1_1186_1299_Closed_Image.style.display='inline'; Codehighlighter1_1186_1299_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_1186_1299_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1186_1299_Closed_Text.style.display='none'; Codehighlighter1_1186_1299_Open_Image.style.display='inline'; Codehighlighter1_1186_1299_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_1186_1299_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_1186_1299_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    TDArray</span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000">&gt;</span>
						<span style="COLOR: #000000"> iArray </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> TDArray</span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000">&gt;</span>
						<span style="COLOR: #000000">(</span>
						<span style="COLOR: #000000">2</span>
						<span style="COLOR: #000000">, </span>
						<span style="COLOR: #000000">3</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    iArray[</span>
						<span style="COLOR: #000000">1</span>
						<span style="COLOR: #000000">][</span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">] </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">100</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    cout </span>
						<span style="COLOR: #000000">&lt;&lt;</span>
						<span style="COLOR: #000000"> iArray;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    system(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">pause</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
		</div>
<img src ="http://www.cppblog.com/andxie99/aggbug/13117.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-09-28 15:44 <a href="http://www.cppblog.com/andxie99/archive/2006/09/28/13117.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>写了一个二维动态数组的函数模板</title><link>http://www.cppblog.com/andxie99/archive/2006/09/28/13077.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Thu, 28 Sep 2006 01:58:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/09/28/13077.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/13077.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/09/28/13077.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/13077.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/13077.html</trackback:ping><description><![CDATA[    写了一个二维动态数组的函数模板，可以将它封成类使用。<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000"> std;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 初始化动态数组</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> Init2DArray(T</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">p, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> rows, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> cols)<br /><img id="Codehighlighter1_136_227_Open_Image" onclick="this.style.display='none'; Codehighlighter1_136_227_Open_Text.style.display='none'; Codehighlighter1_136_227_Closed_Image.style.display='inline'; Codehighlighter1_136_227_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_136_227_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_136_227_Closed_Text.style.display='none'; Codehighlighter1_136_227_Open_Image.style.display='inline'; Codehighlighter1_136_227_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_136_227_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_136_227_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> x</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; x</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">rows; </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">x)<br /><img id="Codehighlighter1_167_225_Open_Image" onclick="this.style.display='none'; Codehighlighter1_167_225_Open_Text.style.display='none'; Codehighlighter1_167_225_Closed_Image.style.display='inline'; Codehighlighter1_167_225_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_167_225_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_167_225_Closed_Text.style.display='none'; Codehighlighter1_167_225_Open_Image.style.display='inline'; Codehighlighter1_167_225_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_167_225_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_167_225_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> y</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; y</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">cols; </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">y)<br /><img id="Codehighlighter1_200_222_Open_Image" onclick="this.style.display='none'; Codehighlighter1_200_222_Open_Text.style.display='none'; Codehighlighter1_200_222_Closed_Image.style.display='inline'; Codehighlighter1_200_222_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_200_222_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_200_222_Closed_Text.style.display='none'; Codehighlighter1_200_222_Open_Image.style.display='inline'; Codehighlighter1_200_222_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span id="Codehighlighter1_200_222_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_200_222_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            p[x][y] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> T();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 动态创建 2 维数组模板</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> Create2DArray(T</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">p, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> rows, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> cols)<br /><img id="Codehighlighter1_311_449_Open_Image" onclick="this.style.display='none'; Codehighlighter1_311_449_Open_Text.style.display='none'; Codehighlighter1_311_449_Closed_Image.style.display='inline'; Codehighlighter1_311_449_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_311_449_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_311_449_Closed_Text.style.display='none'; Codehighlighter1_311_449_Open_Image.style.display='inline'; Codehighlighter1_311_449_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_311_449_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_311_449_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 创建行指针</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    p </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> [rows];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 为每一行分配空间</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">rows; </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">i)<br /><img id="Codehighlighter1_385_410_Open_Image" onclick="this.style.display='none'; Codehighlighter1_385_410_Open_Text.style.display='none'; Codehighlighter1_385_410_Closed_Image.style.display='inline'; Codehighlighter1_385_410_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_385_410_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_385_410_Closed_Text.style.display='none'; Codehighlighter1_385_410_Open_Image.style.display='inline'; Codehighlighter1_385_410_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_385_410_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_385_410_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        p[i] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> T[cols];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 初始化</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    Init2DArray(p, rows, cols);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 删除动态数组</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> Delete2DArray(T</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">p, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> rows)<br /><img id="Codehighlighter1_517_613_Open_Image" onclick="this.style.display='none'; Codehighlighter1_517_613_Open_Text.style.display='none'; Codehighlighter1_517_613_Closed_Image.style.display='inline'; Codehighlighter1_517_613_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_517_613_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_517_613_Closed_Text.style.display='none'; Codehighlighter1_517_613_Open_Image.style.display='inline'; Codehighlighter1_517_613_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_517_613_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_517_613_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 释放每一行的空间</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">rows; </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">i)<br /><img id="Codehighlighter1_561_581_Open_Image" onclick="this.style.display='none'; Codehighlighter1_561_581_Open_Text.style.display='none'; Codehighlighter1_561_581_Closed_Image.style.display='inline'; Codehighlighter1_561_581_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_561_581_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_561_581_Closed_Text.style.display='none'; Codehighlighter1_561_581_Open_Image.style.display='inline'; Codehighlighter1_561_581_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_561_581_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_561_581_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        delete[] p[i];<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 删除指针</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    delete[] p;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    p </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 显示动态数组</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> Show2DArray(T</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">p, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> rows, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> cols, </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000"> arrayName </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">p</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_713_877_Open_Image" onclick="this.style.display='none'; Codehighlighter1_713_877_Open_Text.style.display='none'; Codehighlighter1_713_877_Closed_Image.style.display='inline'; Codehighlighter1_713_877_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_713_877_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_713_877_Closed_Text.style.display='none'; Codehighlighter1_713_877_Open_Image.style.display='inline'; Codehighlighter1_713_877_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_713_877_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_713_877_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> x</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; x</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">rows; </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">x)<br /><img id="Codehighlighter1_744_875_Open_Image" onclick="this.style.display='none'; Codehighlighter1_744_875_Open_Text.style.display='none'; Codehighlighter1_744_875_Closed_Image.style.display='inline'; Codehighlighter1_744_875_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_744_875_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_744_875_Closed_Text.style.display='none'; Codehighlighter1_744_875_Open_Image.style.display='inline'; Codehighlighter1_744_875_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_744_875_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_744_875_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> y</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; y</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">cols; </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">y)<br /><img id="Codehighlighter1_777_856_Open_Image" onclick="this.style.display='none'; Codehighlighter1_777_856_Open_Text.style.display='none'; Codehighlighter1_777_856_Closed_Image.style.display='inline'; Codehighlighter1_777_856_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_777_856_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_777_856_Closed_Text.style.display='none'; Codehighlighter1_777_856_Open_Image.style.display='inline'; Codehighlighter1_777_856_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span id="Codehighlighter1_777_856_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_777_856_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            cout </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> arrayName </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">[</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> x </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">][</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> y </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">] = </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> p[x][y] </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        cout </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> endl;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_895_1369_Open_Image" onclick="this.style.display='none'; Codehighlighter1_895_1369_Open_Text.style.display='none'; Codehighlighter1_895_1369_Closed_Image.style.display='inline'; Codehighlighter1_895_1369_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_895_1369_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_895_1369_Closed_Text.style.display='none'; Codehighlighter1_895_1369_Open_Image.style.display='inline'; Codehighlighter1_895_1369_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_895_1369_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_895_1369_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 测试模板函数</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">**</span><span style="COLOR: #000000">pInt;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">**</span><span style="COLOR: #000000">pChar;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">float</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">**</span><span style="COLOR: #000000">pFloat;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> rows </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> cols </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    Create2DArray(pInt, rows, cols);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    pInt[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">][</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    pInt[</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">][</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    Show2DArray(pInt, rows, cols, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pInt</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    Delete2DArray(pInt, rows);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    Create2DArray(pChar, rows, cols);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    Show2DArray(pChar, rows, cols, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pChar</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    Delete2DArray(pChar, rows);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    Create2DArray(pFloat, rows, cols);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    Show2DArray(pFloat, rows, cols, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pFloat</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    Delete2DArray(pFloat, rows);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    system(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pause</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div><img src ="http://www.cppblog.com/andxie99/aggbug/13077.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-09-28 09:58 <a href="http://www.cppblog.com/andxie99/archive/2006/09/28/13077.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Bjarne Stroustrup语录[C++经验]</title><link>http://www.cppblog.com/andxie99/archive/2006/09/28/13071.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Thu, 28 Sep 2006 00:23:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/09/28/13071.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/13071.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/09/28/13071.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/13071.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/13071.html</trackback:ping><description><![CDATA[<br>
<div>摘录自Bjarne Stroustrup 的《The C++ Programming Language》(Special Edition) <br><br>一、致读者<br><br>1．&nbsp;&nbsp;在编程序时，你是在为你针对某个问题的解决方案中的思想建立起一种具体表示。让程序的结构尽可能地直接反映这些思想：<br>&nbsp;&nbsp;&nbsp;★.如果你能把&#8220;它&#8221;看成一个独立的概念，就把它做成一个类。<br>&nbsp;&nbsp;&nbsp;★.如果你能把&#8220;它&#8221;看成一个独立的实体，就把它做成某个类的一个对象。<br>&nbsp;&nbsp;&nbsp;★.如果两个类有共同的Interface，将此Interface做成一个抽象类。<br>&nbsp;&nbsp;&nbsp;★.如果两个类的实现有某些显著的共同东西，将这些共性做成一个基类。<br>&nbsp;&nbsp;&nbsp;★.如果一个类是一种对象的容器，将它做成一个模板。<br>&nbsp;&nbsp;&nbsp;★.如果一个函数实现对某容器的一个算法，将它做成为对一族容器可用的模板函数。<br>&nbsp;&nbsp;&nbsp;★.如果一组类、模板等相互之间有逻辑联系，将它们放进一个名字空间里。<br><br>2．&nbsp;&nbsp;在你定义一个并不是实现某个像矩阵或复数这样的数学对象的类时，或者定义一个低层的类型如链接表的时候：<br>&nbsp;&nbsp;&nbsp;★.不要使用全局数据（使用成员）。<br>&nbsp;&nbsp;&nbsp;★.不要使用全局函数。<br>&nbsp;&nbsp;&nbsp;★.不要使用公用数据成员。<br>&nbsp;&nbsp;&nbsp;★.不要使用友元，除非为了避免a或c。<br>&nbsp;&nbsp;&nbsp;★.不要在一个类里面放&#8220;类型域&#8221;（指那种为了说明一个类所存储数据的情况而放置的标志域） ；采用虚函数。<br>&nbsp;&nbsp;&nbsp;★.不要使用在线函数(inline function)，除非作为效果显著的优化。<br><br>二、C++ 概览<br><br>1．&nbsp;&nbsp;不用害怕，一切都会随着时间的推移而逐渐明朗起来。<br>2．&nbsp;&nbsp;你并不需要在知道了C++的所有细节之后才能写出好的C++程序。<br>3．&nbsp;&nbsp;请特别关注程序设计技术，而不是各种语言特征。<br><br>三、标准库概览<br><br>1．&nbsp;&nbsp;不要像重新发明车轮那样企图做每件事；去使用库。<br>2．&nbsp;&nbsp;不要相信奇迹；要理解你的库能做什么，它们如何做，它们做时需要多大的代价。<br>3．&nbsp;&nbsp;当你遇到一个选择时，应该优先选择标准库而不是其他的库。<br>4．&nbsp;&nbsp;不要认为标准库对于任何事情都是最理想的。<br>5．&nbsp;&nbsp;切记#include 你所用到的功能的头文件。<br>6．&nbsp;&nbsp;记住，标准库的功能定义在名字空间std之中。<br>7．&nbsp;&nbsp;请用string，而不是char*。<br>8．&nbsp;&nbsp;如果怀疑，就用一个检查区间范围的向量（例如Vec）。<br>9．&nbsp;&nbsp;vector<t> 、list<t>和 map<key,value> 都比T[] 好。<br>10． 如果向一个容器中添加一个元素，用push_back() 或 back_inserter()。<br>11． 采用对vector的push_back()，而不是对数组的realloc()。<br>12． 在main()中捕捉公共的异常。<br><br>四、类型和声明<br><br>1．&nbsp;&nbsp;保持较小的作用域。<br>2．&nbsp;&nbsp;不要在一个作用域和它外围的作用域里采用同样的名字。<br>3．&nbsp;&nbsp;在一个声明中只声明一个名字。<br>4．&nbsp;&nbsp;让常用的和局部的名字比较短，让不常用的和全局的名字比较长。<br>5．&nbsp;&nbsp;避免看起来类似的名字。<br>6．&nbsp;&nbsp;维持某种统一的命名风格。<br>7．&nbsp;&nbsp;仔细选择名字，反映其意义而不是反映实现方式。<br>8．&nbsp;&nbsp;如果所用的内部类型表示某种可能变化的值，请用typedef 为它定义一个有意义的名字。<br>9．&nbsp;&nbsp;用typedef为类型定义同义词，用枚举或类去定义新类型。<br>10． 切记每个声明中都必须描述一个类型（没有&#8220;隐式的int&#8221;）。<br>11． 避免有关字符数值的不必要假设。<br>12． 避免有关整数大小的不必要假设。<br>13． 避免有关浮点类型表示范围的不必要假设。<br>14． 优先使用普通的int 而不是short int 或者long int。<br>15． 优先使用double 而不是float 或者long double。<br>16． 优先使用普通的 char 而不是 signed char或者 unsigned char。<br>17． 避免做出有关对象大小的不必要假设。<br>18． 避免无符号算术。<br>19． 应该带着疑问去看待从signed 到unsigned ，或者从unsigned 到signed 的转换。<br>20． 应该带着疑问去看待从浮点到整型的转换。<br>21． 应该带着疑问去看待向较小类型的转换，如将int转换到char。<br><br>五、忠告<br><br>1．&nbsp;&nbsp;避免非平凡的指针算术。<br>2．&nbsp;&nbsp;当心，不要超出数组的界线去写。<br>3．&nbsp;&nbsp;尽量使用0而不是NULL。<br>4．&nbsp;&nbsp;尽量使用vector 和valarray ，而不是内部（C风格）的数组。<br>5．&nbsp;&nbsp;尽量使用string而不是以0结尾的char 数组。<br>6．&nbsp;&nbsp;尽量少用普通的引用参数。<br>7．&nbsp;&nbsp;避免 void*，除了在某些低级代码里。<br>8．&nbsp;&nbsp;避免在代码中使用非平凡的文字量（&#8220;神秘的数&#8221;）。相反，应该定义和使用各种符号常量。</key,value></t></t></div>
<img src ="http://www.cppblog.com/andxie99/aggbug/13071.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-09-28 08:23 <a href="http://www.cppblog.com/andxie99/archive/2006/09/28/13071.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对指针的认识</title><link>http://www.cppblog.com/andxie99/archive/2006/08/10/11077.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Thu, 10 Aug 2006 01:56:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/08/10/11077.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/11077.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/08/10/11077.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/11077.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/11077.html</trackback:ping><description><![CDATA[<br>对指针的认识：<br>
<p>&nbsp;&nbsp;&nbsp; 每个指针都有一个相关的类型。不同数据类型的指针之间的区别不是在指针的表示上，也不在指针所持有的值（地址）上——对所有类型的指针这两方面都是相同的。不同之处在于指针所指的对象的类型上。指针的类型可以指示编译器怎样解释特定地址上内存的内容，以及该内存区域应该跨越多少内存单元。当指针持有0值时，表明它没有指向任何对象。</p>
<p>&nbsp;&nbsp;&nbsp; 指针不能被初始化或赋值为其他类型对象的地址值。例如：不是说int类型的指针在物理上不能持有与double相关联内存的地址，它能够。但是不允许，因为虽然int型的指针和double型的指针能够持有同样的地址值，但对那块内存的存储布局和内容的解释却完全不同。</p>
<p>&nbsp;&nbsp;&nbsp; 当然，如果我们要做的仅仅是持有地址值（可能是把一个地址同另一个地址作比较），那么指针的实际类型就不重要了。C++提供了一种特殊的指针类型来支持这种需求：空（void*）类型指针，它可以被任何数据指针类型的地址值赋值（函数指针不能赋值给它）。</p>
<p>&nbsp;&nbsp;&nbsp; void*表明相关的值是个地址，但该地址的对象类型不知道。我们不能够操作空类型指针所指向的对象，只能传送该地址值或将它与其他地址值作比较。</p>
<p>&nbsp;&nbsp;&nbsp; 指针可以让它的地址值增加或减少一个整数值，例如：加法指针加2意味着给指针持有的地址值增加了该类型两个对象的长度。</p>
<img src ="http://www.cppblog.com/andxie99/aggbug/11077.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-08-10 09:56 <a href="http://www.cppblog.com/andxie99/archive/2006/08/10/11077.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unicode初探</title><link>http://www.cppblog.com/andxie99/archive/2006/08/08/10973.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Tue, 08 Aug 2006 04:10:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/08/08/10973.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/10973.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/08/08/10973.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/10973.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/10973.html</trackback:ping><description><![CDATA[<p><strong>Char数据型态</strong> <br></p>
<p>假定我们都非常熟悉在C程序中使用char数据型态来定义和储存字符跟字符串。但为了便于理解C如何处理宽字符，让我们先回顾一下可能在Win32程序中出现的标准字符定义。</p>
<p>下面的语句定义并初始化了一个只包含一个字符的变量：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">char c = 'A' ;
</pre>
</div>
<p>变量c需要1个字节来保存，并将用十六进制数0x41初始化，这是字母A的ASCII代码。</p>
<p>您可以像这样定义一个指向字符串的指针：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">char * p ;
</pre>
</div>
<p>因为Windows是一个32位操作系统，所以指针变量p需要用4个字节保存。您还可初始化一个指向字符串的指针：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">char * p = "Hello!" ;
</pre>
</div>
<p>像前面一样，变量p也需要用4个字节保存。该字符串保存在静态内存中并占用7个字节－6个字节保存字符串，另1个字节保存终止符号0。</p>
<p>您还可以像这样定义字符数组：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">char a[10] ;
</pre>
</div>
<p>在这种情况下，编译器为该数组保留了10个字节的储存空间。表达式sizeof（a）将返回10。如果数组是整体变量（即在所有函数外定义），您可使用像下面的语句来初始化一个字符数组：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">char a[] = "Hello!" ;
</pre>
</div>
<p>如果您将该数组定义为一个函数的区域变量，则必须将它定义为一个static变量，如下：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">static char a[] = "Hello!" ;
</pre>
</div>
<p>无论哪种情况，字符串都储存在静态程序内存中，并在末尾添加0，这样就需要7个字节的储存空间。</p>
<p><strong>宽字符</strong> <br></p>
<p>Unicode或者宽字符都没有改变char数据型态在C中的含义。char继续表示1个字节的储存空间，sizeof （char）继续返回1。理论上，C中1个字节可比8位长，但对我们大多数人来说，1个字节（也就是1个char）是8位宽。</p>
<p>C中的宽字符基于wchar_t数据型态，它在几个表头文件包括WCHAR.H中都有定义，像这样：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">typedef unsigned short wchar_t ;
</pre>
</div>
<p>因此，wchar_t数据型态与无符号短整数型态相同，都是16位宽。</p>
<p>要定义包含一个宽字符的变量，可使用下面的语句：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">wchar_t c = 'A' ;
</pre>
</div>
<p>变量c是一个双字节值0x0041，是Unicode表示的字母A。（然而，因为Intel微处理器从最小的字节开始储存多字节数值，该字节实际上是以0x41、0x00的顺序保存在内存中。如果检查Unicode文字的计算机储存应注意这一点。）</p>
<p>您还可定义指向宽字符串的指针：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">wchar_t * p = L"Hello!" ;
</pre>
</div>
<p>注意紧接在第一个引号前面的大写字母L（代表「long」）。这将告诉编译器该字符串按宽字符保存－即每个字符占用2个字节。通常，指针变量p要占用4个字节，而字符串变量需要14个字节－每个字符需要2个字节，末尾的0还需要2个字节。</p>
<p>同样，您还可以用下面的语句定义宽字符数组：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">static wchar_t a[] = L"Hello!" ;
</pre>
</div>
<p>该字符串也需要14个字节的储存空间，sizeof (a) 将返回14。索引数组a可得到单独的字符。a[1] 的值是宽字符「e」，或者0x0065。</p>
<p>虽然看上去更像一个印刷符号，但第一个引号前面的L非常重要，并且在两个符号之间必须没有空格。只有带有L，编译器才知道您需要将字符串存为每个字符2字节。稍后，当我们看到使用宽字符串而不是变量定义时，您还会遇到第一个引号前面的L。幸运的是，如果忘记了包含L，C编译器通常会给提出警告或错误信息。</p>
<p>您还可在单个字符文字前面使用L前缀，来表示它们应解释为宽字符。如下所示：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">wchar_t c = L'A' ;
</pre>
</div>
<p>但通常这是不必要的，C编译器会对该字符进行扩充，使它成为宽字符。</p>
<p><strong>宽字符链接库函数</strong> <br></p>
<p>我们都知道如何获得字符串的长度。例如，如果我们已经像下面这样定义了一个字符串指针：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">char * pc = "Hello!" ;
</pre>
</div>
<p>我们可以呼叫</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">iLength = strlen (pc) ;
</pre>
</div>
<p>这时变量iLength将等于6，也就是字符串中的字符数。</p>
<p>太好了！现在让我们试着定义一个指向宽字符的指针：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">wchar_t * pw = L"Hello!" ;
</pre>
</div>
<p>再次呼叫strlen ：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">iLength = strlen (pw) ;
</pre>
</div>
<p>现在麻烦来了。首先，C编译器会显示一条警告消息，可能是这样的内容：</p>
<p>'function' : incompatible types - from 'unsigned short *' to 'const char *'</p>
<p>这条消息的意思是：声明strlen函数时，该函数应接收char类型的指标，但它现在却接收了一个unsigned short类型的指标。您仍然可编译并执行该程序，但您会发现iLength等于1。为什么？</p>
<p>字符串「Hello!」中的6个字符占用16位：</p>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">0x0048 0x0065 0x006C 0x006C 0x006F 0x0021</pre>
<p>Intel处理器在内存中将其存为：</p>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">48 00 65 00 6C 00 6C 00 6F 00 21 00</pre>
<p>假定strlen函数正试图得到一个字符串的长度，并把第1个字节作为字符开始计数，但接着假定如果下一个字节是0，则表示字符串结束。</p>
<p>这个小练习清楚地说明了C语言本身和执行时期链接库函数之间的区别。编译器将字符串L"Hello!" 解释为一组16位短整数型态数据，并将其保存在wchar_t数组中。编译器还处理数组索引和sizeof操作符，因此这些都能正常工作，但在连结时才添加执行时期链接库函数，例如strlen。这些函数认为字符串由单字节字符组成。遇到宽字符串时，函数就不像我们所希望那样执行了。</p>
<p>您可能要说：「噢，太麻烦了！」现在每个C语言链接库函数都必须重写以接受宽字符。但事实上并不是每个C语言链接库函数都需要重写，只是那些有字符串参数的函数才需要重写，而且也不用由您来完成。它们已经重写完了。</p>
<p>strlen函数的宽字符版是wcslen（wide-character string length：宽字符串长度），并且在STRING.H（其中也说明了strlen）和WCHAR.H中均有说明。strlen函数说明如下：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">size_t __cdecl strlen (const char *) ;        </pre>
</div>
<p>而wcslen函数则说明如下：</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">size_t __cdecl wcslen (const wchar_t *) ;        </pre>
</div>
<p>这时我们知道，要得到宽字符串的长度可以呼叫</p>
<div>
<pre style="BORDER-RIGHT: 1px double; PADDING-RIGHT: 4px; BORDER-TOP: 1px double; PADDING-LEFT: 4px; FONT-SIZE: 12px; PADDING-BOTTOM: 4px; BORDER-LEFT: 1px double; PADDING-TOP: 4px; BORDER-BOTTOM: 1px double; BACKGROUND-COLOR: #cccccc">iLength = wcslen (pw) ; </pre>
</div>
<p>函数将返回字符串中的字符数6。请记住，改成宽字节后，字符串的字符长度不改变，只是位组长度改变了。</p>
<p>您熟悉的所有带有字符串参数的C执行时期链接库函数都有宽字符版。例如，wprintf是printf的宽字符版。这些函数在WCHAR.H和含有标准函数说明的表头文件中说明。</p>
<img src ="http://www.cppblog.com/andxie99/aggbug/10973.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-08-08 12:10 <a href="http://www.cppblog.com/andxie99/archive/2006/08/08/10973.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>匈牙利命名法规则</title><link>http://www.cppblog.com/andxie99/archive/2006/08/08/10961.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Tue, 08 Aug 2006 02:01:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/08/08/10961.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/10961.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/08/08/10961.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/10961.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/10961.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;　　一般情况下，变量的取名方式为：&lt;scope_&gt; + &lt;prefix_&gt; + &lt;qualifier&gt;。　　范围前缀_，类型前缀_，限定词。特殊的类型命名,前缀表示： 　　类、接口                                    前缀&nbsp;&nbsp;&nbsp;      ...&nbsp;&nbsp;<a href='http://www.cppblog.com/andxie99/archive/2006/08/08/10961.html'>阅读全文</a><img src ="http://www.cppblog.com/andxie99/aggbug/10961.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-08-08 10:01 <a href="http://www.cppblog.com/andxie99/archive/2006/08/08/10961.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC的类层次结构图</title><link>http://www.cppblog.com/andxie99/archive/2006/07/12/9747.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 12 Jul 2006 07:27:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/07/12/9747.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/9747.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/07/12/9747.html#Feedback</comments><slash:comments>29</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/9747.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/9747.html</trackback:ping><description><![CDATA[整理资料，看到几张MFC的类层次结构图。也来看看MFC的发展吧：<br /><img height="1029" alt="MFC4_21.jpg" src="http://www.cppblog.com/images/cppblog_com/andxie99/MFC4_21.jpg" width="1461" border="0" /><br /><img height="724" alt="MFC6_0.JPG" src="http://www.cppblog.com/images/cppblog_com/andxie99/MFC6_0.JPG" width="1000" border="0" /><br /><img height="1081" alt="MFC7_0.JPG" src="http://www.cppblog.com/images/cppblog_com/andxie99/MFC7_0.JPG" width="1417" border="0" /><img src ="http://www.cppblog.com/andxie99/aggbug/9747.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-07-12 15:27 <a href="http://www.cppblog.com/andxie99/archive/2006/07/12/9747.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC编程综述</title><link>http://www.cppblog.com/andxie99/archive/2006/07/11/9672.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Tue, 11 Jul 2006 01:54:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/07/11/9672.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/9672.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/07/11/9672.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/9672.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/9672.html</trackback:ping><description><![CDATA[
		<p> </p>
		<p>摘一段以前的文章，原文作者：苟建兵 清华大学热能系(北京，100084)。原文很长，这里只摘了一段。<br /><br />采用MFC开发Windows程序之所以能够大幅度提高开发速度和效率主要是因为MFC在类<br />层次封装了大量Windows SDK函数和典型Windows应用的缺省处理，这样，用户只需<br />要较少的编程就可以实现自己的开发任务。如果在MFC基础上再配合Visual C++提供<br />的AppWizard、ClassWizard和AppStudio工具那么更可以大幅度加快开发进程。MFC<br />提供大量的基类供程序员使用，常见的如CWinApp类、CFrameWnd类、CMDIFrameWnd<br />类、CMDIChildWnd类、CView类、CDC类和CDocument类等等。通过从这些基类中派生<br />出用户自己的类，然后重载特殊的几个函数就可以生成一个独立的应用程序。可以<br />说，采用MFC编写Windows应用程序是非常方便的，虽然其学习过程并不简单，但是<br />其提供的灵活高效性足以使任何Windows程序开发人员为之付出努力。如果用户不曾<br />使用过MFC，那么用户可以通过附录中所列的参考书去学习MFC的强大功能。<br />采用MFC应用框架产生的应用程序使用了标准化的结构，因而使得采用MFC编写的程<br />序的在不同平台上的移植变得非常容易，事实上，MFC的16位和32位版本之间差别很<br />小。MFC提供的标准化结构是经过众多专家分析调研后总结编写出来的，一般情况下<br />可以满足绝大多数用户的要求，但有时用户也可以通过重载一些函数来修改其缺省<br />的风格从而实现自己特有的风格，如自定义应用图表和灰色背景等。在MFC提供的文<br />档视结构中，文档、视和资源之间的联系是通过定义文档模板来实现的，如：<br />m_pSimuTemplate = new CMultiDocTemplate(<br />IDR_SIMUTYPE,<br />RUNTIME_CLASS(CSimuDoc),<br />RUNTIME_CLASS(CMyChild), // Derived MDI child frame<br />RUNTIME_CLASS(CSimuView));<br />上中第一项IDR_SIMUTYPE就包括了视口的菜单，加速键和图表等资源，如果用户使<br />用AppWizard来产生的应用基本框架，那么其也同时产生了缺省的图标，如果用户不<br />满意缺省图标（实际上用户很少满足于缺省图标），只需要将缺省图标删除，然后<br />编辑或者直接引入一个新的图标，在存储这一图标时只需要使用与被删除图标同样<br />的ID即可实现替代。<br />熟悉Windows程序开发的人都知道，在Windows上通过使用灰色背景可以增强应用程<br />序的视觉效果，曾有人戏称，灰色是图形界面永恒的颜色。使用MFC产生的应用程序<br />的背景缺省为白色，如果用户希望改变成灰色或者其它颜色，那就需要使用单独处<br />理，解决的办法很多，如在每次视口的OnPaint()事件中采用灰色刷子人为填充背<br />景，但是这不是最好的办法。笔者发现最好的办法就是采用AfxRegisterWndClass()<br />函数注册一个使用灰色背景刷的新的窗口类，这需要重载PreCreateWindow()函数来<br />实现这一点，如下程序代码片段所示：<br />BOOL CSimuView::PreCreateWindow(CREATESTRUCT&amp; cs)<br />{<br />HBRUSH hbkbrush=CreateSolidBrush(RGB(192,192,192));//创建灰色背景刷<br />LPCSTR lpMyOwnClass=AfxRegisterWndClass(CS_HREDRAW<br />|CS_VREDRAW|CS_OWNDC,0,hbkbrush);//注册新类<br />cs.lpszClass=lpMyOwnClass;//修改缺省的类风格<br />return TRUE;<br />}<br />采用这种方法速度最快，也最省力。同时，还可以在PreCreateWindow()函数定义所<br />希望的任何窗口风格，如窗口大小，光标式样等。<br /><br /></p>
		<p>
				<b>使用单文档-多视结构</b>
		</p>如果用户使用过MFC进行编程，那么就会发现借助于AppWizard基于MFC无论编写SDI<br />(单文档界面)还是编写MDI(多文档界面)都是十分方便的。MDI应用程序目前使用越<br />来越普遍，人们熟悉的Microsoft公司的Office系列产品以及Visual系列产品都是典<br />型的多文档应用程序。这种多文档界面具有多窗口的特点，因而人们可以在一个程<br />序中使用多个子窗口来实现不同数据的浏览查看。如果用户要实现在MDI各个窗口之<br />间针对同一数据进行不同的可视化就是一件比较麻烦的事情。值得庆幸的是，MFC提<br />供的文档-视结构大大简化了这一工作。文档-视结构通过将数据从用户对数据的观<br />察中分离出来，从而方便实现多视，亦即多个视口针对同一数据，如果一个视口中<br />数据发生改变，那么其它相关视口中的内容也会随之发生改变以反映数据的变化。<br />SDI和MDI这两种Windows标准应用程序框架并不是总能满足用户的需要，就作者的工<br />作而言，就特别需要一种被称为单文档多视的应用程序，英文可以缩写为SDMV。通<br />过SDMV应用我们可以利用文档类来统一管理应用程序的所有数据，同时需要采用多<br />窗口以多种方式来可视化这些的数据，如棒图，趋势图和参数列表，从而方便用户<br />从不同角度来观察数据。MDI虽然具有多窗口的特点，但是其为多文档，即通常情况<br />下，一个视口对应一个文档，视口+文档便构成一个子窗口。在各个子窗口之间数据<br />相互独立，如果要保持数据同步更新就需要采用特殊的技术了，采用这种方式既费<br />时又费力。通过笔者的实践发现，利用MFC本身提供的多视概念通过适当改造MDI窗<br />口应用程序就可以实现上述SDMV结构。<br />所谓SDMV应用程序本质上仍然是一个MDI应用程序，只是在程序中我们人为控制使其<br />只能生成一个文档类，这个文档在第一个视口创建时创建，注意，这里并不需要限<br />制各个视口的创建先后顺序。此后与MDI窗口固有特性不同的是，所有新创建的子窗<br />口都不再创建独立文档，而是把该新视口直接连接到已有的文档对象上，这样就使<br />其成为单文档多视的结构，所有相关数据都存储在文档对象中，一旦文挡中数据发<br />生改变，通过UpdateAllViews()函数通知所有相关视口，各个视口就可以在<br />OnUpdate()中相应数据的变化。这种响应机制如下图所示:<br /><br />图 1 文档-视结构数据更新机制<br />由于MDI本质上并不是为这种单文档多视机制服务的，因而在实际应用时需要解决一<br />些问题。<br />1、窗口标题问题<br />窗口标题本来不应该成为问题，缺省情况下MDI窗口通过在文档模板中提供的资源ID<br />所提供的对应字符串来确定窗口标题。但是对于SDMV应用，由于各个视口实质上是<br />对应于同一个文挡，因此每个视口都具有相同标题，只不过增加了一个数据用于指<br />示这是第几个视口。如果在各个视口中指明具体的窗口名字，那么由不同的视口启<br />动创建文档产生的窗口标题就不同，这个名字会影响到后继视口。为了作到不同类<br />型的视口如棒图视口和曲线视口具有不同的标题，这就需要一定的技术处理。根据<br />笔者的摸索发现可以采用如下步骤实现：<br />首先在从标准的MDI子窗口基类CMDIChildWnd派生一个自己的子窗口类，姑且命名为<br />CMyChild，然后在其成员变量中增加一个CString型变量用以存储当前窗口标题：<br />CString winTitle;<br />然后在不同的视口创建过程中通过获取父窗口指针按自己的意愿对上述变量进行赋<br />值，程序片段如下：<br />pChild=(CMyChild*)GetParent();<br />pChild-&gt;winTitle="棒图显示窗口";<br />最后在CMyChild派生类中重载CMDIChildWnd基类中的OnUpdateFrameTitle()函数来<br />强制实现窗口标题的个性化，这一函数在各种类库手册上和联机帮助中都没有，但<br />的确有这样一个具有保护属性的函数用来实现窗口标题的更新操作，这可以从MFC类<br />库的源代码中找到该函数的实现。重载后的源代码如下：<br />void CMyChild::OnUpdateFrameTitle(BOOL bAddToTitle)<br />{<br />// update our parent window first<br />GetMDIFrame()-&gt;OnUpdateFrameTitle(bAddToTitle);<br /><br />if ((GetStyle() &amp; FWS_ADDTOTITLE) == 0)<br />return; // leave child window alone!<br /><br />CDocument* pDocument = GetActiveDocument();<br />if (bAddToTitle &amp;&amp; pDocument != NULL)<br />{<br />char szOld[256];<br />GetWindowText(szOld, sizeof(szOld));<br />char szText[256];<br /><br />lstrcpy(szText,winTitle); //Modified by author!<br />if (m_nWindow &gt; 0)<br />wsprintf(szText + lstrlen(szText), ":%d", m_nWindow);<br /><br />// set title if changed, but don't remove completely<br />if (lstrcmp(szText, szOld) != 0)<br />SetWindowText(szText);<br />}<br />}<br />2、如何创建SDMV应用<br />如何创建SDMV应用比较麻烦，下面通过举例来具体说明。该例子假设用户需要建棒<br />图类型和曲线形式的两种视口，假设用户已经利用CView基类派生并且实现了这两个<br />类，分别对应于CMyChart和CMyTraceView两个类。<br />1) 在应用类（从CWinApp派生出来的类）的头文件中加入下列变量和函数原型说<br />明：<br />CMultiDocTemplate* m_pMyTraceTemplate;<br />CMultiDocTemplate* m_pMyChartTemplate;<br />int ExitInstance();<br />2) 在应用类的InitInstance成员函数中删除对AddDocTemplate函数的调用和<br />OpenFileNew()语句，并且加入如下代码：<br />m_pMyTraceTemplate = new CMultiDocTemplate(<br />IDR_MYTRACEVIEW,<br />RUNTIME_CLASS(CSimuDoc),<br />RUNTIME_CLASS(CMyChild), // Derived MDI child frame<br />RUNTIME_CLASS(CMyTraceView));<br /><br />m_pMyChartTemplate = new CMultiDocTemplate(<br />IDR_MYCHART,<br />RUNTIME_CLASS(CSimuDoc),<br />RUNTIME_CLASS(CMyChild), // Derived MDI child frame<br />RUNTIME_CLASS(CMyChart));<br />3) 实现ExitInstance()函数，在其中删除所用的两个辅助模板：<br />int CTestApp::ExitInstance()<br />{<br />if(m_pMyChartTemplate) delete m_pMyChartTemplate;<br />if(m_pMyTraceTemplate) delete m_pMyTraceTemplate;<br />return TRUE;<br />}<br />4) 在菜单资源中去掉File菜单中的New和Open项，加入New Chart View和New<br />Trace View两项，在对应的菜单命令中实现如下：<br />void CMainFrame::OnNewMychart()<br />{<br />// TODO: Add your command handler code here<br />OnNewView(((CSimuApp*)AfxGetApp())-&gt;m_pMyChartTemplate);<br />}<br />void CMainFrame::OnNewMyTrace()<br />{<br />// TODO: Add your command handler code here<br />OnNewView(((CSimuApp*)AfxGetApp())-&gt;m_pMyTraceTemplate);<br />}<br />上中OnNewView的实现如下：<br />BOOL CMainFrame::OnNewView(CMultiDocTemplate* pDocTemplate)<br />{<br />CMDIChildWnd* pActiveChild = MDIGetActive();<br />CDocument* pDocument;<br />if (pActiveChild == NULL ||<br />(pDocument = pActiveChild-&gt;GetActiveDocument()) == NULL)<br />{<br />TRACE0("Now New the specify view\n");<br />ASSERT(pDocTemplate != NULL);<br />ASSERT(pDocTemplate-&gt;IsKindOf(RUNTIME_CLASS(CDocTemplate)));<br />pDocTemplate-&gt;OpenDocumentFile(NULL);<br />return TRUE;<br />}<br /><br />// otherwise we have a new frame to the same document!<br />CMultiDocTemplate* pTemplate = pDocTemplate;<br />ASSERT_VALID(pTemplate);<br />CFrameWnd* pFrame = pTemplate-&gt;CreateNewFrame(pDocument, pActiveChild);<br />if (pFrame == NULL)<br />{<br />TRACE0("Warning: failed to create new frame\n");<br />return FALSE; // command failed<br />}<br />pTemplate-&gt;InitialUpdateFrame(pFrame, pDocument);<br />return TRUE;<br />}<br />OnNewView是整个SDMV应用的核心组成，它的任务是创建一个新的指定类型的视口，<br />它首先判断是否有活动视口存在，文档是否已经创建，正常情况下活动视口存在则<br />表明文档存在，如果不存在则利用所指定的文档模板创建一个新的活动视口，否则<br />则只创建视口，同时将其连接到已存在的文档对象上。<br />通过以上步骤就可以实现SDMV应用，在其后的具体应用中利用文档对象的<br />UpdateAllViews()函数和视口的OnUpdate()函数就可以很好的工作了。<br /><br /><p><b>使用DDE服务</b></p>Windows 3.x是一个分时多任务操作环境，在此环境下，多个应用程序可以并发地执<br />行。为了在并发执行的多个任务之间共享数据和资源，Windows 提供了几种机制，<br />主要是通过剪贴板(Clipboard)和动态数据交换(Dynamic Data Exchange)。前者对<br />于用户需要直接参与的数据交换来说，是一个非常方便的工具，但是如果希望数据<br />交换自动进行时就必须依靠DDE技术了。编写DDE应用的技术也发展了好几代，从最<br />初的基于消息的DDE到基于DDEML(动态数据交换管理库)，再到现在流行的OLE技<br />术。DDE技术的发展使得程序开发人员编写DDE应用更为简洁。从发展趋势来看，基<br />于OLE的数据交换是最好的，它特别符合当今软件领域的客户-服务器机制<br />(Client-Server)。为适应多平台和Internet的需要，在OLE基础上微软又开发了<br />ActiveX技术。但是不容忽视的是，基于传统的DDE数据交换也自有它的应用空间，<br />使用仍然广泛。目前在Windows 3.x下，基于OLE的远程数据交换还很不成熟，但是<br />在WFW(Windows for Workgroup)下基于网络动态数据交换的技术却很成熟，目前也<br />应用非常普遍。关于DDE应用的开发和NetDDE的应用可以参看附录7。<br />1、回调函数的处理<br />由于DDEML机制需要使用回调函数，因此使用DDEML的关键是解决在MFC编程体系中回<br />调函数的使用。回调函数(Callback function)大量用于Windows的系统服务，通过<br />它，程序员可以安装设备驱动程序和消息过滤系统，以控制Windows的有效使用。<br />许多程序员都发现，利用MFC或者其它的C++应用编写回调函数是非常麻烦的，其根<br />本原因是回调函数是基于C编程的Windows SDK的技术，不是针对C++的，程序员可以<br />将一个C函数直接作为回调函数，但是如果试图直接使用C++的成员函数作为回调函<br />数将发生错误，甚至编译就不能通过。通过查询资料发现，其错误是普通的C++成员<br />函数都隐含了一个传递函数作为参数，亦即“this”指针，C++通过传递一个指向自<br />身的指针给其成员函数从而实现程序函数可以访问C++的数据成员。这也可以理解为<br />什么C++类的多个实例可以共享成员函数但是确有不同的数据成员。由于this指针的<br />作用，使得将一个CALLBACK型的成员函数作为回调函数安装时就会因为隐含的this<br />指针使得函数参数个数不匹配，从而导致回调函数安装失败。要解决这一问题的关<br />键就是不让this指针起作用，通过采用以下两种典型技术可以解决在C++中使用回调<br />函数所遇到的问题。这种方法具有通用性，适合于任何C++。<br />1. 不使用成员函数，直接使用普通C函数，为了实现在C函数中可以访问类的成员变<br />量，可以使用友元操作符(friend)，在C++中将该C函数说明为类的友元即可。这种<br />处理机制与普通的C编程中使用回调函数一样。<br />2. 使用静态成员函数，静态成员函数不使用this指针作为隐含参数，这样就可以作<br />为回调函数了。静态成员函数具有两大特点：其一，可以在没有类实例的情况下使<br />用；其二，只能访问静态成员变量和静态成员函数，不能访问非静态成员变量和非<br />静态成员函数。由于在C++中使用类成员函数作为回调函数的目的就是为了访问所有<br />的成员变量和成员函数，如果作不到这一点将不具有实际意义。解决的办法也很简<br />单，就是使用一个静态类指针作为类成员，通过在类创建时初始化该静态指针，如<br />pThis=this，然后在回调函数中通过该静态指针就可以访问所有成员变量和成员函<br />数了。这种处理办法适用于只有一个类实例的情况，因为多个类实例将共享静态类<br />成员和静态成员函数，这就导致静态指针指向最后创建的类实例。为了避免这种情<br />况，可以使用回调函数的一个参数来传递this指针，从而实现数据成员共享。这种<br />方法稍稍麻烦，这里就不再赘述。<br />2、在MFC中使用DDEML<br />对于典型的MFC应用程序，主框架窗口类(CMainFrame)只有一个实例，因此可以使用<br />静态成员函数作为回调函数，从而实现DDE机制。具体的代码片段如下：<br />(1) 在CMainFrame类中声明如下静态成员：<br />static CMainFrame* pThis;<br />static DWORD idInst;<br />static HDDEDATA CALLBACK EXPORT DdeCallback(UINT,UINT,HCONV,HSZ,HSZ, HDDEDATA,DWORD,DWORD);<br />(2) 在类的创建代码(OnCreate())中作如下说明：<br />pThis=this;<br />lpDdeCallback=MakeProcInstance((FARPROC)DdeCallback,hInstance);<br />if(DdeInitialize(&amp;idInst,(PFNCALLBACK)lpDdeCallback,CBF_FAIL_EXECUTES<br />|CBF_SKIP_REGISTRATIONS|CBF_SKIP_UNREGISTRATIONS,0L))<br />{<br />AfxMessageBox("不能初始化DDE服务","错误");<br />DestroyWindow();<br />}<br />(3) 回调函数实现如下：<br />HDDEDATA FAR PASCAL _export CMainFrame::DdeCallback(UINT iType,UINT iFmt, HCONV hConv,HSZ hsz1,HSZ hsz2,HDDEDATA hData,DWORD dwData1,DWORD dwData2)<br />{<br />char szBuffer[16];<br />int i;<br /><br />switch(iType)<br />{<br />case XTYP_CONNECT: //hsz1=topiv, hsz2=service<br />return (HDDEDATA)TRUE;//TRUE;<br />case XTYP_ADVSTART: //hsz1=topic, hsz2=item<br />case XTYP_REQUEST:<br />case XTYP_ADVREQ:<br />case XTYP_POKE: //hsz1=Topic, hsz2=item, hData=data<br />case XTYP_ADVSTOP:<br />return NULL;<br />}<br />}<br />3、避免变量类型冲突<br />如果在MFC应用直接使用DDEML服务，那么该MFC应用在编译时将会遇到变量类型HSZ<br />重复定义错误。经过追踪发现，错误在于在DDEML.H对HSZ作了如下定义：<br />DECLARE_HANDLE32(HSZ);<br />而在AFXEXT.H(通过stdafx.h引入)中对HSZ又作了如下说明：<br />typedef BPSTR FAR* HSZ; // Long handle to a string<br />两个定义一个为32位整数，一个为BASIC字符串指针，当然会发生编译器不能作变量<br />类型转换的错误。实际上，将HSZ声明为BASIC字符串指针主要用于在MFC应用中使用<br />VBX控制。要改正这一错误，就必须保证不要在同一个代码模块中使用DDEML和VBX支<br />持，通过将使用DDEML和VBX的代码分开，并在使用DDEML代码的模块中最开头定义如<br />下编译器宏就可以解决上述问题：<br />#define NO_VBX_SUPPORT<br /><br /><p><b>使用3D控制</b></p>毫无疑问，3D控制的使用可以显著提高Windows应用程序的界面友好性，目前，许多<br />流行的Windows应用程序都使用了3D控制，典型的如Microsoft公司的Office系列软<br />件，而且，在Windows 95和Windows NT 4.0中，3D控制更是作为操作系统的一部分<br />直接提供，这意味着在其上运行的软件不需要作任何特殊处理，就具有3D界面效<br />果，但是，很遗憾的是，在Windows 3.x中，除了命令按钮控制使用3D控制以外，其<br />余所有的控制，如编辑框，列表框，检查框等都只使用2D控制，要想使用3D控制，<br />程序设计人员就必须在自己的程序中作一定的修改，考虑到目前3D效果的流行，这<br />点努力是值得的。<br />为了支持3D效果，Microsoft公司提供了一个专门用于3D控制的动态连接库，即<br />CTL3D.DLL，但是在其Visual C++中却没有如何使用3D控制的讨论，并且，Visual<br />C++也不直接支持3D编码，因为它不包括使用3D控制所必须的头文件。但是，这并不<br />意味着在Visual C++中不能使用3D控制，只不过用户需要从其它地方获取技术支持<br />罢了。由于使用的是动态连接库机制，因此，任何其它语言提供的3D头文件和<br />CTL3D.DLL的输入库都是可用的。作者使用的就是Borland公司的Borland C++中提供<br />的CTL3D.H和CTL3D.LIB。在C/C++中使用3D控制的方法也有很多种，在这里，为节约<br />篇幅，只讨论与本文相关的主题，即使用MFC编程时如何使用3D控制。<br />在MFC的所有对话框中使用3D控制可以遵循如下步骤：<br />1. 在CWinApp::InitInstance函数中调用Ctl3dRegister和Ctl3dAutosubclass函<br />数：<br />Ctl3dRegister(AfxGetInstanceHandle());<br />Ctl3dAutoSubclass(AfxGetInstanceHandle());<br />值得一提的是，在AppWizard产生的应用框架的CWinApp::InitInstance中有一个函<br />数调用为SetDialogBkColor，此函数的作用是将所有对话框的背景颜色设置为灰<br />色，这个功能与3D界面实现相同的功能，可以移去此语句。<br />由于CTL3D在初始化时读入所有的系统颜色并自己维持，为了使应用程序能够正确反<br />映系统颜色的变化，MFC应用程序可以在WM_SYSCOLORCHANGE消息中调用<br />Ctl3dColorChange函数。<br />2. 在MFC应用程序的CWinApp类中的ExitInstance函数中调用Ctl3dUnregister函<br />数，以方便Windows对CTL3D库的正确管理。<br />3. 在MFC应用程序的项目文件中加入CTL3D.LIB（可以用IMPORT.EXE产生）。<br />使用上述CTL3D的自动子类化的机制可以大大简化使用3D控制，如果这不满足你的要<br />求，那么你就必须单独在需要使用3D控制的对话框的OnInitDialog()中自行子类化<br />相关的控制类了，典型的如下代码片断所示：<br />BOOL CMyDialog::OnInitDialog()<br />{<br />Ctl3dSubclassDlgEx(m_hWnd,CTL3D_ALL);<br />return TRUE;<br />}<br />上面讲了在对话框中使用3D效果的办法，如果用户想在非对话框中使用3D控制，典<br />型的在FormView导出类中使用，可以在导出类的OnInitialUpdate函数中进行适当修<br />改，修改的大小取决于你是否使用了3D控制的自动子类化机制。如果使用前面提到<br />的自动子类化方法，那么仅需要在相应的OnInitialUpdate函数中调用<br />Ctl3dSubclassDlg函数了，如下代码片断所示：<br />void CMyView::OnInitialUpdate()<br />{<br />Ctl3dSubclassDlg(m_hWnd,CTL3D_ALL);<br />}<br />否则，则需要修改如下：<br />void CMyView::OnInitialUpdate()<br />{<br />Ctl3dSubclassDlgEx(m_hWnd,CTL3D_ALL);<br />}<br /><br /><p><b>使用自定义消息</b></p>1、MFC的消息映射机制<br />Windows是一个典型的消息驱动的操作系统，程序的运行是靠对各种消息的响应来实<br />现的，这些消息的来源非常广泛，既包括Windows系统本身，如WM_CLOSE、<br />WM_PAINT、WM_CREATE和WM_TIMER等常用消息，又包括用户菜单选择、键盘加速<br />键以及工具条和对话框按钮等等，如果应用程序要与其它程序协同工作，那么消息的来<br />源还包括其它应用程序发送的消息，串行口和并行口等硬件发送的消息等等。总<br />之，Windows程序的开发是围绕着对众多消息的合理响应和实现来实现程序的各种功<br />能的。使用过C语言来开发Windows程序的人都知道，在Windows程序的窗口回调函数<br />中需要安排Switch语句来响应大量的消息，同时由于消息的间断性使得不同的消息<br />响应之间信息的传递是通过大量的全局变量或者静态数据来实现的。<br />人们常用的两种类库OWL和MFC都提供了消息映射机制用以加速开发速度，使用者只<br />需要按规定定义好对应消息的处理函数自身即可，至于实际调用由类库本身所提供<br />的机制进行，或采用虚函数，或采用消息映射宏。为了有效节约内存，MFC并不大量<br />采用虚函数机制，而是采用宏来将特定的消息映射到派生类中的响应成员函数。这<br />种机制不但适用于Windows自身的140条消息，而且适用于菜单命令消息和按钮控制<br />消息。MFC提供的消息映射机制是非常强大的，它允许在类的各个层次上对消息进行<br />控制，而不简单的局限于消息产生者本身。在应用程序接收到窗口命令时，MFC将按<br />如下次序寻找相应的消息控制函数：<br />SDI应用<br />MDI应用<br />视口<br />视口<br />文档<br />文档<br />SDI主框架<br />MDI子框架<br />应用<br />MDI主框架<br /><br />应用<br />大多数应用对每一个命令通常都只有一个特定的命令控制函数，而这个命令控制函<br />数也只属于某一特定的类，但是如果在应用中对同一消息有多个命令控制函数，那<br />么只有优先级较高的命令控制函数才会被调用。为了简化对常用命令的处理，MFC在<br />基类中提供并实现了许多消息映射的入口，如打印命令，打印预览命令，退出命令<br />以及联机帮助命令等，这样在派生类中就继承了所有的基类中的消息映射函数，从<br />而可以大大简化编程。如果我们要在自己派生类中实现对消息的控制，那么必须在<br />派生类中加上相应的控制函数和映射入口。<br />2、使用自己的消息<br />在程序设计的更深层次，人们常常会发现只依赖于菜单和命令按钮产生的消息是不<br />够的，常常因为程序运行的逻辑结构和不同视口之间数据的同步而需要使用一些自<br />定义的消息，这样通过在相应层次上安排消息响应函数就可以实现自己的特殊需<br />要。比如如果我们要在特定的时间间隔内通知所有数据输出视口重新取得新数据，<br />要依靠菜单命令和按钮命令实现不够理想，比较理想的解决办法是采用定时器事件<br />进行特定的计算操作，操作完成后再采用SendMessage发送自己的特定消息，只有当<br />这一消息得到处理后才会返回主控程序进行下一时间计算。通过在文档层次上安排<br />对消息的响应取得最新计算数据，而后通过UpdateAllViews()成员函数来通知所有<br />相关视口更新数据的显示。视口通过重载OnUpdate()成员函数就可以实现特定数据<br />的更新显示。<br />如果用户能够熟练使用SendMessage()函数和PostMessage()函数，那么要发送自定<br />义消息并不难，通常有两种选择，其一是发送WM_COMMAND消息，通过消息的WORD<br />wParam参数传递用户的命令ID，举例如下：<br />SendMessage(WM_COMMAND,IDC_GETDATA,0); //MFC主框架发送<br />然后在文档层次上安排消息映射入口：<br />ON_COMMAND(IDC_GETDATA, OnGetData)<br />同时在文档类中实现OnGetData()函数：<br />void CSimuDoc::OnGetData()<br />{<br />TRACE("Now in SimuDoc,From OnGetData\n");<br />UpdateAllViews(NULL);<br />}<br />注意在上中的消息映射入口需要用户手工加入，Visual C++提供的ClassWizard并不<br />能替用户完成这一工作。上中例子没有使用PostMessage函数而使用SendMessage函<br />数的原因是利用了SendMessage函数的特点，即它只有发送消息得到适当处理后方才<br />返回，这样有助于程序控制。<br />另一种发送自定义消息的办法是直接发送命令ID，在控制层次上采用ON_MESSAGE来<br />实现消息映射入口，注意这时的命令控制函数的原型根据Windows本身消息处理的规<br />定必须如下：<br />afx_msg LONG OnCaculationOnce(WPARAM wParam,LPARAM lParam);<br />相对来讲，这种机制不如上述机制简单，也就不再赘述。<br /><br /><p><b>使用不带文挡-视结构的MFC应用<br /></b></p>文档-视结构的功能是非常强大的，可以适合于大多数应用程序，但是有时我们只需<br />要非常简单的程序，为了减少最终可执行文件尺寸和提高运行速度，我们没有必要<br />使用文挡-视结构，典型的有简单SDI应用和基于对话框的应用。<br />1、简单SDI应用<br />此时只需要使用CWinApp和CFrameWnd两个类就完全可以了。由于CWinApp类封装了<br />WinMain函数和消息处理循环，因此任何使用MFC进行编程的程序都不能脱离开该<br />类。实际上使用CWinApp类非常简单，主要是派生一个用户自己的应用类，如<br />CMyApp，然后只需重载CWinApp类的InitInstance()函数：<br /><br />BOOL CMyApp::InitInstance()<br />{<br />m_pMainWnd=new CMainFrame();<br />ASSERT(m_pMainWnd!=NULL); //error checking only<br />m_pMainWnd-&gt;ShowWindow(m_nCmdShow);<br />m_pMainWnd-&gt;UpdateWindow();<br />return TRUE;<br />}<br />至于所需要的主框架类，则可以直接使用ClassWizard实用程序生成，该类的头文件<br />与实现代码可以与CMyApp类的头文件和实现代码放在一起。注意，这里由一个技<br />巧，由于ClassWizard的使用需要有相应的CLW文件存在，而收工建代码时没有对应<br />的CLW文件，因此不能直接使用，解决办法是进入App Studio实用工具后使用<br />ClassWizard，此时系统会发觉不存在相应的CLW文件，系统将提示你重建CLW文件并<br />弹出相应对话框，这时候你不需要选择任何文件就直接选择OK按钮，这样系统将为<br />你产生一个空的CLW文件，这样就可以使用ClassWizard实用工具了。为了将CWinApp<br />和CFrameWnd的派生类有机地结合在一起，只需在CFrameWnd派生类的构造函数中进<br />行窗口创建即可。典型代码如下：<br />CMainFrame::CMainFrame()<br />{<br />Create(NULL,"DDE Client Application",WS_OVERLAPPEDWINDOW,rectDefault,<br />NULL,MAKEINTRESOURCE(IDR_MAINFRAME));<br />}<br />采用ClassWizard实用程序生成相关类代码后，所有的类的其它实现和维护就同普通<br />由AppWizard实用程序产生的代码一样了。<br />2、基于对话框的程序<br />有些主要用于数据的输入和输出等的应用在使用时没有必要改变窗口大小，典型的<br />如各种联机注册程序，这些使用对话框作为应用的主界面就足够了，而且开发此类<br />应用具有方便快捷的特点，代码也比较短小，如果直接采用各种控制类生成所需要<br />的控制就特别麻烦。在Visual C++ 4.x版本中使用AppWizard就可以直接生成基于对<br />话框的应用。在Visual 1.x中没有此功能，因此这类应用需要程序员自己实现。<br />实际上使用MFC实现基于对话框的应用非常简单，同样只使用两个MFC类作为基类，<br />这两个类为CWinApp类和CDialog类。所使用的对话框主界面同样可以先用App<br />Studio编辑对话框界面，再使用ClassWizard产生相应代码框架，然后修改CMyApp类<br />的声明，增加一个该对话框类的成员变量m_Mydlg，最后修改CMyApp类的<br />InitInstance()函数如下：<br />BOOL CMyApp::InitInstance()<br />{<br />m_Mydlg.DoModal();<br />return TRUE;<br />}<br /><br /><p><b>MFC应用的人工优化</b></p>使用C/C++编写Windows程序的优点就是灵活高效，运行速度快，Visual C++编译器<br />本身的优化工作相当出色，但这并不等于不需要进行适当的人工优化，为了提高程<br />序的运行速度，程序员可以从以下几方面努力：<br />1) 减少不必要的重复显示<br />相对来讲，Windows的GDI操作是比较慢的，因此在程序中我们应该尽可能地控制整<br />个视口的显示和更新，如果前后两此数据不发生变化，那么就不要重新进行视口的<br />GDI图形操作，尤其对于背景图显示时非万不得已时不要重绘，同时不要经常五必要<br />的刷新整个窗口。<br />2) 在视口极小化时不要进行更新屏幕操作<br />在窗口处于极小化时没有必要继续进行视口更新工作，这样可以显著提高速度。为<br />此需要在子窗口一级捕获上述信息（视口不能捕获该类信息），再在视口中进行相<br />应操作。如下代码片段所示：<br />首先在子窗口类中添加如下程序段：<br />void CMyChild::OnSysCommand(UINT nID,LPARAM lparam)<br />{<br />CMDIChildWnd::OnSysCommand(nID,lparam);<br />if(nID==SC_MINIMIZE){<br />RedrawFlag=0;<br />}<br />else<br />RedrawFlag=1;<br />}<br />再在视口更新时中修改如下：<br />void CMyChart::OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint )<br />{<br />if(pChild-&gt;RedrawFlag)<br />{<br />InvalidateRect(&amp;r,FALSE);<br />TRACE("Now In CMyChart::OnUpdate\n");<br />}<br />}<br />至于上中pChild指针可以在视口创建的例程中获取：<br />pChild=(CMyChild*)GetParent();<br />3) 使用永久性的资源<br />在频繁进行GDI输出的视口中，如在监控软件中常常使用的趋势图显示和棒图显示等<br />等，应该考虑在类层次上建立频繁使用的每种画笔和刷子，这可以避免频繁的在堆<br />中创建和删除GDI对象，从而提高速度。<br />4) 使用自有设备描述句柄<br />亦即在创建视口时通过指定WM_OWNDC风格来拥有自己的显示设备句柄，这虽然会多<br />消耗一些内存，一个DC大约占800字节的内存，但是这避免了每次进行GDI操作前创<br />建并合理初始化显示设备句柄这些重复操作。特别是要自定义坐标系统和使用特殊<br />字体的视口这一点尤其重要。在16M机器日益普遍的今天为了节约一点点内存而降低<br />速度的做法并不可取。<br />5) 优化编译时指定/G3选项和/FPix87选项<br />/G3选项将强迫编译器使用386处理器的处理代码，使用嵌入式协处理器指令对那些<br />频繁进行浮点运算的程序很有帮助。采用这两种编译开关虽然提高了对用户机型的<br />要求，但在386逐渐被淘汰，486市场大幅度萎缩，586市场日益普及的今天上述问题<br />已经不再成为问题了。<br /><br /><br /><img src ="http://www.cppblog.com/andxie99/aggbug/9672.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-07-11 09:54 <a href="http://www.cppblog.com/andxie99/archive/2006/07/11/9672.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>STL 排序(Sort) </title><link>http://www.cppblog.com/andxie99/archive/2006/06/30/9226.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Fri, 30 Jun 2006 04:35:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/06/30/9226.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/9226.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/06/30/9226.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/9226.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/9226.html</trackback:ping><description><![CDATA[
		<br />
网上看到这篇文章，觉得写得比较易懂，修改了原文的一些错误后整理在这里。
作者 Winter 
<div class="twikiToc"><ul><li><a href="#详细解说 STL 排序(Sort)">详细解说 STL 排序(Sort)</a><ul><li><a href="#0 前言: STL，为什么你必须掌握">0 前言: STL，为什么你必须掌握</a></li><li><a href="#1 STL提供的Sort 算法">1 STL提供的Sort 算法</a><ul><li><a href="#1.1 所有sort算法介绍">1.1 所有sort算法介绍</a></li><li><a href="#1.2 sort 中的比较函数">1.2 sort 中的比较函数</a></li><li><a href="#1.3 sort 的稳定性">1.3 sort 的稳定性</a></li><li><a href="#1.4 全排序">1.4 全排序</a></li><li><a href="#1.5 局部排序">1.5 局部排序</a></li><li><a href="#1.6 nth_element 指定元素排序">1.6 nth_element 指定元素排序</a></li><li><a href="#1.7 partition 和stable_partition">1.7 partition 和stable_partition</a></li></ul></li><li><a href="#2 Sort 和容器">2 Sort 和容器</a></li><li><a href="#3 选择合适的排序函数">3 选择合适的排序函数</a></li><li><a href="#4 小结">4 小结</a></li></ul></li></ul></div><font color="#0000ff"><em>一切复杂的排序操作，都可以通过STL方便实现</em> ! </font><h3><a name="0 前言: STL，为什么你必须掌握"></a>0 前言: STL，为什么你必须掌握 </h3><hr />
对于程序员来说，数据结构是必修的一门课。从查找到排序，从链表到二叉树，几乎所有的算法和原理都需要理解，理解不了也要死记硬背下来。幸运的是这些理论都已经比较成熟，算法也基本固定下来，不需要你再去花费心思去考虑其算法原理，也不用再去验证其准确性。不过，等你开始应用计算机语言来工作的时候，你会发现，面对不同的需求你需要一次又一次去用代码重复实现这些已经成熟的算法，而且会一次又一次陷入一些由于自己疏忽而产生的bug中。这时，你想找一种工具，已经帮你实现这些功能，你想怎么用就怎么用，同时不影响性能。你需要的就是STL, 标准模板库！ 
<p>西方有句谚语：不要重复发明轮子！ 
</p><p>STL几乎封装了所有的数据结构中的算法，从链表到队列，从向量到堆栈，从hash到二叉树，从搜索到排序，从增加到删除......可以说，如果你理解了STL，你会发现你已不用拘泥于算法本身，从而站在巨人的肩膀上去考虑更高级的应用。 
</p><p>排序是最广泛的算法之一，本文详细介绍了STL中不同排序算法的用法和区别。 
</p><h3><a name="1 STL提供的Sort 算法"></a>1 STL提供的Sort 算法 </h3><hr />
C++之所以得到这么多人的喜欢，是因为它既具有面向对象的概念，又保持了C语言高效的特点。STL 排序算法同样需要保持高效。因此，对于不同的需求，STL提供了不同的函数。不同的函数，实现的算法又不尽相同。 
<h4><a name="1.1 所有sort算法介绍"></a>1.1 所有sort算法介绍 </h4>所有的sort算法的参数都需要输入一个范围，[begin, end)。这里使用的迭代器(iterator)都需是随机迭代器(RadomAccessIterator), 也就是说可以随机访问的迭代器，如：it+n什么的。（partition 和stable_partition 除外） 
<p>如果你需要自己定义比较函数，你可以把你定义好的仿函数(functor)作为参数传入。每种算法都支持传入比较函数。以下是所有STL sort算法函数的名字列表: 
</p><table class="twikiTable" cellspacing="1" cellpadding="1" border="0"><tbody><tr><th class="twikiFirstCol" bgcolor="#dadada"><a title="Sort by this column" href="?sortcol=0;table=1;up=0#sorted_table" rel="nofollow"><font color="#000000">函数名</font></a></th><th bgcolor="#dadada"><a title="Sort by this column" href="?sortcol=1;table=1;up=0#sorted_table" rel="nofollow"><font color="#000000">功能描述</font></a></th></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">sort </td><td bgcolor="#ffffff">对给定区间所有元素进行排序 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">stable_sort </td><td bgcolor="#eaeaea">对给定区间所有元素进行稳定排序 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">partial_sort </td><td bgcolor="#ffffff">对给定区间所有元素部分排序 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">partial_sort_copy </td><td bgcolor="#eaeaea">对给定区间复制并排序 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">nth_element </td><td bgcolor="#ffffff">找出给定区间的某个位置对应的元素 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">is_sorted </td><td bgcolor="#eaeaea">判断一个区间是否已经排好序 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">partition </td><td bgcolor="#ffffff">使得符合某个条件的元素放在前面 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">stable_partition </td><td bgcolor="#eaeaea">相对稳定的使得符合某个条件的元素放在前面 </td></tr></tbody></table>其中nth_element 是最不易理解的，实际上，这个函数是用来找出第几个。例如：找出包含7个元素的数组中排在中间那个数的值，此时，我可能不关心前面，也不关心后面，我只关心排在第四位的元素值是多少。 
<h4><a name="1.2 sort 中的比较函数"></a>1.2 sort 中的比较函数 </h4>当你需要按照某种特定方式进行排序时，你需要给sort指定比较函数，否则程序会自动提供给你一个比较函数。 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px">vector &lt; <font color="brown">int</font> &gt; vect;
<font color="green">//...</font>
sort(vect.begin(), vect.end());
<font color="green">//此时相当于调用</font>
sort(vect.begin(), vect.end(), less&lt;<font color="brown">int</font>&gt;() );</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>上述例子中系统自己为sort提供了less仿函数。在STL中还提供了其他仿函数，以下是仿函数列表: 
<table class="twikiTable" cellspacing="1" cellpadding="1" border="0"><tbody><tr><th class="twikiFirstCol" bgcolor="#dadada"><a title="Sort by this column" href="?sortcol=0;table=2;up=0#sorted_table" rel="nofollow"><font color="#000000">名称 </font></a></th><th bgcolor="#dadada"><a title="Sort by this column" href="?sortcol=1;table=2;up=0#sorted_table" rel="nofollow"><font color="#000000">功能描述 </font></a></th></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">equal_to </td><td bgcolor="#ffffff">相等 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">not_equal_to </td><td bgcolor="#eaeaea">不相等 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">less </td><td bgcolor="#ffffff">小于 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">greater </td><td bgcolor="#eaeaea">大于 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">less_equal </td><td bgcolor="#ffffff">小于等于 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">greater_equal </td><td bgcolor="#eaeaea">大于等于 </td></tr></tbody></table>需要注意的是，这些函数不是都能适用于你的sort算法，如何选择，决定于你的应用。另外，不能直接写入仿函数的名字，而是要写其重载的()函数： <pre style="PADDING-BOTTOM: 0px">less&lt;int&gt;()
greater&lt;int&gt;()
</pre>当你的容器中元素是一些标准类型（int float char)或者string时，你可以直接使用这些函数模板。但如果你是自己定义的类型或者你需要按照其他方式排序，你可以有两种方法来达到效果：一种是自己写比较函数。另一种是重载类型的'&lt;'操作符。 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="navy">#include</font> &lt;iostream&gt;
<font color="navy">#include</font> &lt;algorithm&gt;
<font color="navy">#include</font> &lt;functional&gt;
<font color="navy">#include</font> &lt;vector&gt;
<font color="brown">using</font><font color="brown">namespace</font> std;

<font color="brown">class</font> myclass {
        <font color="brown">public</font>:
        myclass(<font color="brown">int</font> a, <font color="brown">int</font> b):first(a), second(b){}
        <font color="brown">int</font> first;
        <font color="brown">int</font> second;
        <font color="brown">bool</font><font color="brown">operator</font> &lt; (<font color="brown">const</font> myclass &amp;m)<font color="brown">const</font> {
                <font color="brown">return</font> first &lt; m.first;
        }
};

<font color="brown">bool</font> less_second(<font color="brown">const</font> myclass &amp; m1, <font color="brown">const</font> myclass &amp; m2) {
        <font color="brown">return</font> m1.second &lt; m2.second;
}

<font color="brown">int</font> main() {
        
        vector&lt; myclass &gt; vect;
        <font color="brown">for</font>(<font color="brown">int</font> i = 0 ; i &lt; 10 ; i ++){
                myclass my(10-i, i*3);
                vect.push_back(my);
        }
        <font color="brown">for</font>(<font color="brown">int</font> i = 0 ; i &lt; vect.size(); i ++) 
        cout&lt;&lt;"<font color="blue">(</font>"&lt;&lt;vect[i].first&lt;&lt;"<font color="blue">,</font>"&lt;&lt;vect[i].second&lt;&lt;"<font color="blue">)\n</font>";
        sort(vect.begin(), vect.end());
        cout&lt;&lt;"<font color="blue">after sorted by first:</font>"&lt;&lt;endl;
        <font color="brown">for</font>(<font color="brown">int</font> i = 0 ; i &lt; vect.size(); i ++) 
        cout&lt;&lt;"<font color="blue">(</font>"&lt;&lt;vect[i].first&lt;&lt;"<font color="blue">,</font>"&lt;&lt;vect[i].second&lt;&lt;"<font color="blue">)\n</font>";
        cout&lt;&lt;"<font color="blue">after sorted by second:</font>"&lt;&lt;endl;
        sort(vect.begin(), vect.end(), less_second);
        <font color="brown">for</font>(<font color="brown">int</font> i = 0 ; i &lt; vect.size(); i ++) 
        cout&lt;&lt;"<font color="blue">(</font>"&lt;&lt;vect[i].first&lt;&lt;"<font color="blue">,</font>"&lt;&lt;vect[i].second&lt;&lt;"<font color="blue">)\n</font>";
        
        <font color="brown">return</font> 0 ;
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>知道其输出结果是什么了吧： <pre style="PADDING-BOTTOM: 0px">(10,0)
(9,3)
(8,6)
(7,9)
(6,12)
(5,15)
(4,18)
(3,21)
(2,24)
(1,27)
after sorted by first:
(1,27)
(2,24)
(3,21)
(4,18)
(5,15)
(6,12)
(7,9)
(8,6)
(9,3)
(10,0)
after sorted by second:
(10,0)
(9,3)
(8,6)
(7,9)
(6,12)
(5,15)
(4,18)
(3,21)
(2,24)
(1,27)
</pre><h4><a name="1.3 sort 的稳定性"></a>1.3 sort 的稳定性 </h4>你发现有sort和stable_sort，还有 partition 和stable_partition， 感到奇怪吧。其中的区别是，带有stable的函数可保证相等元素的原本相对次序在排序后保持不变。或许你会问，既然相等，你还管他相对位置呢，也分不清楚谁是谁了？这里需要弄清楚一个问题，这里的相等，是指你提供的函数表示两个元素相等，并不一定是一摸一样的元素。 
<p>例如，如果你写一个比较函数: 
</p><div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="brown">bool</font> less_len(<font color="brown">const</font> string &amp;str1, <font color="brown">const</font> string &amp;str2)
{
        <font color="brown">return</font> str1.length() &lt; str2.length();
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>此时，"apple" 和 "winter" 就是相等的，如果在"apple" 出现在"winter"前面，用带stable的函数排序后，他们的次序一定不变，如果你使用的是不带"stable"的函数排序，那么排序完后，"Winter"有可能在"apple"的前面。 
<p></p><h4><a name="1.4 全排序"></a>1.4 全排序 </h4>全排序即把所给定范围所有的元素按照大小关系顺序排列。用于全排序的函数有 
<p></p><div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="brown">template</font> &lt;<font color="brown">class</font> RandomAccessIterator&gt;
<font color="brown">void</font> sort(RandomAccessIterator first, RandomAccessIterator last);

<font color="brown">template</font> &lt;<font color="brown">class</font> RandomAccessIterator, <font color="brown">class</font> StrictWeakOrdering&gt;
<font color="brown">void</font> sort(RandomAccessIterator first, RandomAccessIterator last,
StrictWeakOrdering comp);

<font color="brown">template</font> &lt;<font color="brown">class</font> RandomAccessIterator&gt;
<font color="brown">void</font> stable_sort(RandomAccessIterator first, RandomAccessIterator last);

<font color="brown">template</font> &lt;<font color="brown">class</font> RandomAccessIterator, <font color="brown">class</font> StrictWeakOrdering&gt;
<font color="brown">void</font> stable_sort(RandomAccessIterator first, RandomAccessIterator last, 
StrictWeakOrdering comp);</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>在第1，3种形式中，sort 和 stable_sort都没有指定比较函数，系统会默认使用operator&lt; 对区间[first,last)内的所有元素进行排序, 因此，如果你使用的类型已经重载了operator&lt;函数，那么你可以省心了。第2, 4种形式，你可以随意指定比较函数，应用更为灵活一些。来看看实际应用： 
<p>班上有10个学生，我想知道他们的成绩排名。 
</p><div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="navy">#include</font> &lt;iostream&gt;
<font color="navy">#include</font> &lt;algorithm&gt;
<font color="navy">#include</font> &lt;functional&gt;
<font color="navy">#include</font> &lt;vector&gt;
<font color="navy">#include</font> &lt;string&gt;
<font color="brown">using</font><font color="brown">namespace</font> std;

<font color="brown">class</font> student{
        <font color="brown">public</font>:
        student(<font color="brown">const</font> string &amp;a, <font color="brown">int</font> b):name(a), score(b){}
        string name;
        <font color="brown">int</font> score;
        <font color="brown">bool</font><font color="brown">operator</font> &lt; (<font color="brown">const</font> student &amp;m)<font color="brown">const</font> {
                <font color="brown">return</font> score&lt; m.score;
        }
};

<font color="brown">int</font> main() {
        vector&lt; student&gt; vect;
        student st1("<font color="blue">Tom</font>", 74);
        vect.push_back(st1);
        st1.name="<font color="blue">Jimy</font>";
        st1.score=56;
        vect.push_back(st1);
        st1.name="<font color="blue">Mary</font>";
        st1.score=92;
        vect.push_back(st1);
        st1.name="<font color="blue">Jessy</font>";
        st1.score=85;
        vect.push_back(st1);
        st1.name="<font color="blue">Jone</font>";
        st1.score=56;
        vect.push_back(st1);
        st1.name="<font color="blue">Bush</font>";
        st1.score=52;
        vect.push_back(st1);
        st1.name="<font color="blue">Winter</font>";
        st1.score=77;
        vect.push_back(st1);
        st1.name="<font color="blue">Andyer</font>";
        st1.score=63;
        vect.push_back(st1);
        st1.name="<font color="blue">Lily</font>";
        st1.score=76;
        vect.push_back(st1);
        st1.name="<font color="blue">Maryia</font>";
        st1.score=89;
        vect.push_back(st1);
        cout&lt;&lt;"<font color="blue">------before sort...</font>"&lt;&lt;endl;
        <font color="brown">for</font>(<font color="brown">int</font> i = 0 ; i &lt; vect.size(); i ++) cout&lt;&lt;vect[i].name&lt;&lt;"<font color="blue">:\t</font>"&lt;&lt;vect[i].score&lt;&lt;endl;
        stable_sort(vect.begin(), vect.end(),less&lt;student&gt;());
        cout &lt;&lt;"<font color="blue">-----after sort ....</font>"&lt;&lt;endl;
        <font color="brown">for</font>(<font color="brown">int</font> i = 0 ; i &lt; vect.size(); i ++) cout&lt;&lt;vect[i].name&lt;&lt;"<font color="blue">:\t</font>"&lt;&lt;vect[i].score&lt;&lt;endl;
        <font color="brown">return</font> 0 ;
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>其输出是： <pre style="PADDING-BOTTOM: 0px">------before sort...
Tom:    74
Jimy:   56
Mary:   92
Jessy:  85
Jone:   56
Bush:   52
Winter: 77
Andyer: 63
Lily:   76
Maryia: 89
-----after sort ....
Bush:   52
Jimy:   56
Jone:   56
Andyer: 63
Tom:    74
Lily:   76
Winter: 77
Jessy:  85
Maryia: 89
Mary:   92
</pre>sort采用的是成熟的"快速排序算法"(目前大部分STL版本已经不是采用简单的快速排序，而是结合内插排序算法)。可以保证很好的平均性能、复杂度为n*log(n)，由于单纯的快速排序在理论上有最差的情况，性能很低，其算法复杂度为n*n，但目前大部分的STL版本都已经在这方面做了优化，因此你可以放心使用。stable_sort采用的是"归并排序"，分派足够内存时，其算法复杂度为n*log(n), 否则其复杂度为n*log(n)*log(n)，其优点是会保持相等元素之间的相对位置在排序前后保持一致。 
<h4><a name="1.5 局部排序"></a>1.5 局部排序 </h4>局部排序其实是为了减少不必要的操作而提供的排序方式。其函数原型为： 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="brown">template</font> &lt;<font color="brown">class</font> RandomAccessIterator&gt;
<font color="brown">void</font> partial_sort(RandomAccessIterator first, 
RandomAccessIterator middle,
RandomAccessIterator last);

<font color="brown">template</font> &lt;<font color="brown">class</font> RandomAccessIterator, <font color="brown">class</font> StrictWeakOrdering&gt;
<font color="brown">void</font> partial_sort(RandomAccessIterator first,
RandomAccessIterator middle,
RandomAccessIterator last, 
StrictWeakOrdering comp);

<font color="brown">template</font> &lt;<font color="brown">class</font> InputIterator, <font color="brown">class</font> RandomAccessIterator&gt;
RandomAccessIterator partial_sort_copy(InputIterator first, InputIterator last,
RandomAccessIterator result_first,
RandomAccessIterator result_last);

<font color="brown">template</font> &lt;<font color="brown">class</font> InputIterator, <font color="brown">class</font> RandomAccessIterator, 
<font color="brown">class</font> StrictWeakOrdering&gt;
RandomAccessIterator partial_sort_copy(InputIterator first, InputIterator last,
RandomAccessIterator result_first,
RandomAccessIterator result_last, Compare comp);</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>理解了sort 和stable_sort后，再来理解partial_sort 就比较容易了。先看看其用途: 班上有10个学生，我想知道分数最低的5名是哪些人。如果没有partial_sort，你就需要用sort把所有人排好序，然后再取前5个。现在你只需要对分数最低5名排序，把上面的程序做如下修改： 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px">stable_sort(vect.begin(), vect.end(),less&lt;student&gt;());
替换为：
partial_sort(vect.begin(), vect.begin()+5, vect.end(),less&lt;student&gt;());</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>输出结果为： <pre style="PADDING-BOTTOM: 0px">------before sort...
Tom:    74
Jimy:   56
Mary:   92
Jessy:  85
Jone:   56
Bush:   52
Winter: 77
Andyer: 63
Lily:   76
Maryia: 89
-----after sort ....
Bush:   52
Jimy:   56
Jone:   56
Andyer: 63
Tom:    74
Mary:   92
Jessy:  85
Winter: 77
Lily:   76
Maryia: 89
</pre>这样的好处知道了吗？当数据量小的时候可能看不出优势，如果是100万学生，我想找分数最少的5个人...... 
<p>partial_sort采用的堆排序（heapsort），它在任何情况下的复杂度都是n*log(n). 如果你希望用partial_sort来实现全排序，你只要让middle=last就可以了。 
</p><p>partial_sort_copy其实是copy和partial_sort的组合。被排序(被复制)的数量是[first, last)和[result_first, result_last)中区间较小的那个。如果[result_first, result_last)区间大于[first, last)区间，那么partial_sort相当于copy和sort的组合。 
</p><h4><a name="1.6 nth_element 指定元素排序"></a>1.6 nth_element 指定元素排序 </h4>nth_element一个容易看懂但解释比较麻烦的排序。用例子说会更方便：<br />班上有10个学生，我想知道分数排在倒数第4名的学生。<br />如果要满足上述需求，可以用sort排好序，然后取第4位（因为是由小到大排), 更聪明的朋友会用partial_sort, 只排前4位，然后得到第4位。其实这是你还是浪费，因为前两位你根本没有必要排序，此时，你就需要nth_element: 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="brown">template</font> &lt;<font color="brown">class</font> RandomAccessIterator&gt;
<font color="brown">void</font> nth_element(RandomAccessIterator first, RandomAccessIterator nth,
RandomAccessIterator last);

<font color="brown">template</font> &lt;<font color="brown">class</font> RandomAccessIterator, <font color="brown">class</font> StrictWeakOrdering&gt;
<font color="brown">void</font> nth_element(RandomAccessIterator first, RandomAccessIterator nth,
RandomAccessIterator last, StrictWeakOrdering comp);</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>对于上述实例需求，你只需要按下面要求修改1.4中的程序： 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px">stable_sort(vect.begin(), vect.end(),less&lt;student&gt;());
替换为：
nth_element(vect.begin(), vect.begin()+3, vect.end(),less&lt;student&gt;());</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>运行结果为： <pre style="PADDING-BOTTOM: 0px">------before sort...
Tom:    74
Jimy:   56
Mary:   92
Jessy:  85
Jone:   56
Bush:   52
Winter: 77
Andyer: 63
Lily:   76
Maryia: 89
-----after sort ....
Jone:   56
Bush:   52
Jimy:   56
Andyer: 63
Jessy:  85
Mary:   92
Winter: 77
Tom:    74
Lily:   76
Maryia: 89
</pre>第四个是谁？Andyer，这个倒霉的家伙。为什么是begin()+3而不是+4? begin()是第一个，begin()+1是第二个，... begin()+3当然就是第四个了。 
<h4><a name="1.7 partition 和stable_partition"></a>1.7 partition 和stable_partition </h4>好像这两个函数并不是用来排序的，'分类'算法，会更加贴切一些。partition就是把一个区间中的元素按照某个条件分成两类。其函数原型为： 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="brown">template</font> &lt;<font color="brown">class</font> ForwardIterator, <font color="brown">class</font> Predicate&gt;
ForwardIterator partition(ForwardIterator first,
ForwardIterator last, Predicate pred)
<font color="brown">template</font> &lt;<font color="brown">class</font> ForwardIterator, <font color="brown">class</font> Predicate&gt;
ForwardIterator stable_partition(ForwardIterator first, ForwardIterator last, 
Predicate pred);</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>看看应用吧：班上10个学生，计算所有没有及格（低于60分）的学生。你只需要按照下面格式替换1.4中的程序： 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px">stable_sort(vect.begin(), vect.end(),less&lt;student&gt;());
替换为：
student exam("<font color="blue">pass</font>", 60);
stable_partition(vect.begin(), vect.end(), bind2nd(less&lt;student&gt;(), exam));</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>其输出结果为： <pre style="PADDING-BOTTOM: 0px">------before sort...
Tom:    74
Jimy:   56
Mary:   92
Jessy:  85
Jone:   56
Bush:   52
Winter: 77
Andyer: 63
Lily:   76
Maryia: 89
-----after sort ....
Jimy:   56
Jone:   56
Bush:   52
Tom:    74
Mary:   92
Jessy:  85
Winter: 77
Andyer: 63
Lily:   76
Maryia: 89
</pre>看见了吗，Jimy，Jone, Bush(难怪说美国总统比较笨)都没有及格。而且使用的是stable_partition, 元素之间的相对次序是没有变. 
<h3><a name="2 Sort 和容器"></a>2 Sort 和容器 </h3><hr />
STL中标准容器主要vector, list, deque, string, set, multiset, map, multimay， 其中set, multiset, map, multimap都是以树结构的方式存储其元素. 因此在这些容器中，元素一直是有序的。 
<p>这些容器的迭代器类型并不是随机型迭代器，因此，上述的那些排序函数，对于这些容器是不可用的。上述sort函数对于下列容器是可用的： 
</p><ul><li>vector 
</li><li>string 
</li><li>deque </li></ul>如果你自己定义的容器也支持随机型迭代器，那么使用排序算法是没有任何问题的。 
<p>对于list容器，list自带一个sort成员函数list::sort(). 它和算法函数中的sort差不多，但是list::sort是基于指针的方式排序，也就是说，所有的数据移动和比较都是用指针的方式实现，因此排序后的迭代器一直保持有效（vector中sort后的迭代器会失效). 
</p><p></p><h3><a name="3 选择合适的排序函数"></a>3 选择合适的排序函数 </h3><hr />
为什么要选择合适的排序函数？可能你并不关心效率(这里的效率指的是程序运行时间), 或者说你的数据量很小， 因此你觉得随便用哪个函数都无关紧要。 
<p>其实不然，即使你不关心效率，如果你选择合适的排序函数，你会让你的代码更容易让人明白，你会让你的代码更有扩充性，逐渐养成一个良好的习惯，很重要吧。 
</p><p>如果你以前有用过C语言中的qsort, 想知道qsort和他们的比较，那我告诉你，qsort和sort是一样的，因为他们采用的都是快速排序。从效率上看，以下几种sort算法的是一个排序，效率由高到低（耗时由小变大）： 
</p><ol><li>partion 
</li><li>stable_partition 
</li><li>nth_element 
</li><li>partial_sort 
</li><li>sort 
</li><li>stable_sort </li></ol>Effective STL中对如何选择排序函数总结的很好： 
<ul><li>若需对vector, string, deque, 或 array容器进行全排序，你可选择sort或stable_sort； 
</li><li>若只需对vector, string, deque, 或 array容器中取得top n的元素，部分排序partial_sort是首选. 
</li><li>若对于vector, string, deque, 或array容器，你需要找到第n个位置的元素或者你需要得到top n且不关系top n中的内部顺序，nth_element是最理想的； 
</li><li>若你需要从标准序列容器或者array中把满足某个条件或者不满足某个条件的元素分开，你最好使用partition或stable_partition； 
</li><li>若使用的list容器，你可以直接使用partition和stable_partition算法，你可以使用list::sort代替sort和stable_sort排序。若你需要得到partial_sort或nth_element的排序效果，你必须间接使用。正如上面介绍的有几种方式可以选择。 </li></ul>总之记住一句话： <strong>如果你想节约时间，不要走弯路, 也不要走多余的路!</strong><h3><a name="4 小结"></a>4 小结 </h3><hr />
讨论技术就像个无底洞，经常容易由一点可以引申另外无数个技术点。因此需要从全局的角度来观察问题，就像观察STL中的sort算法一样。其实在STL还有make_heap, sort_heap等排序算法。本文章没有提到。本文以实例的方式，解释了STL中排序算法的特性，并总结了在实际情况下应如何选择合适的算法。 <img src ="http://www.cppblog.com/andxie99/aggbug/9226.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-06-30 12:35 <a href="http://www.cppblog.com/andxie99/archive/2006/06/30/9226.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++的iostream标准库介绍</title><link>http://www.cppblog.com/andxie99/archive/2006/06/29/9132.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Thu, 29 Jun 2006 00:21:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/06/29/9132.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/9132.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/06/29/9132.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/9132.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/9132.html</trackback:ping><description><![CDATA[
		<h2>
				<a name="C++的iostream标准库介绍">
				</a>C++的iostream标准库介绍 </h2>
		<div class="twikiToc">
				<ul>
						<li>
								<a href="#C++的iostream标准库介绍">C++的iostream标准库介绍</a>
								<ul>
										<li>
												<a href="#0 为什么需要iostream">0 为什么需要iostream</a>
										</li>
										<li>
												<a href="#1 iostream: istream 和 ostream">1 iostream: istream 和 ostream</a>
										</li>
										<li>
												<a href="#2 fstream: ifstream 和 ofstream">2 fstream: ifstream 和 ofstream</a>
										</li>
										<li>
												<a href="#3 strstream: ostrstream 和 istrs">3 strstream: ostrstream 和 istrstream</a>
										</li>
										<li>
												<a href="#4 stringstream">4 stringstream</a>
										</li>
										<li>
												<a href="#5 io_state 输入/输出的状态标志">5 io_state 输入/输出的状态标志</a>
										</li>
								</ul>
						</li>
				</ul>
		</div>
		<h3>
				<a name="0 为什么需要iostream">
				</a>0 为什么需要iostream </h3>　　我们从一开始就一直在利用C++的输入输出在做着各种练习，输入输出是由iostream库提供的，所以讨论此标准库是有必要的，它与C语言的 stdio库不同，它从一开始就是用多重继承与虚拟继承实现的面向对象的层次结构，作为一个c++的标准库组件提供给程序员使用。 
<p>　　iostream为内置类型对象提供了输入输出支持，同时也支持文件的输入输出，类的设计者可以通过对iostream库的扩展，来支持自定义类型的输入输出操作。 </p><p>　　为什么说要扩展才能提供支持呢？我们来一个示例。 </p><div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="navy">#include</font> &lt;stdio.h&gt; 
<font color="navy">#include</font> &lt;iostream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std;     

<font color="brown">class</font> Test 
{ 
        <font color="brown">public</font>: 
        Test(<font color="brown">int</font> a=0,<font color="brown">int</font> b=0) 
        { 
                Test::a=a; 
                Test::b=b; 
        } 
        <font color="brown">int</font> a; 
        <font color="brown">int</font> b; 
}; 
<font color="brown">int</font> main() 
{ 
        Test t(100,50); 
        printf("<font color="blue">%???</font>",t);<font color="green">//不明确的输出格式 </font>
        scanf("<font color="blue">%???</font>",t);<font color="green">//不明确的输入格式 </font>
        cout&lt;&lt;t&lt;&lt;endl;<font color="green">//同样不够明确 </font>
        cin&gt;&gt;t;<font color="green">//同样不够明确 </font>
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　由于自定义类的特殊性，在上面的代码中，无论你使用c风格的输入输出，或者是c++的输入输出都不是不明确的一个表示，由于c语言没有运算符重载机制，导致stdio库的不可扩充性，让我们无法让printf()和scanf()支持对自定义类对象的扩充识别，而c++是可以通过运算符重载机制扩充 iostream库的，使系统能能够识别自定义类型，从而让输入输出明确的知道他们该干什么，格式是什么。 
<p>　　在上例中我们之所以用printf与cout进行对比目的是为了告诉大家，C与C++处理输入输出的根本不同，我们从c远的输入输出可以很明显看出是函数调用方式，而c++的则是对象模式，cout和cin是ostream类和istream类的对象。 </p><h3><a name="1 iostream: istream 和 ostream"></a>1 iostream: istream 和 ostream </h3>　　C++中的iostream库主要包含下图所示的几个头文件: 
<table class="twikiTable" cellspacing="1" cellpadding="1" border="0"><tbody><tr><th class="twikiFirstCol" bgcolor="#dadada" colspan="2"><strong><font color="#000000">IOSstream 库</font></strong></th></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">fstream </td><td bgcolor="#ffffff">iomainip </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">ios </td><td bgcolor="#eaeaea">iosfwd </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">iostream </td><td bgcolor="#ffffff">istream </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">ostream </td><td bgcolor="#eaeaea">sstream </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">streambuf </td><td bgcolor="#ffffff">strstream </td></tr></tbody></table><p>　　我们所熟悉的输入输出操作分别是由istream(输入流)和ostream(输出流)这两个类提供的，为了允许双向的输入／输出，由istream和ostream派生出了iostream类。 </p><p>　　类的继承关系见下图：<br /><img src="http://www.cppblog.com/images/cppblog_com/andxie99/05cppios02.gif" /></p><p>iostream库定义了以下三个标准流对象： </p><ol><li>cin，表示标准输入(standard input)的istream类对象。cin使我们可以从设备读入数据。 
</li><li>cout，表示标准输出(standard output)的ostream类对象。cout使我们可以向设备输出或者写数据。 
</li><li>cerr，表示标准错误(standard error)的osttream类对象。cerr是导出程序错误消息的地方，它只能允许向屏幕设备写数据。 </li></ol><p>　　输出主要由重载的左移操作符（&lt;&lt;）来完成，输入主要由重载的右移操作符(&gt;&gt;)完成: </p><ol><li>&gt;&gt;a表示将数据放入a对象中。 
</li><li>&lt;&lt;a表示将a对象中存储的数据拿出。 </li></ol><p>　　这些标准的流对象都有默认的所对应的设备，见下表：<br /></p><table class="twikiTable" cellspacing="1" cellpadding="1" border="0"><tbody><tr><th class="twikiFirstCol" bgcolor="#dadada"><font color="#000000">C++对象名</font></th><th bgcolor="#dadada"><font color="#000000">设备名称</font></th><th bgcolor="#dadada"><font color="#000000">C中标准设备名</font></th><th bgcolor="#dadada"><font color="#000000">默认含义</font></th></tr><tr><td class="twikiFirstCol" align="middle" bgcolor="#ffffff">cin </td><td align="middle" bgcolor="#ffffff">键盘 </td><td align="middle" bgcolor="#ffffff">stdin </td><td align="middle" bgcolor="#ffffff">标准输入 </td></tr><tr><td class="twikiFirstCol" align="middle" bgcolor="#eaeaea">cout </td><td align="middle" bgcolor="#eaeaea">显示器屏幕 </td><td align="middle" bgcolor="#eaeaea">stdout </td><td align="middle" bgcolor="#eaeaea">标准输出 </td></tr><tr><td class="twikiFirstCol" align="middle" bgcolor="#ffffff">cerr </td><td align="middle" bgcolor="#ffffff">显示器屏幕 </td><td align="middle" bgcolor="#ffffff">stderr </td><td align="middle" bgcolor="#ffffff">标准错误输出 </td></tr></tbody></table>　　上表中的意思表明cin对象的默认输入设备是键盘，cout对象的默认输出设备是显示器屏幕。 
<p>　　那么原理上Ｃ++有是如何利用cin／cout对象与左移和右移运算符重载来实现输入输出的呢？ </p><p>　　下面我们以输出为例，说明其实现原理： </p><ol><li>cout是ostream类的对象，因为它所指向的是标准设备（显示器屏幕），所以它在iostream头文件中作为全局对象进行定义。 
</li><li>ostream cout(stdout);//其默认指向的C中的标准设备名，作为其构造函数的参数使用。 
</li><li>在iostream.h头文件中，ostream类对应每个基本数据类型都有其友元函数对左移操作符进行了友元函数的重载。 
<ul><li>ostream&amp; operator&lt;&lt;(ostream &amp;temp,int source); 
</li><li>ostream&amp; operator&lt;&lt;(ostream &amp;temp,char *ps); 
</li><li>... 等等 </li></ul></li></ol><p>　　一句输出语句：cout&lt;&lt;"http://www.cppblog.com/andxie99";，事实上调用的就是ostream&amp; operator&lt;&lt;(ostream &amp;temp,char *ps);这个运算符重载函数，由于返回的是流对象的引用，引用可以作为左值使用，所以当程序中有类似cout&lt;&lt;"http://www.cppblog.com/andxie99"&lt;&lt;"白纸人生";这样的语句出现的时候，就能够构成连续输出。 </p><p>　　由于iostream库不光支持对象的输入输出，同时也支持文件流的输入输出，所以在详细讲解左移与右移运算符重载之前，我们有必要先对文件的输入输出以及输入输出的控制符有所了解。 </p><h3><a name="2 fstream: ifstream 和 ofstream"></a>2 fstream: ifstream 和 ofstream </h3>　　和文件有关系的输入输出类主要在fstream.h这个头文件中被定义，在这个头文件中主要被定义了三个类，由这三个类控制对文件的各种输入输出操作，他们分别是ifstream、ofstream、fstream，其中fstream类是由iostream类派生而来，他们之间的继承关系见下图所示。<br /><img src="http://www.cppblog.com/images/cppblog_com/andxie99/05cppios04.gif" /><p>由于文件设备并不像显示器屏幕与键盘那样是标准默认设备，所以它在fstream.h头文件中是没有像cout那样预先定义的全局对象，所以我们必须自己定义一个该类的对象，我们要以文件作为设备向文件输出信息(也就是向文件写数据)，那么就应该使用ofstream类。 </p><p>　　ofstream类的默认构造函数原形为： </p><div class="fragment"><pre style="PADDING-BOTTOM: 16px">　　ofstream::ofstream(<font color="brown">const</font><font color="brown">char</font> *filename,<font color="brown">int</font> mode = ios::out,<br /><font color="brown">                     int</font> openprot = filebuf::openprot);</pre><pre style="PADDING-BOTTOM: 0px"></pre></div><ul><li>filename：　　要打开的文件名 
</li><li>mode：　　　　要打开文件的方式 
</li><li>prot：　　　　打开文件的属性 </li></ul><p>　　其中mode和openprot这两个参数的可选项表见下表： </p><table class="twikiTable" cellspacing="1" cellpadding="1" border="0"><tbody><tr><td class="twikiFirstCol" align="middle" bgcolor="#eaeaea" colspan="2">mode属性表 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">ios::app </td><td bgcolor="#ffffff">以追加的方式打开文件 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">ios::ate </td><td bgcolor="#eaeaea">文件打开后定位到文件尾，ios:app就包含有此属性 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">ios::binary </td><td bgcolor="#ffffff">以二进制方式打开文件，缺省的方式是文本方式。两种方式的区别见前文 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">ios::in </td><td bgcolor="#eaeaea">文件以输入方式打开 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">ios::out </td><td bgcolor="#ffffff">文件以输出方式打开 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">ios::trunc </td><td bgcolor="#eaeaea">如果文件存在，把文件长度设为0 </td></tr></tbody></table>　　可以用“或”把以上属性连接起来，如ios::out|ios::binary。 
<table class="twikiTable" cellspacing="1" cellpadding="1" border="0"><tbody><tr><td class="twikiFirstCol" align="middle" bgcolor="#eaeaea" colspan="2">openprot属性表 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">属性 </td><td align="middle" bgcolor="#ffffff">含义 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">0 </td><td bgcolor="#eaeaea">普通文件，打开访问 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">1 </td><td bgcolor="#ffffff">只读文件 </td></tr><tr><td class="twikiFirstCol" bgcolor="#eaeaea">2 </td><td bgcolor="#eaeaea">隐含文件 </td></tr><tr><td class="twikiFirstCol" bgcolor="#ffffff">4 </td><td bgcolor="#ffffff">系统文件 </td></tr></tbody></table>　　可以用“或”或者“+”把以上属性连接起来 ，如3或1|2就是以只读和隐含属性打开文件。 
<p>实例代码如下： </p><div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="navy">#include</font> &lt;fstream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 

<font color="brown">int</font> main()  
{ 
        ofstream myfile("<font color="blue">c:\\1.txt</font>",ios::out|ios::trunc,0); 
        myfile&lt;&lt;"<font color="blue">白纸人生</font>"&lt;&lt;endl&lt;&lt;"<font color="blue">网址：</font>"&lt;&lt;"<font color="blue">www.cppblog.com/andxie99</font>"; 
        myfile.close() 
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　文件使用完后可以使用close成员函数关闭文件。 
<p>　　ios::app为追加模式，在使用追加模式的时候同时进行文件状态的判断是一个比较好的习惯。 </p><p>　　示例如下： </p><p></p><div class="fragment"><pre style="PADDING-BOTTOM: 16px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="navy">#include</font> &lt;fstream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 
<font color="brown">int</font> main()  
{ 
        ofstream myfile("<font color="blue">c:\\1.txt</font>",ios::app,0); 
        <font color="brown">if</font>(!myfile)<font color="green">//或者写成myfile.fail() </font>
        { 
                cout&lt;&lt;"<font color="blue">文件打开失败，目标文件状态可能为只读！</font>"; 
                system("<font color="blue">pause</font>"); 
                exit(1); 
        } 
        myfile&lt;&lt;"<font color="blue">白纸人生</font>"&lt;&lt;endl&lt;&lt;"<font color="blue">网址：</font>"&lt;&lt;"<font color="blue">www.cppblog.com/andxie99</font>"&lt;&lt;endl; 
        myfile.close(); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div><p>　　在定义ifstream和ofstream类对象的时候，我们也可以不指定文件。以后可以通过成员函数open()显式的把一个文件连接到一个类对象上。 </p><p>　　例如： </p><p></p><div class="fragment"><pre style="PADDING-BOTTOM: 16px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="navy">#include</font> &lt;fstream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 
<font color="brown">int</font> main()  
{ 
        ofstream myfile; 
        myfile.open("<font color="blue">c:\\1.txt</font>",ios::out|ios::app,0); 
        <font color="brown">if</font>(!myfile)<font color="green">//或者写成myfile.fail() </font>
        { 
                cout&lt;&lt;"<font color="blue">文件创建失败,磁盘不可写或者文件为只读!</font>"; 
                system("<font color="blue">pause</font>"); 
                exit(1); 
        } 
        myfile&lt;&lt;"<font color="blue">白纸人生</font>"&lt;&lt;endl&lt;&lt;"<font color="blue">网址：</font>"&lt;&lt;"<font color="blue">www.cppblog.com/andxie99</font>"&lt;&lt;endl; 
        myfile.close(); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　下面我们来看一下是如何利用ifstream类对象，将文件中的数据读取出来，然后再输出到标准设备中的例子。 
<p>　　代码如下： </p><div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="navy">#include</font> &lt;fstream&gt; 
<font color="navy">#include</font> &lt;string&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 
<font color="brown">int</font> main()  
{ 
        ifstream myfile; 
        myfile.open("<font color="blue">c:\\1.txt</font>",ios::in,0); 
        <font color="brown">if</font>(!myfile) 
        { 
                cout&lt;&lt;"<font color="blue">文件读错误</font>"; 
                system("<font color="blue">pause</font>"); 
                exit(1); 
        } 
        <font color="brown">char</font> ch; 
        string content; 
        <font color="brown">while</font>(myfile.get(ch)) 
        { 
                content+=ch; 
                cout.put(ch);<font color="green">//cout&lt;&lt;ch;这么写也是可以的 </font>
        } 
        myfile.close(); 
        cout&lt;&lt;content; 
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　上例中，我们利用成员函数get()，逐一的读取文件中的有效字符，再利用put()成员函数，将文件中的数据通过循环逐一输出到标准设备(屏幕)上， get()成员函数会在文件读到默尾的时候返回假值，所以我们可以利用它的这个特性作为while循环的终止条件，我们同时也在上例中引入了C++风格的字符串类型string，在循环读取的时候逐一保存到content中，要使用string类型，必须包含string.h的头文件。 
<p></p><p>我们在简单介绍过ofstream类和ifstream类后，我们再来看一下fstream类，fstream类是由iostream派生而来，fstream类对象可以同对文件进行读写操作。 </p><p>　　示例代码如下： </p><div class="fragment"><pre style="PADDING-BOTTOM: 16px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="navy">#include</font> &lt;fstream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 
<font color="brown">int</font> main()  
{ 
        fstream myfile; 
        myfile.open("<font color="blue">c:\\1.txt</font>",ios::out|ios::app,0); 
        <font color="brown">if</font>(!myfile) 
        { 
                cout&lt;&lt;"<font color="blue">文件写错误,文件属性可能为只读!</font>"&lt;&lt;endl; 
                system("<font color="blue">pause</font>"); 
                exit(1); 
        } 
        myfile&lt;&lt;"<font color="blue">白纸人生</font>"&lt;&lt;endl&lt;&lt;"<font color="blue">网址：</font>"&lt;&lt;"<font color="blue">www.cppblog.com/andxie99</font>"&lt;&lt;endl;   
        myfile.close(); 
        
        myfile.open("<font color="blue">c:\\1.txt</font>",ios::in,0); 
        <font color="brown">if</font>(!myfile) 
        { 
                cout&lt;&lt;"<font color="blue">文件读错误,文件可能丢失!</font>"&lt;&lt;endl; 
                system("<font color="blue">pause</font>"); 
                exit(1); 
        } 
        <font color="brown">char</font> ch; 
        <font color="brown">while</font>(myfile.get(ch)) 
        { 
                cout.put(ch); 
        } 
        myfile.close(); 
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　由于fstream类可以对文件同时进行读写操作，所以对它的对象进行初始话的时候一定要显式的指定mode和openprot参数。 
<p>　　接下来我们来学习一下串流类的基础知识，什么叫串流类？ </p><h3><a name="3 strstream: ostrstream 和 istrs"></a>3 strstream: ostrstream 和 istrstream </h3>　　简单的理解就是能够控制字符串类型对象进行输入输出的类，C++不光可以支持C++风格的字符串流控制，还可以支持C风格的字符串流控制。 
<p>　　我们先看看看C++是如何对C风格的字符串流进行控制的，C中的字符串其实也就是字符数组，字符数组内的数据在内存中的位置的排列是连续的，我们通常用 char str[size]或者char *str的方式声明创建C风格字符数组，为了能让字符数组作为设备并提供输入输出操作，C++引入了ostrstream、istrstream、 strstream这三个类，要使用他们创建对象就必须包含strstream.h头文件。 </p><ul><li>istrstream类用于执行C风格的串流的输入操作，也就是以字符串数组作为输入设备。 
</li><li>ostrstream类用于执行C风格的串流的输出操作，也就是一字符串数组作为输出设备。 
</li><li>strstream类同时可以支持C风格的串流的输入输出操作。 </li></ul><p>　　istrstream类是从istream（输入流类）和strstreambase（字符串流基类）派生而来，ostrstream是从 ostream（输出流类）和strstreambase（字符串流基类）派生而来，strstream则是从iostream(输入输出流类)和和 strstreambase（字符串流基类）派生而来。 </p><p>　　他们的继承关系如下图所示:<br /><img src="http://www.cppblog.com/images/cppblog_com/andxie99/05cppios05.gif" /></p><p>　　串流同样不是标准设备，不会有预先定义好的全局对象，所以不能直接操作，需要通过构造函数创建对象。 </p><p>类istrstream的构造函数原形如下： </p><div class="fragment"><pre style="PADDING-BOTTOM: 0px">　　istrstream::istrstream(<font color="brown">const</font><font color="brown">char</font> *str,<font color="brown">int</font> size);</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　参数1表示字符串数组,而参数2表示数组大小，当size为0时，表示istrstream类对象直接连接到由str所指向的内存空间并以\0结尾的字符串。 
<p>　　下面的示例代码就是利用istrstream类创建类对象，制定流输入设备为字符串数组，通过它向一个字符型对象输入数据。代码如下： </p><div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="navy">#include</font> &lt;strstream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 
<font color="brown">int</font> main()  
{ 
        <font color="brown">char</font> *name = "<font color="blue">www.cppblog.com/andxie99</font>"; 
        <font color="brown">int</font> arraysize = strlen(name)+1; 
        istrstream is(name,arraysize); 
        <font color="brown">char</font> temp; 
        is&gt;&gt;temp; 
        cout&lt;&lt;temp; 
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　类ostrstream用于执行串流的输出，它的构造函数如下所示： 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px">　　ostrstream::ostrstream(<font color="brown">char</font> *_Ptr,<font color="brown">int</font> streamsize,<font color="brown">int</font> Mode = ios::out);</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　第一个参数是字符数组，第二个是说明数组的大小，第三个参数是指打开方式。 
<p>　　我们来一个示例代码： </p><div class="fragment"><pre style="PADDING-BOTTOM: 16px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="navy">#include</font> &lt;strstream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 
<font color="brown">int</font> main()  
{ 
        <font color="brown">int</font> arraysize=1; 
        <font color="brown">char</font> *pbuffer=<font color="brown">new</font><font color="brown">char</font>[arraysize]; 
        ostrstream ostr(pbuffer,arraysize,ios::out); 
        ostr&lt;&lt;arraysize&lt;&lt;ends;<font color="green">//使用ostrstream输出到流对象的时候,要用ends结束字符串 </font>
        cout&lt;&lt;pbuffer; 
        <font color="brown">delete</font>[] pbuffer; 
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　上面的代码中，我们创建一个c风格的串流输出对象ostr，我们将arraysize内的数据成功的以字符串的形式输出到了ostr对象所指向的pbuffer指针的堆空间中，pbuffer也正是我们要输出的字符串数组，在结尾要使用ends结束字符串，如果不这么做就有溢出的危险。 
<h3><a name="4 stringstream"></a>4 stringstream </h3>对于stringstream了来说，不用我多说，大家也已经知道它是用于C++风格的字符串的输入输出的。　　stringstream的构造函数原形如下： 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px">　　stringstream::stringstream(string str);</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　示例代码如下: 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="navy">#include</font> &lt;sstream&gt; 
<font color="navy">#include</font> &lt;string&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 

<font color="brown">int</font> main()  
{ 
        stringstream ostr("<font color="blue">ccc</font>"); 
        ostr.put('d'); 
        ostr.put('e'); 
        ostr&lt;&lt;"<font color="blue">fg</font>"; 
        string gstr = ostr.str(); 
        cout&lt;&lt;gstr&lt;&lt;endl; 
        
        <font color="brown">char</font> a; 
        ostr&gt;&gt;a; 
        cout&lt;&lt;a 
        
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　除此而外，stringstream类的对象我们还常用它进行string与各种内置类型数据之间的转换。示例代码如下： 
<div class="fragment"><pre style="PADDING-BOTTOM: 16px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="navy">#include</font> &lt;sstream&gt; 
<font color="navy">#include</font> &lt;string&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 

<font color="brown">int</font> main()  
{ 
        stringstream sstr; 
        <font color="green">//--------int转string----------- </font><font color="brown">int</font> a=100; 
        string str; 
        sstr&lt;&lt;a; 
        sstr&gt;&gt;str; 
        cout&lt;&lt;str&lt;&lt;endl; 
        <font color="green">//--------string转char[]-------- </font>
        sstr.clear();<font color="green">//如果你想通过使用同一stringstream对象实现多种类型的转换，<br />                        //请注意在每一次转换之后都必须调用clear()成员函数。 </font>
        string name = "<font color="blue">colinguan</font>"; 
        <font color="brown">char</font> cname[200]; 
        sstr&lt;&lt;name; 
        sstr&gt;&gt;cname; 
        cout&lt;&lt;cname; 
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　接下来我们来学习一下输入/输出的状态标志的相关知识. 
<h3><a name="5 io_state 输入/输出的状态标志"></a>5 io_state 输入/输出的状态标志 </h3>C++中负责的输入/输出的系统包括了关于每一个输入/输出操作的结果的记录信息。这些当前的状态信息被包含在io_state类型的对象中。io_state是一个枚举类型（就像open_mode一样），以下便是它包含的值。 
<ul><li>goodbit 无错误 
</li><li>Eofbit 已到达文件尾 
</li><li>failbit 非致命的输入/输出错误，可挽回 
</li><li>badbit　致命的输入/输出错误,无法挽回 </li></ul><p>有两种方法可以获得输入/输出的状态信息。一种方法是通过调用rdstate()函数，它将返回当前状态的错误标记。例如，假如没有任何错误，则rdstate()会返回goodbit.下例示例，表示出了rdstate()的用法： </p><div class="fragment"><pre style="PADDING-BOTTOM: 16px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 

<font color="brown">int</font> main()  
{ 
        <font color="brown">int</font> a; 
        cin&gt;&gt;a; 
        cout&lt;&lt;cin.rdstate()&lt;&lt;endl; 
        <font color="brown">if</font>(cin.rdstate() == ios::goodbit) 
        { 
                cout&lt;&lt;"<font color="blue">输入数据的类型正确，无错误！</font>"&lt;&lt;endl; 
        } 
        <font color="brown">if</font>(cin.rdstate() == ios_base::failbit) 
        { 
                cout&lt;&lt;"<font color="blue">输入数据类型错误，非致命错误，可清除输入缓冲区挽回！</font>"&lt;&lt;endl; 
        } 
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　另一种方法则是使用下面任何一个函数来检测相应的输入/输出状态： 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="brown">bool</font> bad();
<font color="brown">bool</font> eof();
<font color="brown">bool</font> fail();
<font color="brown">bool</font> good();</pre><pre style="PADDING-BOTTOM: 0px"></pre></div><p>　　下例示例，表示出了上面各成员函数的用法： </p><div class="fragment"><pre style="PADDING-BOTTOM: 16px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 

<font color="brown">int</font> main()  
{ 
        <font color="brown">int</font> a; 
        cin&gt;&gt;a; 
        cout&lt;&lt;cin.rdstate()&lt;&lt;endl; 
        <font color="brown">if</font>(cin.good()) 
        { 
                cout&lt;&lt;"<font color="blue">输入数据的类型正确，无错误！</font>"&lt;&lt;endl; 
        } 
        <font color="brown">if</font>(cin.fail()) 
        { 
                cout&lt;&lt;"<font color="blue">输入数据类型错误，非致命错误，可清除输入缓冲区挽回！</font>"&lt;&lt;endl; 
        } 
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　如果错误发生，那么流状态既被标记为错误，你必须清除这些错误状态，以使你的程序能正确适当地继续运行。要清除错误状态，需使用clear()函数。此函数带一个参数，它是你将要设为当前状态的标志值。，只要将ios::goodbit作为实参。 
<p>　　示例代码如下： </p><div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 

<font color="brown">int</font> main()  
{ 
        <font color="brown">int</font> a; 
        cin&gt;&gt;a; 
        cout&lt;&lt;cin.rdstate()&lt;&lt;endl; 
        cin.clear(ios::goodbit); 
        cout&lt;&lt;cin.rdstate()&lt;&lt;endl; 
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>通常当我们发现输入有错又需要改正的时候，使用clear()更改标记为正确后，同时也需要使用get()成员函数清除输入缓冲区，以达到重复输入的目的。 
<p>　　示例代码如下： </p><div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 

<font color="brown">int</font> main()  
{ 
        <font color="brown">int</font> a; 
        <font color="brown">while</font>(1) 
        { 
                cin&gt;&gt;a; 
                <font color="brown">if</font>(!cin)<font color="green">//条件可改写为cin.fail() </font>
                { 
                        cout&lt;&lt;"<font color="blue">输入有错!请重新输入</font>"&lt;&lt;endl; 
                        cin.clear(); 
                        cin.get(); 
                } 
                <font color="brown">else</font> 
                { 
                        cout&lt;&lt;a; 
                        <font color="brown">break</font>; 
                } 
        } 
        system("<font color="blue">pause</font>"); 
}</pre><pre style="PADDING-BOTTOM: 0px"></pre></div>　　最后再给出一个对文件流错误标记处理的例子，巩固学习，代码如下： 
<div class="fragment"><pre style="PADDING-BOTTOM: 0px"><font color="navy">#include</font> &lt;iostream&gt; 
<font color="navy">#include</font> &lt;fstream&gt; 
<font color="brown">using</font><font color="brown">namespace</font> std; 

<font color="brown">int</font> main()  
{ 
        ifstream myfile("<font color="blue">c:\\1.txt</font>",ios_base::in,0); 
        <font color="brown">if</font>(myfile.fail()) 
        { 
                cout&lt;&lt;"<font color="blue">文件读取失败或指定文件不存在!</font>"&lt;&lt;endl; 
        } 
        <font color="brown">else</font> 
        { 
                <font color="brown">char</font> ch; 
                <font color="brown">while</font>(myfile.get(ch)) 
                { 
                        cout&lt;&lt;ch; 
                } 
                <font color="brown">if</font>(myfile.eof()) 
                { 
                        cout&lt;&lt;"<font color="blue">文件内容已经全部读完</font>"&lt;&lt;endl; 
                } 
                <font color="brown">while</font>(myfile.get(ch)) 
                { 
                        cout&lt;&lt;ch; 
                } 
        } 
        system("<font color="blue">pause</font>"); 
}</pre></div><img src ="http://www.cppblog.com/andxie99/aggbug/9132.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-06-29 08:21 <a href="http://www.cppblog.com/andxie99/archive/2006/06/29/9132.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++内存分配的五种方法的区别</title><link>http://www.cppblog.com/andxie99/archive/2006/06/20/8737.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Tue, 20 Jun 2006 04:33:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/06/20/8737.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/8737.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/06/20/8737.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/8737.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/8737.html</trackback:ping><description><![CDATA[　　在C++中，内存分成5个区，他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 <br><br>　　栈，就是那些由编译器在需要的时候分配，在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。 <br><br>　　堆，就是那些由new分配的内存块，他们的释放编译器不去管，由我们的应用程序去控制，一般一个new就要对应一个delete。如果程序员没有释放掉，那么在程序结束后，操作系统会自动回收。 <br><br>　　自由存储区，就是那些由malloc等分配的内存块，他和堆是十分相似的，不过它是用free来结束自己的生命的。 <br><br>　　全局/静态存储区，全局变量和静态变量被分配到同一块内存中，在以前的C语言中，全局变量又分为初始化的和未初始化的，在C++里面没有这个区分了，他们共同占用同一块内存区。 <br><br>　　常量存储区，这是一块比较特殊的存储区，他们里面存放的是常量，不允许修改（当然，你要通过非正当手段也可以修改，而且方法很多，在《const的思考》一文中，我给出了6种方法） <br><br>　　明确区分堆与栈 <br><br>　　在bbs上，堆与栈的区分问题，似乎是一个永恒的话题，由此可见，初学者对此往往是混淆不清的，所以我决定拿他第一个开刀。 <br><br>　　首先，我们举一个例子： <br><br>void f() { int* p=new int[5]; } <br><br>　　这条短短的一句话就包含了堆与栈，看到new，我们首先就应该想到，我们分配了一块堆内存，那么指针p呢？他分配的是一块栈内存，所以这句话的意思就是：在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小，然后调用operator new分配内存，然后返回这块内存的首地址，放入栈中，他在VC6下的汇编代码如下： <br><br>00401028 push 14h <br>0040102A call operator new (00401060) <br>0040102F add esp,4 <br>00401032 mov dword ptr [ebp-8],eax <br>00401035 mov eax,dword ptr [ebp-8] <br>00401038 mov dword ptr [ebp-4],eax <br><br>　　这里，我们为了简单并没有释放内存，那么该怎么去释放呢？是delete p么？澳，错了，应该是delete []p，这是为了告诉编译器：我删除的是一个数组，VC6就会根据相应的Cookie信息去进行释放内存的工作。 <br><br>　　好了，我们回到我们的主题：堆和栈究竟有什么区别？ <br><br>　　主要的区别由以下几点： <br><br>　　1、管理方式不同； <br><br>　　2、空间大小不同； <br><br>　　3、能否产生碎片不同； <br><br>　　4、生长方向不同； <br><br>　　5、分配方式不同； <br><br>　　6、分配效率不同； <br><br>　　管理方式：对于栈来讲，是由编译器自动管理，无需我们手工控制；对于堆来说，释放工作由程序员控制，容易产生memory leak。 <br><br>　　空间大小：一般来讲在32位系统下，堆内存可以达到4G的空间，从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲，一般都是有一定的空间大小的，例如，在VC6下面，默认的栈空间大小是1M（好像是，记不清楚了）。当然，我们可以修改： <br><br>　　打开工程，依次操作菜单如下：Project-&gt;Setting-&gt;Link，在Category 中选中Output，然后在Reserve中设定堆栈的最大值和commit。 <br><br>　　注意：reserve最小值为4Byte；commit是保留在虚拟内存的页文件里面，它设置的较大会使栈开辟较大的值，可能增加内存的开销和启动时间。 <br><br>　　碎片问题：对于堆来讲，频繁的new/delete势必会造成内存空间的不连续，从而造成大量的碎片，使程序效率降低。对于栈来讲，则不会存在这个问题，因为栈是先进后出的队列，他们是如此的一一对应，以至于永远都不可能有一个内存块从栈中间弹出，在他弹出之前，在他上面的后进的栈内容已经被弹出，详细的可以参考数据结构，这里我们就不再一一讨论了。 <br><br>　　生长方向：对于堆来讲，生长方向是向上的，也就是向着内存地址增加的方向；对于栈来讲，它的生长方向是向下的，是向着内存地址减小的方向增长。 <br><br>　　分配方式：堆都是动态分配的，没有静态分配的堆。栈有2种分配方式：静态分配和动态分配。静态分配是编译器完成的，比如局部变量的分配。动态分配由alloca函数进行分配，但是栈的动态分配和堆是不同的，他的动态分配是由编译器进行释放，无需我们手工实现。 <br><br>　　分配效率：栈是机器系统提供的数据结构，计算机会在底层对栈提供支持：分配专门的寄存器存放栈的地址，压栈出栈都有专门的指令执行，这就决定了栈的效率比较高。堆则是C/C++函数库提供的，它的机制是很复杂的，例如为了分配一块内存，库函数会按照一定的算法（具体的算法可以参考数据结构/操作系统）在堆内存中搜索可用的足够大小的空间，如果没有足够大小的空间（可能是由于内存碎片太多），就有可能调用系统功能去增加程序数据段的内存空间，这样就有机会分到足够大小的内存，然后进行返回。显然，堆的效率比栈要低得多。<br><br>　　从这里我们可以看到，堆和栈相比，由于大量new/delete的使用，容易造成大量的内存碎片；由于没有专门的系统支持，效率很低；由于可能引发用户态和核心态的切换，内存的申请，代价变得更加昂贵。所以栈在程序中是应用最广泛的，就算是函数的调用也利用栈去完成，函数调用过程中的参数，返回地址，EBP和局部变量都采用栈的方式存放。所以，我们推荐大家尽量用栈，而不是用堆。 <br><br>　　虽然栈有如此众多的好处，但是由于和堆相比不是那么灵活，有时候分配大量的内存空间，还是用堆好一些。 <br><br>　　无论是堆还是栈，都要防止越界现象的发生（除非你是故意使其越界），因为越界的结果要么是程序崩溃，要么是摧毁程序的堆、栈结构，产生以想不到的结果,就算是在你的程序运行过程中，没有发生上面的问题，你还是要小心，说不定什么时候就崩掉，那时候debug可是相当困难的：） 
<img src ="http://www.cppblog.com/andxie99/aggbug/8737.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-06-20 12:33 <a href="http://www.cppblog.com/andxie99/archive/2006/06/20/8737.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>static_cast&lt;&gt;揭密</title><link>http://www.cppblog.com/andxie99/archive/2006/06/14/8545.html</link><dc:creator>思勤无邪</dc:creator><author>思勤无邪</author><pubDate>Wed, 14 Jun 2006 06:54:00 GMT</pubDate><guid>http://www.cppblog.com/andxie99/archive/2006/06/14/8545.html</guid><wfw:comment>http://www.cppblog.com/andxie99/comments/8545.html</wfw:comment><comments>http://www.cppblog.com/andxie99/archive/2006/06/14/8545.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/andxie99/comments/commentRss/8545.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/andxie99/services/trackbacks/8545.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<p>
												<br />作者：Sam NG </p>
										<p>译者：<a href="mailto:zhaotide@vckbase.com">小刀人</a></p>
										<p>
												<br />原文链接：<a href="http://www.codeproject.com/cpp/static_cast.asp">What static_cast&lt;&gt; is actually doing</a><br /><br />本文讨论static_cast&lt;&gt; 和 reinterpret_cast&lt;&gt;。 </p>
										<p>
												<strong>介绍</strong>
												<br />大多程序员在学C++前都学过C，并且习惯于C风格（类型）转换。当写C++（程序）时，有时候我们在使用static_cast&lt;&gt;和reinterpret_cast&lt;&gt;时可能会有点模糊。在本文中，我将说明static_cast&lt;&gt;实际上做了什么，并且指出一些将会导致错误的情况。<br /><br /><strong>泛型（Generic Types）</strong><br /><br /></p>
										<pre style="PADDING-RIGHT: 5pt; PADDING-LEFT: 5pt; PADDING-BOTTOM: 5pt; FONT: 14px 'Courier New', Courier, mono; WIDTH: 100%; COLOR: #003399; PADDING-TOP: 5pt; BACKGROUND-COLOR: #f5f5f0">        float f = 12.3;<br />
        float* pf = &amp;f;
      <p>// static cast&lt;&gt;<br />
        // 成功编译, n = 12<br />
        int n = static_cast&lt;int&gt;(f);<br />
        // 错误,指向的类型是无关的（译注：即指针变量pf是float类型，现在要被转换为int类型）
        //int* pn = static_cast&lt;int*&gt;(pf);<br />
        //成功编译<br />
        void* pv = static_cast&lt;void*&gt;(pf);<br />
        //成功编译, 但是 *pn2是无意义的内存（rubbish）<br />
        int* pn2 = static_cast&lt;int*&gt;(pv);</p><p>// reinterpret_cast&lt;&gt;<br />
        //错误,编译器知道你应该调用static_cast&lt;&gt;<br />
        //int i = reinterpret_cast&lt;int&gt;(f);<br />
        //成功编译, 但是 *pn 实际上是无意义的内存,和 *pn2一样<br />
        int* pi = reinterpret_cast&lt;int*&gt;(pf);</p></pre>简而言之，static_cast&lt;&gt; 将尝试转换，举例来说，如float-到-integer，而reinterpret_cast&lt;&gt;简单改变编译器的意图重新考虑那个对象作为另一类型。<br /><br /><strong>指针类型（Pointer Types）</strong><br /><br />指针转换有点复杂，我们将在本文的剩余部分使用下面的类：<br /><pre style="PADDING-RIGHT: 5pt; PADDING-LEFT: 5pt; PADDING-BOTTOM: 5pt; FONT: 14px 'Courier New', Courier, mono; WIDTH: 100%; COLOR: #003399; PADDING-TOP: 5pt; BACKGROUND-COLOR: #f5f5f0">class CBaseX<br />
      {<br />
      public:<br />
      int x;<br />
      CBaseX() { x = 10; }<br />
      void foo() { printf("CBaseX::foo() x=%d\n", x); }<br />
      };
      <p>class CBaseY<br />
        {<br />
        public:<br />
        int y;<br />
        int* py;<br />
        CBaseY() { y = 20; py = &amp;y; }<br />
        void bar() { printf("CBaseY::bar() y=%d, *py=%d\n", y, *py); 
        }<br />
        };</p><p>class CDerived : public CBaseX, public CBaseY<br />
        {<br />
        public:<br />
        int z;<br />
        };</p></pre><strong>情况1：两个无关的类之间的转换 </strong><br /><br /><pre style="PADDING-RIGHT: 5pt; PADDING-LEFT: 5pt; PADDING-BOTTOM: 5pt; FONT: 14px 'Courier New', Courier, mono; WIDTH: 100%; COLOR: #003399; PADDING-TOP: 5pt; BACKGROUND-COLOR: #f5f5f0">      // Convert between CBaseX* and CBaseY*<br />
      // CBaseX* 和 CBaseY*之间的转换<br />
      CBaseX* pX = new CBaseX();<br />
      // Error, types pointed to are unrelated<br />
      // 错误， 类型指向是无关的<br />
      // CBaseY* pY1 = static_cast&lt;CBaseY*&gt;(pX);<br />
      // Compile OK, but pY2 is not CBaseX<br />
      // 成功编译, 但是 pY2 不是CBaseX<br />
      CBaseY* pY2 = reinterpret_cast&lt;CBaseY*&gt;(pX);<br />
      // System crash!!<br />
      // 系统崩溃!!<br />
      // pY2-&gt;bar();</pre>正如我们在泛型例子中所认识到的，如果你尝试转换一个对象到另一个无关的类static_cast&lt;&gt;将失败，而reinterpret_cast&lt;&gt;就总是成功“欺骗”编译器：那个对象就是那个无关类。<br /><br /><strong>情况2：转换到相关的类</strong><br /><pre style="PADDING-RIGHT: 5pt; PADDING-LEFT: 5pt; PADDING-BOTTOM: 5pt; FONT: 14px 'Courier New', Courier, mono; WIDTH: 100%; COLOR: #003399; PADDING-TOP: 5pt; BACKGROUND-COLOR: #f5f5f0">      1. CDerived* pD = new CDerived();<br />
      2. printf("CDerived* pD = %x\n", (int)pD);<br />
      3. <br />
      4. // static_cast&lt;&gt; CDerived* -&gt; CBaseY* -&gt; CDerived*<br />
      //成功编译，隐式static_cast&lt;&gt;转换<br />
      5. CBaseY* pY1 = pD;<br />
      6. printf("CBaseY* pY1 = %x\n", (int)pY1);<br />
      // 成功编译, 现在 pD1 = pD<br />
      7. CDerived* pD1 = static_cast&lt;CDerived*&gt;(pY1);<br />
      8. printf("CDerived* pD1 = %x\n", (int)pD1);<br />
      9. <br />
      10. // reinterpret_cast<br />
      // 成功编译, 但是 pY2 不是 CBaseY*<br />
      11. CBaseY* pY2 = reinterpret_cast&lt;CBaseY*&gt;(pD);<br />
      12. printf("CBaseY* pY2 = %x\n", (int)pY2);<br />
      13. <br />
      14. // 无关的 static_cast&lt;&gt;<br />
      15. CBaseY* pY3 = new CBaseY();<br />
      16. printf("CBaseY* pY3 = %x\n", (int)pY3);<br />
      // 成功编译,尽管 pY3 只是一个 "新 CBaseY()"<br />
      17. CDerived* pD3 = static_cast&lt;CDerived*&gt;(pY3);<br />
      18. printf("CDerived* pD3 = %x\n", (int)pD3);<br /></pre><pre style="PADDING-RIGHT: 5pt; PADDING-LEFT: 5pt; PADDING-BOTTOM: 5pt; FONT: 14px 'Courier New', Courier, mono; WIDTH: 100%; COLOR: #003399; PADDING-TOP: 5pt; BACKGROUND-COLOR: #f5f5f0">      ---------------------- 输出 ---------------------------<br />
      CDerived* pD = 392fb8<br />
      CBaseY* pY1 = 392fbc<br />
      CDerived* pD1 = 392fb8<br />
      CBaseY* pY2 = 392fb8<br />
      CBaseY* pY3 = 390ff0<br />
      CDerived* pD3 = 390fec<br /><br /></pre><p>注意：在将CDerived*用隐式 static_cast&lt;&gt;转换到CBaseY*（第5行）时，结果是（指向）CDerived*（的指针向后） 偏移了4（个字节）（译注：4为int类型在内存中所占字节数）。为了知道static_cast&lt;&gt; 实际如何，我们不得不要来看一下CDerived的内存布局。</p><p align="left"><strong>CDerived的内存布局（Memory Layout）</strong><br /><br /><img height="224" alt="static_cast_layout.gif" src="http://www.cppblog.com/images/cppblog_com/andxie99/static_cast_layout.gif" width="355" border="0" /><br /><br />如图所示，CDerived的内存布局包括两个对象，CBaseX 和 CBaseY，编译器也知道这一点。因此，当你将CDerived* 转换到 CBaseY*时，它给指针添加4个字节，同时当你将CBaseY*转换到CDerived*时，它给指针减去4。然而，甚至它即便不是一个CDerived你也可以这样做。<br />当然，这个问题只在如果你做了多继承时发生。在你将CDerived转换 到 CBaseX时static_cast&lt;&gt; 和 reinterpret_cast&lt;&gt;是没有区别的。<br /><br /><strong>情况3：void*之间的向前和向后转换</strong><br /><br />因为任何指针可以被转换到void*，而void*可以被向后转换到任何指针（对于static_cast&lt;&gt; 和 reinterpret_cast&lt;&gt;转换都可以这样做），如果没有小心处理的话错误可能发生。<br /><br /></p><pre style="PADDING-RIGHT: 5pt; PADDING-LEFT: 5pt; PADDING-BOTTOM: 5pt; FONT: 14px 'Courier New', Courier, mono; WIDTH: 100%; COLOR: #003399; PADDING-TOP: 5pt; BACKGROUND-COLOR: #f5f5f0">    CDerived* pD = new CDerived();<br />
        printf("CDerived* pD = %x\n", (int)pD);<p></p><p>    CBaseY* pY = pD; // 成功编译, pY = pD + 4<br />
        printf("CBaseY* pY = %x\n", (int)pY);</p><p>      void* pV1 = pY; //成功编译, pV1 = pY<br />
        printf("void* pV1 = %x\n", (int)pV1);</p><p>         // pD2 = pY, 但是我们预期 pD2 = pY - 4<br />
        CDerived* pD2 = static_cast&lt;CDerived*&gt;(pV1);<br />
        printf("CDerived* pD2 = %x\n", (int)pD2);<br />
        // 系统崩溃<br />
        // pD2-&gt;bar();<br /></p></pre><pre style="PADDING-RIGHT: 5pt; PADDING-LEFT: 5pt; PADDING-BOTTOM: 5pt; FONT: 14px 'Courier New', Courier, mono; WIDTH: 100%; COLOR: #003399; PADDING-TOP: 5pt; BACKGROUND-COLOR: #f5f5f0">        ---------------------- 输出 ---------------------------<br />
        CDerived* pD = 392fb8<br />
        CBaseY* pY = 392fbc<br />
        void* pV1 = 392fbc<br />
        CDerived* pD2 = 392fbc<br /></pre><p>一旦我们已经转换指针为void*，我们就不能轻易将其转换回原类。在上面的例子中，从一个void* 返回CDerived*的唯一方法是将其转换为CBaseY*然后再转换为CDerived*。 <br />但是如果我们不能确定它是CBaseY* 还是 CDerived*，这时我们不得不用dynamic_cast&lt;&gt; 或typeid[2]。<br /><br /><strong>注释：</strong><br />1. dynamic_cast&lt;&gt;，从另一方面来说，可以防止一个泛型CBaseY* 被转换到CDerived*。<br />2. dynamic_cast&lt;&gt;需要类成为多态，即包括“虚”函数，并因此而不能成为void*。<br /></p><p align="left"><br /></p></td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/andxie99/aggbug/8545.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/andxie99/" target="_blank">思勤无邪</a> 2006-06-14 14:54 <a href="http://www.cppblog.com/andxie99/archive/2006/06/14/8545.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>