﻿<?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>BlogJava-与心灵对话-随笔分类-C++ &amp;VC</title><link>http://www.blogjava.net/dongwq/category/23498.html</link><description>过去理解的，现在未必理解。
过去懂得的，重温必有新意。
整理过去，整理现在。成就现在，成就未来。</description><language>zh-cn</language><lastBuildDate>Wed, 21 Apr 2010 00:11:40 GMT</lastBuildDate><pubDate>Wed, 21 Apr 2010 00:11:40 GMT</pubDate><ttl>60</ttl><item><title>C++ placement new 用法举例zz</title><link>http://www.blogjava.net/dongwq/archive/2010/04/20/318874.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Tue, 20 Apr 2010 09:15:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2010/04/20/318874.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/318874.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2010/04/20/318874.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/318874.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/318874.html</trackback:ping><description><![CDATA[<div class="tit">C++ placement new 用法举例zz</div>
<div class="date">2009-12-17 16:16</div>
<table style="table-layout: fixed; width: 100%">
    <tbody>
        <tr>
            <td>
            <div class="cnt" id="blog_text">
            <p><span>在处理内存分配的时候，</span><span>C++</span><span>程序员会用</span><span>new</span><span>操作符（</span><em><span>operator new</span></em><span>）来分配内存，并用</span><span>delete</span><span>操作符（</span><em><span>operator delete</span></em><span>）来释放内存。这是一个</span><span>new</span><span>操作符的例子。</span></p>
            <p><span>class CTest<br />
            {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>/* </span><span>成员函数和成员数据</span><span> */</span><span><br />
            };<br />
            <br />
            </span><span>// . . . </span><span>代码</span><span><br />
            <br />
            // </span><span>分配一个对象</span><span><br />
            CTest * pTest = new Test;<br />
            </span><span>// </span><span>分配一个有十个对象的数组</span><span> (CTest </span><span>要有缺省构造函数（</span><span>default constuctor</span><span>）</span><span>)</span><span><br />
            CTest * p10Tests = new Test[ 10];</span><span> </span></p>
            <p><span>虽然这种写法在大多数时候都工作得很好，但还是有些情况下使用</span><em><span>new</span></em><span>是很烦人的，比如当你想重新分配一个数组或者当你想在预分配的内存上构造一个对象的时候。</span></p>
            <p><span>比如第一种情况，重新分配一个数组效率是很低的：</span></p>
            <p><span>// </span><span>分配一个有</span><span>10</span><span>个对象的数组</span><span><br />
            CTest * pTests = new Test[ 10];<br />
            </span><span>// . . .<br />
            // </span><span>假设现在我们需要</span><span>11</span><span>个对象</span><span><br />
            CTest * pNewTests = new Test[ 11];<br />
            </span><span>// . . . </span><span>我们必须把原来的对象拷贝到新分配的内存中</span><span><br />
            for ( int i = 0; i &lt; 10; i++)<br />
            &nbsp;&nbsp;&nbsp;&nbsp; pNewTests[ i] = pTests[ i];<br />
            delete pTests;<br />
            pTests = pNewTests; </span></p>
            <p><span>如果你想在预分配的内存上创建对象，用缺省的</span><span>new</span><span>操作符是行不通的。要解决这个问题，你可以用</span><em><span>placement new</span></em><span>构造。它允许你构造一个新对象到预分配的内存上：</span></p>
            <p><span>// buffer </span><span>是一个</span><span>void</span><span>指针</span><span> (void *)<br />
            // </span><span>用方括号</span><span>[] </span><span>括起来的部分是可选的</span><span><br />
            [CYourClass * pValue = ] new( buffer) CYourClass[( parameters)];</span><span> </span></p>
            <p><span>下面是一些例子：</span></p>
            <p><span>#include &lt;new&gt;<br />
            <br />
            class CTest<br />
            {<br />
            public:<br />
            &nbsp;&nbsp;&nbsp;&nbsp; CTest()<br />
            &nbsp;&nbsp;&nbsp;&nbsp; {}<br />
            &nbsp;&nbsp;&nbsp;&nbsp; CTest( int)<br />
            &nbsp;&nbsp;&nbsp;&nbsp; {}<br />
            &nbsp;&nbsp;&nbsp;&nbsp;</span><span>/* </span><span>代码</span><span>*/</span><span><br />
            };<br />
            <br />
            int main(int argc, char* argv[])<br />
            {</span><span><br />
            &nbsp;&nbsp;&nbsp;&nbsp; // </span><span>由于这个例子的目的，我们不考虑内存对齐问题</span><span><br />
            &nbsp;&nbsp;&nbsp;&nbsp; char strBuff[ sizeof( CTest) * 10 + 100];<br />
            &nbsp;&nbsp;&nbsp;&nbsp; CTest * pBuffer = ( CTest *)strBuff;<br />
            <br />
            &nbsp;&nbsp;&nbsp;&nbsp;</span><span>// </span><span>缺省构造</span><span><br />
            &nbsp;&nbsp;&nbsp;&nbsp; CTest * pFirst = new(pBuffer) CTest;<br />
            <br />
            &nbsp;&nbsp;&nbsp;&nbsp;</span><span>// </span><span>缺省构造</span><span><br />
            &nbsp;&nbsp;&nbsp;&nbsp; CTest * pSecond = new(pBuffer + 1) CTest;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;</span><span>// </span><span>带参数的构造；</span><span><br />
            &nbsp;&nbsp;&nbsp;&nbsp; // </span><span>不理会返回的指针</span><span><br />
            &nbsp;&nbsp;&nbsp;&nbsp; new(pBuffer + 2) CTest( 5);<br />
            <br />
            &nbsp;&nbsp;&nbsp;&nbsp;</span><span>// </span><span>带参数的构造</span><span><br />
            &nbsp;&nbsp;&nbsp;&nbsp; CTest * pFourth = new( pBuffer + 3) CTest( 10);<br />
            <br />
            &nbsp;&nbsp;&nbsp;&nbsp;</span><span>// </span><span>缺省构造</span><span><br />
            &nbsp;&nbsp;&nbsp;&nbsp; CTest * pFifth = new(pBuffer + 4) CTest();<br />
            <br />
            &nbsp;&nbsp;&nbsp;&nbsp;</span><span>// </span><span>构造多个元素（缺省构造）</span><span><br />
            &nbsp;&nbsp;&nbsp;&nbsp; CTest * pMultipleElements = new(pBuffer + 5) CTest[ 5];<br />
            &nbsp;&nbsp;&nbsp;&nbsp; return 0;<br />
            } </span></p>
            <p><span>当你有自己的内存缓冲区或者在你实现自己的内存分配策略的时候，</span><em><span>placement new</span></em><span>会很有用。事实上在</span><span>STL</span><span>中广泛使用了</span><em><span>placement new</span></em><span>来给容器分配内存；每个容器类都有一个模版参数说明了构造</span><span>/</span><span>析构对象时所用的分配器（</span><span>allocator</span><span>）。</span></p>
            <p><span>在使用</span><em><span>placement new</span></em><span>的时候，你要记住以下几点：</span></p>
            <ul type="disc">
                <li><span>加上头文件</span><span>#include &lt;new&gt; </span>
                <li><span>你可以用</span><span>placement new</span><span>构造一个数组中的元素。</span><span> </span>
                <li><span>要析构一个用</span><span>placement new</span><span>分配的对象，你应该手工调用析构函数（并不存在一个</span><span>&#8220;placement delete&#8221;</span><span>）。它的语法如下：</span><span> </span></li>
            </ul>
            <p><span>pFirst-&gt;~CTest();<br />
            pSecond-&gt;~CTest();</span></p>
            前段事件，我问过关于placement&nbsp;new的问题，一位仁兄讲了一些道理，他说道：<br />
            <br />
            ：：栈上的对象(注意,是类对象,char类型就无需了,后面还会提到)保证放在对齐地址上.&nbsp;<br />
            <br />
            但是，个人实验了一下，发现并不是这样<br />
            <br />
            例如：<br />
            int&nbsp;main()<br />
            {<br />
            char&nbsp;c1&nbsp;=&nbsp;'A'&nbsp;;<br />
            char&nbsp;c2&nbsp;=&nbsp;'B'&nbsp;;<br />
            char&nbsp;c3&nbsp;=&nbsp;'C'&nbsp;;<br />
            char&nbsp;c4&nbsp;=&nbsp;'D'&nbsp;;<br />
            char&nbsp;c5&nbsp;=&nbsp;'E'&nbsp;;<br />
            <br />
            //--------&nbsp;验证这四个地址是否是&nbsp;4&nbsp;的倍数&nbsp;--------------//<br />
            if&nbsp;(&nbsp;((int)(&amp;c1))&nbsp;%&nbsp;4&nbsp;==&nbsp;0&nbsp;)<br />
            cout&nbsp;&lt;&lt;&nbsp;"c1:Yes"&nbsp;&lt;&lt;&nbsp;endl&nbsp;;<br />
            <br />
            if&nbsp;(&nbsp;((int)(&amp;c2))&nbsp;%&nbsp;4&nbsp;==&nbsp;0&nbsp;)<br />
            cout&nbsp;&lt;&lt;&nbsp;"c2:Yes"&nbsp;&lt;&lt;&nbsp;endl&nbsp;;<br />
            <br />
            if&nbsp;(&nbsp;((int)(&amp;c3))&nbsp;%&nbsp;4&nbsp;==&nbsp;0&nbsp;)<br />
            cout&nbsp;&lt;&lt;&nbsp;"c3:Yes"&nbsp;&lt;&lt;&nbsp;endl&nbsp;;<br />
            <br />
            if&nbsp;(&nbsp;((int)(&amp;c4))&nbsp;%&nbsp;4&nbsp;==&nbsp;0&nbsp;)<br />
            cout&nbsp;&lt;&lt;&nbsp;"c4:Yes"&nbsp;&lt;&lt;&nbsp;endl&nbsp;;<br />
            <br />
            if&nbsp;(&nbsp;((int)(&amp;c5))&nbsp;%&nbsp;4&nbsp;==&nbsp;0&nbsp;)<br />
            cout&nbsp;&lt;&lt;&nbsp;"c5:Yes"&nbsp;&lt;&lt;&nbsp;endl&nbsp;;<br />
            <br />
            cout&nbsp;&lt;&lt;&nbsp;(int)(&amp;c1)&nbsp;&lt;&lt;&nbsp;endl&nbsp;//&nbsp;输出四个字符所在的地址（输出结果都是&nbsp;4&nbsp;的倍数）<br />
            &nbsp;&lt;&lt;&nbsp;(int)(&amp;c2)&nbsp;&lt;&lt;&nbsp;endl&nbsp;<br />
            &nbsp;&lt;&lt;&nbsp;(int)(&amp;c3)&nbsp;&lt;&lt;&nbsp;endl&nbsp;<br />
            &nbsp;&lt;&lt;&nbsp;(int)(&amp;c4)&nbsp;&lt;&lt;&nbsp;endl&nbsp;<br />
            &nbsp;&lt;&lt;&nbsp;(int)(&amp;c5)&nbsp;&lt;&lt;&nbsp;endl&nbsp;;<br />
            }<br />
            -----------------------------<br />
            上面的执行结果在VC下运行都是&nbsp;4&nbsp;的倍数<br />
            －－－－－－－－－－－－－－<br />
            <br />
            --&gt;&nbsp;问题1：连栈上分配的空间地址都是&nbsp;4&nbsp;的倍数，那就说明系统分配的空间都是&nbsp;4&nbsp;的倍数吧？？？<br />
            <br />
            --&gt;&nbsp;问题2：如果万一，如果放一个对象的地址不是4的倍数，那么会出现什么情况？？可以给简单说一下吗？<br />
            <br />
            --&gt;&nbsp;问题3：地址对齐的通用性？？？<br />
            &nbsp;&nbsp;&nbsp;－－－－－－－－－－－－－<br />
            &nbsp;&nbsp;&nbsp;程序1：<br />
            Class&nbsp;C1<br />
            {<br />
            int&nbsp;i&nbsp;;<br />
            char&nbsp;c&nbsp;;<br />
            }&nbsp;;<br />
            cout&nbsp;&lt;&lt;&nbsp;sizeof(C1)&nbsp;&lt;&lt;&nbsp;endl&nbsp;;//&nbsp;输出结果：&nbsp;8&nbsp;（是&nbsp;4&nbsp;的倍数）<br />
            &nbsp;&nbsp;&nbsp;程序2：<br />
            class&nbsp;C2<br />
            {<br />
            char&nbsp;c1&nbsp;;<br />
            char&nbsp;c2&nbsp;;<br />
            }&nbsp;;<br />
            cout&nbsp;&lt;&lt;&nbsp;sizeof(C2)&nbsp;&lt;&lt;&nbsp;endl&nbsp;;//&nbsp;输出结果：2&nbsp;（&nbsp;上一个中char类型也给了4个字节，怎么这个地方都给了一个字节？？）<br />
            --&gt;&nbsp;问题4：由上面的程序2&nbsp;引出下面的程序<br />
            class&nbsp;C2//&nbsp;sizeof(C2)&nbsp;=2&nbsp;,在VC实验下的结果，不是&nbsp;4<br />
            {<br />
            char&nbsp;c1&nbsp;;<br />
            char&nbsp;c2&nbsp;;<br />
            }&nbsp;;<br />
            //----------用placement&nbsp;new方法建立对象----------------<br />
            void&nbsp;*ptr&nbsp;=&nbsp;operator&nbsp;new(100)&nbsp;;//&nbsp;分配内存<br />
            C2&nbsp;*POINTER&nbsp;=&nbsp;(C2*)ptr&nbsp;;//&nbsp;类型转换<br />
            String&nbsp;*str1&nbsp;=&nbsp;new&nbsp;(POINTER)&nbsp;C2()&nbsp;;//&nbsp;建立一C2对象<br />
            String&nbsp;*str2&nbsp;=&nbsp;new&nbsp;(POINTER+1)&nbsp;C2()&nbsp;;//&nbsp;再建立一个对象<br />
            String&nbsp;*str3&nbsp;=&nbsp;new&nbsp;(POINTER+2)&nbsp;C2()&nbsp;;//&nbsp;再建立一个对象<br />
            <br />
            cout&nbsp;&lt;&lt;&nbsp;(int)(str1)&nbsp;&lt;&lt;&nbsp;endl//&nbsp;结果：3608720（&nbsp;&nbsp;是4的倍数）<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;(int)(str2)&nbsp;&lt;&lt;&nbsp;endl&nbsp;//&nbsp;结果：3608722（不是4的倍数）！！<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;(int)(str3)&nbsp;&lt;&lt;&nbsp;endl&nbsp;;//&nbsp;结果：3608724（不是4的倍数）！！<br />
            </div>
            </td>
        </tr>
    </tbody>
</table><img src ="http://www.blogjava.net/dongwq/aggbug/318874.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2010-04-20 17:15 <a href="http://www.blogjava.net/dongwq/archive/2010/04/20/318874.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符串拆分的中文处理问题zz</title><link>http://www.blogjava.net/dongwq/archive/2010/04/19/318703.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Sun, 18 Apr 2010 17:47:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2010/04/19/318703.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/318703.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2010/04/19/318703.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/318703.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/318703.html</trackback:ping><description><![CDATA[<div id="blog_body">
<p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><strong><span style="font-size: 18pt; font-family: 宋体">字符串拆分的中文处理问题</span></strong></p>
<p style="margin: 0cm 0cm 0pt; text-align: right" align="right"><span style="font-family: 宋体">容健行＠</span><font face="Times New Roman">2007</font><span style="font-family: 宋体">年</span><font face="Times New Roman">7</font><span style="font-family: 宋体">月</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: right" align="right"><span style="font-family: 宋体">转载请注明出处</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: right" align="right"><span style="font-family: 宋体">原文出处：<a href="http://www.devdiv.net/home/space.php?uid=125&amp;do=blog&amp;id=365" target="_blank">http://www.devdiv.net/home/space.php?uid=125&amp;do=blog&amp;id=365</a></span></p>
<h3 style="margin: 13pt 0cm"><span style="font-family: 宋体"><font size="5">概述：</font></span></h3>
<p style="margin: 0cm 0cm 0pt; text-indent: 27pt"><span style="font-family: 宋体">拆分一个字符串在程序中使用非常广泛，特别是我们经常跟表格打交道的程序员们。所谓拆分字符串，就是将一个字符串中间以某个（或某些）字符为分隔，拆分成多个字符串。如</span><font face="Times New Roman"> std::string s = "abc&nbsp;| ddd | </font><span style="font-family: 宋体">中国</span><font face="Times New Roman">";&nbsp;&nbsp;&nbsp; </font><span style="font-family: 宋体">如果以竖线&#8220;</span><font face="Times New Roman">|</font><span style="font-family: 宋体">&#8221;拆分，可以将这个字符串拆分成三个字符串。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 27pt"><span style="font-family: 宋体">当然字符串拆分还包括通过正则表达式来拆分，为了简化问题，我们以单个字符做分隔的拆分，因为这种拆分用得最多。代码使用</span><font face="Times New Roman">C++</font><span style="font-family: 宋体">来讲解。</span></p>
<h3 style="margin: 13pt 0cm"><span style="font-family: 宋体"><font size="5">问题：</font></span></h3>
<p style="margin: 0cm 0cm 0pt; text-indent: 27pt"><span style="font-family: 宋体">问题来源于实际，是之前我们组和其他组都有遇上的。先看一个例子，使用</span><font face="Times New Roman">"|"</font><span style="font-family: 宋体">拆分以下字符串，看起来怎么数都是分为</span><font face="Times New Roman">48</font><span style="font-family: 宋体">列，但我看到好几个版本的字符串拆分函数却报有</span><font face="Times New Roman">49列：</font></p>
<p style="margin: 0cm 0cm 0pt"><font face="Times New Roman">"AGZGY1000004|200|</font><span style="font-family: 宋体">刘瓅</span><font face="Times New Roman">||20100101||OPRT10|1|0||AAGZ0Y100|0|0|24|0|0|0|0||-1|20030101|0|20991231||AGZGK6172888|200|</font><span style="font-family: 宋体">曾晓翔</span><font face="Times New Roman">||20100101||OPRT10|1|0||AAGZ0K617|0|0|24|0|0|0|0||-1|20061215|1|20061215||"</font></p>
<h3 style="margin: 13pt 0cm"><span style="font-family: 宋体"><font size="5">原因分析：</font></span></h3>
<p style="margin: 0cm 0cm 0pt; text-indent: 27pt"><span style="font-family: 宋体">让我们先把以上字符串放到</span><font face="Times New Roman">UltraEdit</font><span style="font-family: 宋体">中，并切换到</span><font face="Times New Roman">16</font><span style="font-family: 宋体">进制的编辑模式，看看它的编码。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 27pt"><span style="font-family: 宋体">原因是原来的字符串拆分函数只是简单的查找&#8220;｜&#8221;（编码为</span><font face="Times New Roman">0x7c</font><span style="font-family: 宋体">）</span><font face="Times New Roman">,</font><span style="font-family: 宋体">而没有考虑到中文的处理（源代码太多，且有好几个版本，这里略去）。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 27pt"><span style="font-family: 宋体">在</span><font face="Times New Roman">boss</font><span style="font-family: 宋体">中，</span><font face="Times New Roman">c++</font><span style="font-family: 宋体">程序使用的编码方式几乎全为</span><font face="Times New Roman">ansi</font><span style="font-family: 宋体">，而在</span><font face="Times New Roman">ansi</font><span style="font-family: 宋体">中，表示中文是用两个字符，且第一个字符是一个大于</span><font face="Times New Roman">0x80</font><span style="font-family: 宋体">的字符（字符的第一位为</span><font face="Times New Roman">1</font><span style="font-family: 宋体">），第二个字符为任意字符。这里引起一个问题：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 27pt"><span style="font-family: 宋体">当我们要分割字符串时，假如用</span><font face="Times New Roman">"|"(0x7c)</font><span style="font-family: 宋体">作为分割符，当分析上面这个字符遇到</span><font face="Times New Roman">"</font><span style="font-family: 宋体">瓅</span><font face="Times New Roman">"(</font><span style="font-family: 宋体">编码为</span><font face="Times New Roman">0xad,0x7c)</font><span style="font-family: 宋体">这个字符时，会把它第二个字符作为了分割符，结果就多出了一列。</span></p>
<h3 style="margin: 13pt 0cm"><span style="font-family: 宋体"><font size="5">解决方案：</font></span></h3>
<p style="margin: 0cm 0cm 0pt; text-indent: 27pt"><span style="font-family: 宋体">问题原因找到了，重新写了一下字符串拆分函数－</span><font face="Times New Roman">Split</font><span style="font-family: 宋体">，这里使用的方法是：找到分隔符后，再向前查找字符看一下它前一个字符是否为东亚文字的第一个字符编码（编码大于</span><font face="Times New Roman">0x80</font><span style="font-family: 宋体">）。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 27pt"><span style="font-family: 宋体">考虑到以后支持</span><font face="Times New Roman">unicode</font><span style="font-family: 宋体">，这里使用了模板。以下可能不是最高效简单的实现，但如果以后遇上这种问题，可以参考一下。</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">#include</span><span style="font-size: 11pt; font-family: 宋体"> <span style="color: red">"stdafx.h"</span></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">#include</span><span style="font-size: 11pt; font-family: 宋体"> <span style="color: red">&lt;stdio.h&gt;</span></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">#include</span><span style="font-size: 11pt; font-family: 宋体"> <span style="color: red">&lt;tchar.h&gt;</span></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">#include</span><span style="font-size: 11pt; font-family: 宋体"> <span style="color: red">&lt;iostream&gt;</span></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">#include</span><span style="font-size: 11pt; font-family: 宋体"> <span style="color: red">&lt;string&gt;</span></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">#include</span><span style="font-size: 11pt; font-family: 宋体"> <span style="color: red">&lt;vector&gt;</span></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">#include</span><span style="font-size: 11pt; font-family: 宋体"> <span style="color: red">&lt;algorithm&gt;</span></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">#include</span><span style="font-size: 11pt; font-family: 宋体"> <span style="color: red">&lt;fstream&gt;</span></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: green; font-family: 宋体">// unicode </span><span style="font-size: 11pt; color: green; font-family: 宋体">分割策略</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">inline</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">bool</span> __SplitPolicy(</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> std::wstring&amp; s, </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> std::wstring&amp; splitchar, </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; std::wstring::size_type&amp; pos)</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">{</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; pos = s.find_first_of(splitchar, pos);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">return</span> pos != std::string::npos;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">}</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: green; font-family: 宋体">// ansi </span><span style="font-size: 11pt; color: green; font-family: 宋体">分割策略</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">inline</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">bool</span> __SplitPolicy(</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> std::string&amp; s, </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> std::string&amp; splitchar, </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; std::string::size_type&amp; pos)</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">{</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; pos = s.find_first_of(splitchar, pos);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">if</span> (pos != std::string::npos) </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green">// </span></span><span style="font-size: 11pt; color: green; font-family: 宋体">如果前一个字符的第一位为1，且当前字符是在东亚文字的第二个字符，</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green">// </span></span><span style="font-size: 11pt; color: green; font-family: 宋体">则认为该字符是东亚字的其中一个字符，要跳过，不作为分割符。</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::string::size_type i = <span style="color: olive">1</span>;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">for</span> (; i &lt; pos; ++i)</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">if</span> (!((<span style="color: blue">char</span>)(s[pos - i]) &amp; <span style="color: olive">0x80</span>)) <span style="color: green">// </span></span><span style="font-size: 11pt; color: green; font-family: 宋体">判断第一位是否为1。（0x80的二进制为 10000000）</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">break</span>;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">if</span> (!(i % <span style="color: olive">2</span>)) <span style="color: green">// </span></span><span style="font-size: 11pt; color: green; font-family: 宋体">看一下当前字符是否为东亚文字的第二个字符</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++pos;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __SplitPolicy(s, splitchar, pos);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">return</span> pos != std::string::npos;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">}</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">template</span><span style="font-size: 11pt; font-family: 宋体">&lt;<span style="color: blue">typename</span> char_type&gt; <span style="color: blue">inline</span> </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">int</span> Split(</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> std::basic_string&lt;char_type&gt;&amp; s, </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> std::basic_string&lt;char_type&gt;&amp; splitchar, </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; std::vector&lt;std::basic_string&lt;char_type&gt; &gt;&amp; vec)</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">{</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">typedef</span> std::basic_string&lt;char_type&gt;&nbsp;&nbsp; string_t;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">typedef</span> <span style="color: blue">typename</span> string_t::size_type&nbsp;&nbsp; size_t;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; string_t tmpstr;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; size_t pos = <span style="color: olive">0</span>, prev_pos = <span style="color: olive">0</span>;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; vec.clear();</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">while</span> (__SplitPolicy(s, splitchar, pos))</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmpstr = s.substr(prev_pos, pos - prev_pos);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vec.push_back(tmpstr);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; prev_pos = ++pos;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; size_t len = s.length() - prev_pos;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">if</span> (len &gt; <span style="color: olive">0</span>)</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vec.push_back(s.substr(prev_pos, len));</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">return</span> <span style="color: blue">static_cast</span>&lt;<span style="color: blue">int</span>&gt;(vec.size());</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">}</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: green; font-family: 宋体">// ansi</span><span style="font-size: 11pt; color: green; font-family: 宋体">版本测试</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">void</span><span style="font-size: 11pt; font-family: 宋体"> testSplit()</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">{</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; std::vector&lt;std::string&gt; vec;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> std::string str = <span style="color: red">"AGZGY1000004|200|</span></span><span style="font-size: 11pt; color: red; font-family: 宋体">刘瓅瓅||20100101||OPRT10|1|0||AAGZ0Y100|0|0|24|0|0|0|0||-1|20030101|0|20991231||AGZGK6172888|200|曾晓翔||20100101||OPRT10|1|0||AAGZ0K617|0|0|24|0|0|0|0||-1|20061215|1|20061215||a"</span><span style="font-size: 11pt; font-family: 宋体">;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> std::string sp = <span style="color: red">"|"</span>;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">int</span> count = Split(str, sp, vec);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">for</span> (std::vector&lt;std::string&gt;::const_iterator it = vec.begin(); it != vec.end(); ++it)</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; *it &lt;&lt; <span style="color: red">" "</span>;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">}</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: green; font-family: 宋体">// unicode</span><span style="font-size: 11pt; color: green; font-family: 宋体">版本测试</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">void</span><span style="font-size: 11pt; font-family: 宋体"> testSplitW()</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">{</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; std::vector&lt;std::wstring&gt; vec;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> std::wstring str = L<span style="color: red">"AGZGY1000004|200|</span></span><span style="font-size: 11pt; color: red; font-family: 宋体">刘瓅||20100101||OPRT10|1|0||AAGZ0Y100|0|0|24|0|0|0|0||-1|20030101|0|20991231||AGZGK6172888|200|曾晓翔||20100101||OPRT10|1|0||AAGZ0K617|0|0|24|0|0|0|0||-1|20061215|1|20061215||"</span><span style="font-size: 11pt; font-family: 宋体">;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> std::wstring sp = L<span style="color: red">"|"</span>;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; Split(str, sp, vec);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> <span style="color: blue">char</span> head[<span style="color: olive">3</span>] = {<span style="color: olive">0xff</span>, <span style="color: olive">0xfe</span>, <span style="color: olive">0</span>};</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">const</span> <span style="color: blue">wchar_t</span> line[<span style="color: olive">3</span>] = L<span style="color: red">" "</span>;</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: green">// </span></span><span style="font-size: 11pt; color: green; font-family: 宋体">控制台输出不了unicode字符，使用输出到文件的方式</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; std::ofstream fileOut(<span style="color: red">"C:/out.txt"</span>);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; fileOut.write(head, <span style="color: olive">2</span>);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="color: blue">for</span> (std::vector&lt;std::wstring&gt;::iterator it = vec.begin(); it != vec.end(); ++it)</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fileOut.write((<span style="color: blue">const</span> <span style="color: blue">char</span>*)it-&gt;c_str(), it-&gt;length() * <span style="color: olive">2</span>);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fileOut.write((<span style="color: blue">const</span> <span style="color: blue">char</span>*)line, <span style="color: olive">2</span>);</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">}</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; color: blue; font-family: 宋体">int</span><span style="font-size: 11pt; font-family: 宋体"> main()</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">{</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; testSplit();</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">&nbsp;&nbsp;&nbsp; testSplitW();</span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">}</span></p>
<h3 style="margin: 13pt 0cm"><font size="5"><span style="font-family: 宋体">参考：</span></font></h3>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: 11pt; font-family: 宋体">1</span><span style="font-size: 11pt; font-family: 宋体">．<a href="http://unicode.org/" target="_blank"><font color="#000000">http://unicode.org/</font></a></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><font face="Times New Roman">2</font><span style="font-family: 宋体">．</span><span style="font-size: 11pt; font-family: 宋体">《谈谈Unicode编码，简要解释UCS、UTF、BMP、BOM等名词》</span></p>
</div><img src ="http://www.blogjava.net/dongwq/aggbug/318703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2010-04-19 01:47 <a href="http://www.blogjava.net/dongwq/archive/2010/04/19/318703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于C++中文字符的处理</title><link>http://www.blogjava.net/dongwq/archive/2010/04/18/318627.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Sat, 17 Apr 2010 17:10:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2010/04/18/318627.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/318627.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2010/04/18/318627.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/318627.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/318627.html</trackback:ping><description><![CDATA[<h3><a href="http://hcmfys.javaeye.com/blog/588784">关于C++中文字符的处理</a></h3>
<div class="blog_content">
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt; color: red">一 引入问题</span></div>
<div style="text-indent: 21pt; line-height: 20pt" align="left"><span style="font-size: 9pt">代码 wchar_t a[3]=L&#8221;中国&#8221;，编译时出错，出错信息为：数组越界。但wchar_t 是一个宽字节类型，数组a的大小应为6个字节，而两个汉字的的unicode码占4个字节，再加上一个结束符，最多6个字节，所以应该不会越界。难道是编译器出问题了？</span></div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt; color: red">二 解决引入问题所需的知识</span></div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt; color: red">&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9pt">主要需两方面的知识，第一个为字符尤其是汉字的编码，以及语言和工具的支持情况，第二个是vc/c++中MutiByte Charater Set 和 Wide Character Set有关内存分配的情况.</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt; color: red">三 汉字的编码方式及在vc/c++中的处理</span></div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt; color: blue">1.</span><span style="font-size: 9pt; color: blue">汉字编码方式的介绍</span> </div>
<div style="text-indent: 18pt; line-height: 20pt" align="left"><span style="font-size: 9pt">对英文字符的处理，7位ASCII码字符集中的字符即可满足使用需求，且英文字符在计算机上的输入及输出也非常简单，因此，英文字符的输入、存储、内部处理和输出都可以只用同一个编码（如ASCII码）。</span></div>
<div style="text-indent: 18pt; line-height: 20pt" align="left"><span style="font-size: 9pt">而汉字是一种象形文字，字数极多（现代汉字中仅常用字就有六、七千个，总字数高达5万个以上），且字形复杂，每一个汉字都有"音、形、义"三要素，同音字、异体字也很多，这些都给汉字的的计算机处理带来了很大的困难。要在计算机中处理汉字，必须解决以下几个问题：首先是汉字的输入，即如何把结构复杂的方块汉字输入到计算机中去，这是汉字处理的关键；其次，汉字在计算机内如何表示和存储？如何与西文兼容？最后，如何将汉字的处理结果从计算机内输出？ </span></div>
<div style="text-indent: 15.75pt; line-height: 20pt" align="left"><span style="font-size: 9pt">为此，必须将汉字代码化，即对汉字进行编码。对应于上述汉字处理过程中的输入、内部处理及输出这三个主要环节，每一个汉字的编码都包括输入码、交换码、内部码和字形码。在计算机的汉字信息处理系统中，处理汉字时要进行如下的代码转换：输入码&#8594;交换码&#8594;内部码&#8594;字形码。</span></div>
<div align="left"><span style="font-size: 9pt">(1)</span><span style="font-size: 9pt">输入码： 作用是，利用它和现有的标准西文键盘结合来输入汉字。输入码也称为外码。主要归为四类：</span> </div>
<div align="left"><span style="font-size: 9pt">a)</span><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9pt">数字编码：数字编码是用等长的数字串为汉字逐一编号，以这个编号作为汉字的输入码。例如，区位码、电报码等都属于数字编码。</span> </div>
<div align="left"><span style="font-size: 9pt">b)</span><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9pt">拼音码：拼音码是以汉字的读音为基础的输入办法。</span> </div>
<div align="left"><span style="font-size: 9pt">c)</span><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9pt">字形码：字形码是以汉字的字形结构为基础的输入编码。例如，五笔字型码（王码）。</span> </div>
<div align="left"><span style="font-size: 9pt">d)</span><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9pt">音形码：音形码是兼顾汉字的读音和字形的输入编码。</span> </div>
<div align="left"><span style="font-size: 9pt">(2)</span><span style="font-size: 9pt">交换码：用于汉字外码和内部码的交换。交换码的国家标准代号为GB2312-80。</span> </div>
<div align="left"><span style="font-size: 9pt">(3)</span><span style="font-size: 9pt">内部码：内部码是汉字在计算机内的基本表示形式，是计算机对汉字进行识别、存储、处理和传输所用的编码。内部码也是双字节编码，将国标码两个字节的最高位都置为"1"，即转换成汉字的内部码。</span> </div>
<div align="left"><span style="font-size: 9pt">(4)</span><span style="font-size: 9pt">字形码：字形码是表示汉字字形信息（汉字的结构、形状、笔划等）的编码，用来实现计算机对汉字的输出（显示、打印）。</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt; color: blue">2.VC</span><span style="font-size: 9pt; color: blue">中汉字的编码方式</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; vc/c++</span><span style="font-size: 9pt">正是采用了GB2312内部码作为汉字的编码方式,因此vc/c++中的各种输入输出方法，如cin/wcin,cout/wcout,scanf/wsanf,printf/wprintf...都是基于GB2312的，如果汉字的内码不是这种编码方式，那么利用上述各种方法就不会正确的解析汉字。</span> </div>
<div style="text-indent: 24pt; line-height: 20pt" align="left"><span style="font-size: 9pt">仔细观察ASCII字符表，从第161个字符开始，后面的字符并不经常为用户所使用，负值也未使用。GB2312编码方式充分利用这一特性，将161-255（-95~-1）之间的数值空间作为汉字的标识码。既然255-161 = 94不能满足汉字容量的要求，就将每两个字符并在一块(即一个汉字占两个字节)，显然，94* 94 =8836基本上已经满足了常用汉字个数的要求。计算机处理字符时，当连续处理到两个大与160(或-95~-1)的字节时，就认为这两个字节存放了一个汉字字符。可以用下面的Demo程序来模拟vc/c++中输出汉字字符的过程。</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">unsigned</span> <span style="color: blue">char</span> input[50];</span></div>
<div style="text-indent: 18pt" align="left"><span style="font-size: 9pt">cin&gt;&gt;input;</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">int</span> flag=0;</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">for</span>(<span style="color: blue">int</span> i =0 ;i &lt; 50 ;i++)</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">if</span>(input[i] &gt; 0xa0 &amp;&amp; input[i] != 0)</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">if</span>(flag == 1)</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;"chinese character"&lt;&lt;endl;</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flag = 0;</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">else</span></span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flag++;</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div align="left"></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">else</span> <span style="color: blue">if</span>(input[i] == 0)</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">break</span>;</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">else</span> </span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;"english character"&lt;&lt;endl;</span></div>
<div align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="text-indent: 24pt; line-height: 20pt" align="left"><span style="font-size: 9pt">}</span></div>
<div style="text-indent: 24pt; line-height: 20pt" align="left"><span style="font-size: 9pt">输入：</span><span style="font-size: 9pt">Hello</span><span style="font-size: 9pt">中国 （&#8220;中国&#8221;对应的GB2312内码为：214 208，185 250）</span> </div>
<div style="text-indent: 24pt; line-height: 20pt" align="left"><span style="font-size: 9pt">输出：english character</span></div>
<div style="text-indent: 45pt; line-height: 20pt" align="left"><span style="font-size: 9pt">english character</span></div>
<div style="text-indent: 45pt; line-height: 20pt" align="left"><span style="font-size: 9pt">english character</span></div>
<div style="text-indent: 45pt; line-height: 20pt" align="left"><span style="font-size: 9pt">english character</span></div>
<div style="text-indent: 45pt; line-height: 20pt" align="left"><span style="font-size: 9pt">english character</span></div>
<div style="text-indent: 45pt; line-height: 20pt" align="left"><span style="font-size: 9pt">chinese character</span></div>
<div style="text-indent: 45pt; line-height: 20pt" align="left"><span style="font-size: 9pt">chinese character</span></div>
<div align="left"></div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt">vc/c++</span><span style="font-size: 9pt">中的英文字符仍然采用ASCII编码方式。可以设想，其他国家程序员利用vc/c++编写程序输入本国字符时，vc/c++则会采用该国的字符编码方式来处理这些字符。</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9pt">问题又产生了，韩国的vc/c++程序在中国的vc/c++上运行时，如果没有相应的内码库，则对韩语字符的显示有可能出现乱码。我个人猜测，vc安装程序中应该带有不同国家的内码库，这样一来肯定会占用很大的空间。如果所有的国家使用统一的编码方式，且所有的程序设计语言和开发工具都支持这种编码方式该多好！而现实中，确实已经有这种编码方式了，且许多新的语言也都支持这种编码方式，如Java、C#等，它就是下面的Unicode编码</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt; color: blue">3.</span><span style="font-size: 9pt; color: blue">新的内码标准---Unicode</span> </div>
<div style="text-indent: 18pt; line-height: 20pt" align="left"><span style="font-size: 9pt">Unicode</span><span style="font-size: 9pt">（统一码、万国码、单一码）是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码，以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发，1994年正式公布。随着计算机工作能力的增强，Unicode也在面世以来的十多年里得到普及。最新版本的 Unicode 是 2005<span>年3</span><span>月31</span><span>日</span>推出的Unicode 4.1.0 。另外，5.0 Beta已于2005年12月12日推出，以供各会员评价。</span> </div>
<div style="text-indent: 18pt; line-height: 20pt" align="left"><span style="font-size: 9pt">Unicode </span><span style="font-size: 9pt">编码系统可分为编码方式和实现方式两个层次。</span> </div>
<div style="text-indent: 18pt; line-height: 20pt" align="left"><span style="font-size: 9pt">编码方式：Unicode 的编码方式与 ISO 10646 的通用字符集（Universal Character Set，UCS）概念相对应，目前的用于实用的 Unicode 版本对应于 UCS-2，使用16位的编码空间。也就是每个字符占用2个字节。这样理论上一共最多可以表示 216 个字符。基本满足各种语言的使用。实际上目前版本的 Unicode 尚未填充满这16位编码，保留了大量空间作为特殊使用或将来扩展。</span></div>
<div style="text-indent: 18pt; line-height: 20pt" align="left"><span style="font-size: 9pt">实现方式：Unicode 的实现方式不同于编码方式。一个字符的 Unicode 编码是确定的。但是在实际传输过程中，由于不同系统平台的设计不一定一致，以及出于节省空间的目的，对 Unicode 编码的实现方式有所不同。Unicode 的实现方式称为Unicode转换格式（Unicode Translation Format，简称为 UTF）。如，UTF-8 编码，这是一种变长编码，它将基本7位ASCII字符仍用7位编码表示，占用一个字节（首位补0）。而遇到与其他 Unicode 字符混合的情况，将按一定算法转换，每个字符使用1-3个字节编码，并利用首位为0或1进行识别。</span></div>
<div style="text-indent: 15.75pt; line-height: 20pt" align="left"><span style="font-size: 9pt">Java</span><span style="font-size: 9pt">与C#语言都是采用Unicode编码方式，在这两种语言中定义一个字符，在内存中存放的就是这个字符的两字节Unicode码。如下所示：</span> </div>
<div style="text-indent: 15.75pt; line-height: 20pt" align="left"><span style="font-size: 9pt; color: blue">char</span><span style="font-size: 9pt"> a='</span><span style="font-size: 9pt">我';<span>&nbsp;&nbsp;&nbsp;&nbsp; =&gt; </span>内存中存放的Unicode码为：25105</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt; color: blue">4.</span><span style="font-size: 9pt; color: blue">内码的相互转换</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt">(1)vc</span><span style="font-size: 9pt">中的实现方法</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9pt">利用Windows系统提供的API：</span><strong><span style="font-size: 9pt">::MultiByteToWideChar</span></strong><strong><span style="font-size: 9pt">和</span></strong><strong><span style="font-size: 9pt">::WideCharToMultiByte</span></strong> </div>
<div style="text-indent: 17.7pt; line-height: 20pt" align="left"><strong><span style="font-size: 9pt">::MultiByteToWideChar</span></strong><strong><span style="font-size: 9pt">：</span></strong><span style="font-size: 9pt">实现当前码到</span><span style="font-size: 9pt">Unicode</span><span style="font-size: 9pt">码的转换；</span> </div>
<div style="text-indent: 17.7pt; line-height: 20pt" align="left"><strong><span style="font-size: 9pt">::WideCharToMultiByte</span></strong><strong><span style="font-size: 9pt">：</span></strong><span style="font-size: 9pt">实现</span><span style="font-size: 9pt">Unicode</span><span style="font-size: 9pt">码到当前码的转换；</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt">(2)Java</span><span style="font-size: 9pt">中的实现方法</span> </div>
<div style="text-indent: 4.45pt; line-height: 20pt" align="left"><strong><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp; String vcString=new String(javaString.getBytes("UTF-8"),"gb2312");</span></strong></div>
<div style="text-indent: 17.8pt; line-height: 20pt" align="left"><span style="font-size: 9pt">java</span><span style="font-size: 9pt">的编码应该是</span><span style="font-size: 9pt">UTF-8</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt">(3)C#</span><span style="font-size: 9pt">中的实现方法</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp; ??</span></div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt; color: red">四 vc中的MutiByte Charater Set 和 Wide Character Set</span></div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt; color: blue">1.MultiByte Charater Set</span><span style="font-size: 9pt; color: blue">方式</span> </div>
<div style="line-height: 20pt" align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9pt">这种方式以按字节为单位存放字符，即如果一个字符码为两字节，则在内存中占两字节，字符码为一字节，就占一字节。例如，字符串&#8220;中国abc&#8221;的编码为：中(0xd6、0xd0)、国(0xb9、0xfa)、a(0x61)、b(0x62)、c(0x63)、\0(0x00)，就存为如下方式：</span> </div>
<div><img alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/fishinthewind/Win_1.bmp" /></div>
<div></div>
<div></div>
<div>
<div style="text-indent: 13.5pt; line-height: 18pt"><span style="font-size: 9pt">对应的类型，方法有：</span></div>
<div style="line-height: 18pt"><span style="font-size: 9pt">char</span><span style="font-size: 9pt">、scanf、printf、cin、cout &#8230;</span> </div>
<div style="line-height: 18pt">
<div style="line-height: 18pt"><span style="font-size: 9pt; color: blue">2.Wide Character Set</span></div>
<div style="line-height: 18pt"><span style="font-size: 9pt; color: blue"><span style="font-size: 9pt"><font color="#000000">这种方式是以两字节为单位存放字符，即如果一个字符码为两字节，则在内存中占四字节，字符码为一<span style="font-size: 9pt">字节，就占两字节。例如，字符串&#8220;中国<span>abc</span>&#8221;就存为如下方式：</span></font></span></span></div>
<div style="line-height: 18pt"><span style="font-size: 9pt; color: blue"><span style="font-size: 9pt"><font color="#000000"></font></span></span></div>
<div style="line-height: 18pt"><span style="font-size: 9pt; color: blue"><span style="font-size: 9pt"><font color="#000000"></font></span></span></div>
</div>
</div>
<div><img alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/fishinthewind/win_2.bmp" /></div>
<div></div>
<div></div>
<div><span style="font-size: 9pt">对应的类型，方法有：</span></div>
<div>
<div style="line-height: 18pt"><span style="font-size: 9pt">wchar_t</span><span style="font-size: 9pt">、wscanf、wprintf、wcin、wcout &#8230;</span> </div>
<div style="text-indent: 13.5pt; line-height: 18pt"><span style="font-size: 9pt">造成上面存储方式的根本原因在于，<span style="color: red">wchar_t</span><span style="color: red">类型其实是一个unsigned short 类型</span>。如，存储上面字符串的数组的定义为：wchar_t buffer[8] 等价于unsigned short buffer[8].而所有以字母w开头的方法也都是以unsigned short类型,即两字节为单位来处理字符，因此，存储在wchar_t类型数组中的字符串无法用cout显示，只能用wcout方法来显示。</span></div>
<div style="text-indent: 13.5pt; line-height: 18pt"><span style="font-size: 9pt">由于Unicode码也是采用两个字节，因此Wide Character Set方式能够很好的支持Unicode码的存储，但是在vc的环境下要将一个Unicode码存入两字节而不是四字节内存中，必须通过上面的API函数</span><strong><span style="font-size: 9pt">::MultiByteToWideChar</span></strong><strong><span style="font-size: 9pt">。</span></strong><span style="font-size: 9pt">首先，将当前的编码转换为Unicode码，然后，将每个字符的Unicode码放入每一个wchar_t类型的变量中。以下是一个实例代码：</span> </div>
<div style="line-height: 18pt" align="left"><span style="font-size: 9pt; color: blue">char</span><span style="font-size: 9pt"> input[50];</span> </div>
<div style="line-height: 18pt" align="left"><span style="font-size: 9pt">cin&gt;&gt;input;</span></div>
<div style="line-height: 18pt" align="left"><span style="font-size: 9pt; color: blue">int</span><span style="font-size: 9pt"> size;</span> </div>
<div style="line-height: 18pt" align="left"><span style="font-size: 9pt">size=::MultiByteToWideChar(CP_ACP,0,input,strlen(input)+1,NULL,0);</span></div>
<div style="line-height: 18pt" align="left"><span style="font-size: 9pt; color: blue">if</span><span style="font-size: 9pt">(size==0)</span> </div>
<div style="line-height: 18pt" align="left"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">return</span> -1;</span></div>
<div style="line-height: 18pt" align="left"><span style="font-size: 9pt; color: blue">wchar_t</span><span style="font-size: 9pt"> *widebuff=<span style="color: blue">new</span> <span style="color: blue">wchar_t</span>[size];</span> </div>
<div style="line-height: 18pt"><span style="font-size: 9pt">::MultiByteToWideChar(CP_ACP,0,input,strlen(input)+1,widebuff,size);</span></div>
<div style="line-height: 18pt"><span style="font-size: 9pt">输入：中国abc</span></div>
<div style="line-height: 18pt"><span style="font-size: 9pt">Debug</span><span style="font-size: 9pt">断点调试：</span> </div>
<div style="line-height: 18pt"><span style="font-size: 9pt">size==6</span></div>
<div style="line-height: 18pt"><span style="font-size: 9pt">数组widebuff[0-size]占12字节，存放了6个字符的Unicode码，码值为：</span></div>
<div style="text-indent: 9pt; line-height: 18pt"><span style="font-size: 9pt">中(0x4e2d) 国(0x56fd) a(0x0061) b(0x0062) c(0x0063) d(0x0000)</span></div>
<div style="line-height: 18pt"><span style="font-size: 9pt">这时，数组的大小size等于输入的字符个数加上一个结束符，符合我们的想象。</span></div>
<div style="line-height: 18pt"><span style="font-size: 9pt; color: red">五 引入问题的错误分析</span></div>
<div style="line-height: 18pt"><span style="font-size: 9pt">(1) </span><span style="font-size: 9pt">没有理解编译器中的编码方式</span> </div>
<div style="line-height: 18pt"><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9pt">虽然vc/c++中汉字的编码占两个字节，但并不是Unicode码，是GB2312码。</span> </div>
<div style="line-height: 18pt"><span style="font-size: 9pt">(2) </span><span style="font-size: 9pt">没有理解MutiByte Charater Set 和 Wide Character Set的存储原则；</span> </div>
<div><span style="font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9pt">在vc/c++中，&#8220;中国&#8221;按char[5]来对待，而wchar_t a[3]实际上是三个unsigned short类型的变量，因此赋值时会越界。</span></div>
</div>
</div><img src ="http://www.blogjava.net/dongwq/aggbug/318627.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2010-04-18 01:10 <a href="http://www.blogjava.net/dongwq/archive/2010/04/18/318627.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gameloft??</title><link>http://www.blogjava.net/dongwq/archive/2010/04/17/318576.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Fri, 16 Apr 2010 17:38:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2010/04/17/318576.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/318576.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2010/04/17/318576.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/318576.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/318576.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;
<p>//gameloft 笔试题<br />
/* <br />
1、RGB值转灰度值对32位整数取R，G，B对应的8位并加权合成。<br />
2、求一个字符串中出现频率最高的字符。字符范围并涡有说明，通常应<br />
指ASCII字符集，可是当时考虑复杂了，于是想到了stl的map来做。<br />
结果没有写完。就交了。 <br />
*/ <br />
#include&lt;iostream&gt;</p>
<p>using namespace std;<br />
#define CHARNUM 256&nbsp; <br />
//计算一个串最出现频率最高的字符</p>
<p>char mostFreq(const char* str)<br />
{<br />
&nbsp;int freq[CHARNUM]= {0};<br />
&nbsp;int firstPos[CHARNUM] = {0};<br />
&nbsp;int pos = 0; <br />
&nbsp;const char* p = str;<br />
&nbsp;while( *p != '\0')<br />
&nbsp;{<br />
&nbsp;&nbsp;if(freq[*p] == 0)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;firstPos[*p] = pos;&nbsp; <br />
&nbsp;&nbsp;} <br />
&nbsp;&nbsp;freq[*p++]++;<br />
&nbsp; &nbsp;pos++;<br />
&nbsp; }<br />
&nbsp; int maxF = -1;<br />
&nbsp; int ch = '\0';<br />
&nbsp; for(int i = 1;i &lt; 256;i++)<br />
&nbsp; {<br />
&nbsp; &nbsp;if( freq[i] &gt; maxF)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp; &nbsp;ch = i;<br />
&nbsp;&nbsp; maxF = freq[i]; <br />
&nbsp;&nbsp; } <br />
&nbsp;&nbsp; if( freq[i] == maxF)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp; &nbsp;if( firstPos[i] &lt; firstPos[ch])<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp; &nbsp;ch = i;&nbsp; <br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp; } &nbsp; &nbsp; <br />
&nbsp; } <br />
&nbsp; cout&lt;&lt;" maxF ="&lt;&lt;maxF&lt;&lt;endl;<br />
&nbsp; <br />
&nbsp; return (char)ch; <br />
} <br />
&nbsp;<br />
int main()<br />
{<br />
&nbsp;int* a[9][4][5];<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;int b = a[5] - a[3];<br />
&nbsp;cout&lt;&lt;"b = "&lt;&lt;b&lt;&lt;endl;<br />
&nbsp;<br />
&nbsp;int* c[3];<br />
&nbsp;<br />
&nbsp;char * str = "aabyebbdfdf&nbsp;1`5454545$$$#$#$2788kldef";<br />
&nbsp;<br />
&nbsp;char ch;<br />
&nbsp;ch = mostFreq( str); <br />
&nbsp;<br />
&nbsp;cout&lt;&lt;"ch = " &lt;&lt;ch&lt;&lt;endl; <br />
}<br />
4.给出一个CThing 类的源代码让分析，其中有三个语句要求解释语句作用。<br />
一个填空，分析时有点忙了，应该一个函数一个函数的分析，或许会有清晰思路。<br />
将各个类的名称和功能整理下会理出些思路。<br />
5、给出strcpy的源代码让说明其功能，并指出参数设置上只少一人错误<br />
6、给出一个将整数i转换为8进制的方法，要求对其进行改进。<br />
src:<br />
void count(int i, char* str)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp; map[ <br />
&nbsp;sorry, 记忆不清楚了 </p>
<p>7、给几个名词让解释placement new,ARM, GCC, android, 还有一人？？<br />
&nbsp;8、英文解释题目。第一个还好。第二个说游戏加速的<br />
&nbsp;<br />
&nbsp;increment&nbsp; ...update frame , ??这词词认识，放一起读不出来表示什么<br />
&nbsp;意思 <br />
</p><img src ="http://www.blogjava.net/dongwq/aggbug/318576.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2010-04-17 01:38 <a href="http://www.blogjava.net/dongwq/archive/2010/04/17/318576.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++一些用法整理</title><link>http://www.blogjava.net/dongwq/archive/2010/04/16/318481.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Fri, 16 Apr 2010 02:31:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2010/04/16/318481.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/318481.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2010/04/16/318481.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/318481.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/318481.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;1&nbsp;&nbsp;2&nbsp;&nbsp;3&nbsp;&nbsp;4#include&lt;cstdio&gt;&nbsp;&nbsp;5#include&lt;iostream&gt;&nbsp;&nbsp;6#include&lt;cstdlib&gt;&nbsp;&nbsp;7#include&lt;typeinfo&gt;&nbs...&nbsp;&nbsp;<a href='http://www.blogjava.net/dongwq/archive/2010/04/16/318481.html'>阅读全文</a><img src ="http://www.blogjava.net/dongwq/aggbug/318481.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2010-04-16 10:31 <a href="http://www.blogjava.net/dongwq/archive/2010/04/16/318481.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CSingleList的类实现，可以丰富起来</title><link>http://www.blogjava.net/dongwq/archive/2010/04/16/318480.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Fri, 16 Apr 2010 02:30:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2010/04/16/318480.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/318480.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2010/04/16/318480.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/318480.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/318480.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;1&nbsp;&nbsp;2&nbsp;&nbsp;3//&nbsp;realize&nbsp;a&nbsp;SingleList&nbsp;class&nbsp;&nbsp;4/**//*&nbsp;&nbsp;5实现方法&nbsp;&nbsp;6add()&nbsp;&nbsp;7add2Head(dd);&nbsp;&nbsp;8del...&nbsp;&nbsp;<a href='http://www.blogjava.net/dongwq/archive/2010/04/16/318480.html'>阅读全文</a><img src ="http://www.blogjava.net/dongwq/aggbug/318480.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2010-04-16 10:30 <a href="http://www.blogjava.net/dongwq/archive/2010/04/16/318480.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>指向指针的引用</title><link>http://www.blogjava.net/dongwq/archive/2009/04/15/265844.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Wed, 15 Apr 2009 13:03:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2009/04/15/265844.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/265844.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2009/04/15/265844.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/265844.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/265844.html</trackback:ping><description><![CDATA[＊＊君子耻其言而过其行＊＊<br />
<br />
typedef&nbsp;&nbsp; int*&nbsp;&nbsp; pint; <br />
typedef&nbsp;&nbsp; pint*&nbsp;&nbsp; ppint; <br />
void&nbsp;&nbsp; func(ppint&nbsp;&nbsp; &amp;x) <br />
{ <br />
&nbsp;x&nbsp;&nbsp; =&nbsp;&nbsp; new&nbsp;&nbsp; int*; <br />
&nbsp;*x=&nbsp;&nbsp; new&nbsp;&nbsp; int(32); <br />
} <br />
//使用方法<br />
<p>&nbsp;int&nbsp;&nbsp; **p=0; <br />
&nbsp;func(p); <br />
&nbsp;cout&lt;&lt;(**p)&lt;&lt;endl; </p>
<p>&nbsp;int *pV;<br />
&nbsp;pV =&nbsp; new int(2);　　//这里注意与在cpp中与java中语法的差异<br />
&nbsp;cout&lt;&lt;"PV = "&lt;&lt;(*pV)&lt;&lt;endl;</p>
&nbsp;int ival = 1024; <br />
&nbsp;int *pi = &amp;ival; <br />
&nbsp;int* &amp;ptrVal2 = pi;<img src ="http://www.blogjava.net/dongwq/aggbug/265844.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2009-04-15 21:03 <a href="http://www.blogjava.net/dongwq/archive/2009/04/15/265844.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zz泛型编程：源起、实现与意义</title><link>http://www.blogjava.net/dongwq/archive/2009/01/04/249663.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Sat, 03 Jan 2009 16:28:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2009/01/04/249663.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/249663.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2009/01/04/249663.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/249663.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/249663.html</trackback:ping><description><![CDATA[<div align="center"><strong><span style="font-size: 22pt">泛型编程：源起、实现与意义</span></strong></div>
<div>&nbsp;<span style="font-size: 12pt">By </span><span style="font-size: 12pt">刘未鹏 </span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">的罗浮宫</span><span style="font-size: 12pt">(<a href="http://blog.csdn.net/pongba">http://blog.csdn.net/pongba</a>)</span><span style="font-size: 12pt">(</span><span style="font-size: 12pt">去年</span><span style="font-size: 12pt">12</span><span style="font-size: 12pt">月《程序员》的约稿</span><span style="font-size: 12pt">)</span></div>
<div align="center"><span style="font-size: 12pt">(</span><span style="font-size: 12pt">以前也写过一篇相关的文章：</span><span style="font-size: 12pt"><a href="http://blog.csdn.net/pongba/archive/2007/07/29/1715263.aspx">Generic Programming - What Are You, anyway?</a> )</span></div>
<div>&nbsp;<strong><span style="font-size: 16pt">为什么泛型</span></strong></div>
<div><span style="font-size: 12pt">泛型编程（</span><span style="font-size: 12pt">Generic Programming</span><span style="font-size: 12pt">）最初提出时的动机很简单直接：发明一种语言机制，能够帮助实现一个通用的标准容器库。所谓通用的标准容器库，就是要能够做到，比如用一个</span><span style="font-size: 12pt">List</span><span style="font-size: 12pt">类存放所有可能类型的对象</span><span style="font-size: 12pt">,</span><span style="font-size: 12pt">这样的事情；熟悉一些其它面向对象的语言的人应该知道，如</span><span style="font-size: 12pt">Java</span><span style="font-size: 12pt">里面这是通过在</span><span style="font-size: 12pt">List</span><span style="font-size: 12pt">里面存放</span><span style="font-size: 12pt">Object</span><span style="font-size: 12pt">引用来实现的。</span><span style="font-size: 12pt">Java</span><span style="font-size: 12pt">的单根继承在这里起到了关键的作用。然而单根继承对</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">这样的处在语言链底层的语言却是不能承受之重。此外使用单根继承来实现通用容器也会带来效率和类型安全方面的问题，两者都与</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">的理念不相吻合。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">于是</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">另谋他法——除了单根继承之外，另一个实现通用容器的方案就是使用&#8220;参数化类型&#8221;。一个容器需要能够存放任何类型的对象，那干脆就把这个对象的类型&#8220;抽&#8221;出来，参数化它</span><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn1" name="_ftnref1"><span style="font-size: 12pt">[1]</span></a><span style="font-size: 12pt">：</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">template&lt;class T&gt; class vector {</span></div>
<div><span style="font-size: 12pt">&nbsp;T* v;</span></div>
<div><span style="font-size: 12pt">&nbsp;int sz;</span></div>
<div><span style="font-size: 12pt">public:</span></div>
<div><span style="font-size: 12pt">&nbsp;vector(int);</span></div>
<div><span style="font-size: 12pt">&nbsp;T&amp; operator[](int);</span></div>
<div><span style="font-size: 12pt">&nbsp;T&amp; elem(int i) { return v[i]; }</span></div>
<div><span style="font-size: 12pt">&nbsp;// ...</span></div>
<div><span style="font-size: 12pt">};</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">一般来说看到这个定义的时候，每个人都会想到</span><span style="font-size: 12pt">C</span><span style="font-size: 12pt">的宏。的确，模板和宏在精神上的确有相仿之处。而且的确，也有人使用</span><span style="font-size: 12pt">C</span><span style="font-size: 12pt">的宏来实现通用容器。模板是将一个定义里面的类型参数化出来，而宏也可以做到参数化类型。甚至某种意义上可以说宏是模板的超集——因为宏不仅可以参数化类型，宏实质上可以参数化一切文本，因为它本来就是一个文本替换工具。然而，跟模板相比，宏的最大的缺点就是它并不工作在</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">的语法解析层面，宏是由预处理器来处理的，而在预处理器的眼里没有</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">，只有一堆文本，因此</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">的类型检查根本不起作用。比如上面的定义如果用宏来实现，那么就算你传进去的</span><span style="font-size: 12pt">T</span><span style="font-size: 12pt">不是一个类型，预处理器也不会报错；只有等到文本替换完了，到</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">编译器工作的时候才会发现一堆莫名其妙的类型错误，但那个时候错误就已经到处都是了。往往最后会抛出一堆吓人的编译错误。更何况宏基本无法调试。</span></div>
<div>&nbsp;</div>
<div style="border-right: windowtext 1pt solid; padding-right: 4pt; border-top: windowtext 1pt solid; padding-left: 4pt; padding-bottom: 1pt; border-left: windowtext 1pt solid; padding-top: 1pt; border-bottom: windowtext 1pt solid">
<div style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none"><strong><span style="font-size: 12pt">注</span></strong><strong><span style="font-size: 12pt">1</span></strong></div>
<div style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">实际上，还有一种实现通用容器的办法。只不过它更糟糕：它要求任何能存放在容器内的类型都继承自一个NodeBase，NodeBase里面有pre和next指针，通过这种方式，就可以将任意类型链入一个链表内了。但这种方式的致命缺点是(1)它是侵入性的，每个能够放在该容器内的类型都必须继承自NodeBase基类。(2)它不支持基本内建类型（int、double等），因为内建类型并不，也不能继承自NodeBase。这还姑且不说它是类型不安全的，以及效率问题。</div>
</div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">我们再来看一看通用算法，这是泛型的另一个动机。比如我们熟悉的</span><span style="font-size: 12pt">C</span><span style="font-size: 12pt">的</span><span style="font-size: 12pt">qsort</span><span style="font-size: 12pt">：</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">void qsort(void *base, size_t nmemb, size_t size,</span></div>
<div style="text-indent: 54pt"><span style="font-size: 12pt">int (*compar)(const void *, const void *));</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">这个算法有如下几个问题：</span></div>
<div>&nbsp;</div>
<div style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 12pt">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 12pt">类型安全性：使用者必须自行保证</span><span style="font-size: 12pt">base</span><span style="font-size: 12pt">指向的数组的元素类型和</span><span style="font-size: 12pt">compar</span><span style="font-size: 12pt">的两个参数的类型是一致的；使用者必须自行保证</span><span style="font-size: 12pt">size</span><span style="font-size: 12pt">必须是数组元素类型的大小。</span></div>
<div style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 12pt">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 12pt">通用性：</span><span style="font-size: 12pt">qsort</span><span style="font-size: 12pt">对参数数组的二进制接口有严格要求——它必须是一个内存连续的数组。如果你实现了一个巧妙的、分段连续的自定义数组，就没法使用</span><span style="font-size: 12pt">qsort</span><span style="font-size: 12pt">了。</span></div>
<div style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 12pt">3.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 12pt">接口直观性：如果你有一个数组</span><span style="font-size: 12pt">char* arr = new arr[10];</span><span style="font-size: 12pt">那么该数组的元素类型其实就已经&#8220;透露&#8221;了它自己的大小。然而</span><span style="font-size: 12pt">qsort</span><span style="font-size: 12pt">把数组的元素类型给&#8220;</span><span style="font-size: 12pt">void</span><span style="font-size: 12pt">&#8221;掉了（</span><span style="font-size: 12pt">void *base</span><span style="font-size: 12pt">），于是丢失掉了这一信息，而只能让调用方手动提供一个</span><span style="font-size: 12pt">size</span><span style="font-size: 12pt">。为什么要把数组类型声明为</span><span style="font-size: 12pt">void*</span><span style="font-size: 12pt">？因为除此之外别无它法，声明为任意一个类型的指针都不妥（</span><span style="font-size: 12pt">compar</span><span style="font-size: 12pt">的参数类型也是如此）。</span><span style="font-size: 12pt">qsort</span><span style="font-size: 12pt">为了通用性，把类型信息丢掉了，进而导致了必须用额外的参数来提供类型大小信息。在这个特定的算法里问题还不明显，毕竟只多一个</span><span style="font-size: 12pt">size</span><span style="font-size: 12pt">参数而已，但一旦涉及的类型信息多了起来，其接口的可伸缩性（</span><span style="font-size: 12pt">scalability</span><span style="font-size: 12pt">）问题和直观性问题就会逐渐显现。</span></div>
<div style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 12pt">4.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 12pt">效率：</span><span style="font-size: 12pt">compar</span><span style="font-size: 12pt">是通过函数指针调用的，这带来了一定的开销。但跟上面的其它问题比起来这个问题还不是最严重的。</span></div>
<div>&nbsp;</div>
<div><strong><span style="font-size: 16pt">泛型编程</span></strong></div>
<div><span style="font-size: 12pt">泛型编程最初诞生于</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">中，由</span><span style="font-size: 12pt">Alexander Stepanov<a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn2" name="_ftnref2">[2]</a></span><span style="font-size: 12pt">和</span><span style="font-size: 12pt">David Musser<a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn3" name="_ftnref3">[3]</a></span><span style="font-size: 12pt">创立。目的是为了实现</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">的</span><span style="font-size: 12pt">STL</span><span style="font-size: 12pt">（标准模板库）。其语言支持机制就是模板（</span><span style="font-size: 12pt">Templates</span><span style="font-size: 12pt">）。模板的精神其实很简单：参数化类型。换句话说，把一个原本特定于某个类型的算法或类当中的类型信息抽掉，抽出来做成模板参数</span><span style="font-size: 12pt">T</span><span style="font-size: 12pt">。比如</span><span style="font-size: 12pt">qsort</span><span style="font-size: 12pt">泛化之后就变成了：</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">template&lt;class RandomAccessIterator, class Compare&gt;</span></div>
<div><span style="font-size: 12pt">void sort(RandomAccessIterator first, RandomAccessIterator last,</span></div>
<div><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Compare comp);</span></div>
<div><span style="font-size: 12pt">其中</span><span style="font-size: 12pt">first</span><span style="font-size: 12pt">，</span><span style="font-size: 12pt">last</span><span style="font-size: 12pt">这一对迭代器代表一个前闭后开区间，迭代器和前开后闭区间都是</span><span style="font-size: 12pt">STL</span><span style="font-size: 12pt">的核心概念。迭代器建模的是内建指针的接口（解引用、递增、递减等）、前开后闭区间是一个简单的数学概念，表示从</span><span style="font-size: 12pt">first</span><span style="font-size: 12pt">（含</span><span style="font-size: 12pt">first</span><span style="font-size: 12pt">）到</span><span style="font-size: 12pt">last</span><span style="font-size: 12pt">（不含</span><span style="font-size: 12pt">last</span><span style="font-size: 12pt">）的区间内的所有元素。此外，</span><span style="font-size: 12pt">comp</span><span style="font-size: 12pt">是一个仿函数（</span><span style="font-size: 12pt">functor</span><span style="font-size: 12pt">）。仿函数也是</span><span style="font-size: 12pt">STL</span><span style="font-size: 12pt">的核心概念，仿函数是建模的内建函数的接口，一个仿函数可以是一个内建的函数，也可以是一个重载了</span><span style="font-size: 12pt">operator()</span><span style="font-size: 12pt">的类对象，只要是支持函数调用的语法形式就可成为一个仿函数。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">通过操作符重载，</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">允许了自定义类型具有跟内建类型同样的使用接口；又通过模板这样的参数化类型机制，</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">允许了一个算法或类定义，能够利用这样的接口一致性来对自身进行泛化。例如，一个原本操作内建指针的算法，被泛化为操纵一切迭代器的算法。一个原本使用内建函数指针的算法，被泛化为能够接受一切重载了函数调用操作符（</span><span style="font-size: 12pt">operator()</span><span style="font-size: 12pt">）的类对象的算法。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">让我们来看一看模板是如何解决上面所说的</span><span style="font-size: 12pt">qsort</span><span style="font-size: 12pt">的各个问题的：</span></div>
<div>&nbsp;</div>
<div style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 12pt">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 12pt">类型安全性：如果你调用</span><span style="font-size: 12pt">std::sort(arr, arr + n, comp);</span><span style="font-size: 12pt">那么</span><span style="font-size: 12pt">comp</span><span style="font-size: 12pt">的类型就必须要和</span><span style="font-size: 12pt">arr</span><span style="font-size: 12pt">的数组元素类型一致，否则编译器就会帮你检查出来。而且</span><span style="font-size: 12pt">comp</span><span style="font-size: 12pt">的参数类型再也不用</span><span style="font-size: 12pt">const void*</span><span style="font-size: 12pt">这种不直观的表示了，而是可以直接声明为对应的数组元素的类型。</span></div>
<div style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 12pt">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 12pt">通用性：这个刚才已经说过了。泛型的核心目的之一就是通用性。</span><span style="font-size: 12pt">std::sort</span><span style="font-size: 12pt">可以用于一切迭代器，其</span><span style="font-size: 12pt">compare</span><span style="font-size: 12pt">函数可以是一切支持函数调用语法的对象。如果你想要将</span><span style="font-size: 12pt">std::sort</span><span style="font-size: 12pt">用在你自己的容器上的话，你只要定义一个自己的迭代器类（严格来说是一个随机访问迭代器，</span><span style="font-size: 12pt">STL</span><span style="font-size: 12pt">对迭代器的访问能力有一些分类，随机访问迭代器具有建模的内建指针的访问能力），如果需要的话，再定义一个自己的仿函数类即可。</span></div>
<div style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 12pt">3.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 12pt">接口直观性：跟</span><span style="font-size: 12pt">qsort</span><span style="font-size: 12pt">相比，</span><span style="font-size: 12pt">std::sort</span><span style="font-size: 12pt">的使用接口上没有多余的东西，也没有不直观的</span><span style="font-size: 12pt">size</span><span style="font-size: 12pt">参数。一个有待排序的区间，一个代表比较标准的仿函数，仅此而已</span><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn4" name="_ftnref4"><span style="font-size: 12pt">[4]</span></a><span style="font-size: 12pt">。</span></div>
<div style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 12pt">4.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 12pt">效率：如果你传给</span><span style="font-size: 12pt">std::sort</span><span style="font-size: 12pt">的</span><span style="font-size: 12pt">compare</span><span style="font-size: 12pt">函数是一个自定义了</span><span style="font-size: 12pt">operator()</span><span style="font-size: 12pt">的仿函数。那么编译器就能够利用类型信息，将对该仿函数的</span><span style="font-size: 12pt">operatpr()</span><span style="font-size: 12pt">调用直接内联。消除函数调用开销。</span></div>
<div>&nbsp;</div>
<div><strong><span style="font-size: 16pt">动态多态与静态多态</span></strong></div>
<div><span style="font-size: 12pt">泛型编程的核心活动是抽象：将一个特定于某些类型的算法中那些类型无关的共性抽象出来，比如，在</span><span style="font-size: 12pt">STL</span><span style="font-size: 12pt">的概念体系里面，管你是一个数组还是一个链表，反正都是一个区间，这就是一层抽象。管你是一个内建函数还是一个自定义类，反正都是一个</span><span style="font-size: 12pt">Callable</span><span style="font-size: 12pt">（可调用）的对象（在</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">里面通过仿函数来表示），这就是一层抽象。泛型编程的过程就是一个不断将这些抽象提升（</span><span style="font-size: 12pt">lift</span><span style="font-size: 12pt">）出来的过程，最终的目的是形成一个最大程度上通用的算法或类。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">有人肯定会问，既然同是抽象，那为什么不用基于多态的面向对象抽象呢？比如</span><span style="font-size: 12pt">STL</span><span style="font-size: 12pt">的</span><span style="font-size: 12pt">std::for_each</span><span style="font-size: 12pt">，用</span><span style="font-size: 12pt">Java</span><span style="font-size: 12pt">的多态机制也可以解决：</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">interface IUnaryFun</span></div>
<div><span style="font-size: 12pt">{</span></div>
<div style="text-indent: 12pt"><span style="font-size: 12pt">void invoke(Object o);</span></div>
<div><span style="font-size: 12pt">}</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">interface IInputIter</span></div>
<div><span style="font-size: 12pt">{</span></div>
<div style="text-indent: 12pt"><span style="font-size: 12pt">IInputIter preIncrement();</span></div>
<div style="text-indent: 12pt"><span style="font-size: 12pt">boolean equals(IInputIter otherIter);</span></div>
<div style="text-indent: 12pt"><span style="font-size: 12pt">&#8230; // other methods</span></div>
<div><span style="font-size: 12pt">}</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">IUnaryFun for_each(IInputIter first, IInputIter last, IUnaryFun func)</span></div>
<div><span style="font-size: 12pt">{</span></div>
<div><span style="font-size: 12pt">&nbsp;for(;!first.equals(last); first.preIncrement())</span></div>
<div style="text-indent: 24pt"><span style="font-size: 12pt">func.invoke(*first);</span></div>
<div><span style="font-size: 12pt">&nbsp;return func;</span></div>
<div><span style="font-size: 12pt">}</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">其实，这里最主要的原因很简单，效率。面向对象的多态引入了间接调用。当然，并不是说间接调用不好，有些时候，比如确实需要运行期多态的时候，只能诉诸继承这样的手段。但当能够利用编译期类型信息的时候，为什么要付出不必要的间接调用开销呢？比如这里的</span><span style="font-size: 12pt">for_each</span><span style="font-size: 12pt">，利用接口来实现其通用性，就付出了所谓的&#8220;抽象惩罚&#8221;（</span><span style="font-size: 12pt">abstraction penalty</span><span style="font-size: 12pt">）。而</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">的模板，就是为了消除这样的抽象惩罚。利用模板编写的</span><span style="font-size: 12pt">std::for_each</span><span style="font-size: 12pt">，对于每一个特定的参数类型组合都有一个独立的，最高效的实例化版本，就跟你手写一个特定于这些类型的专门的</span><span style="font-size: 12pt">for_each</span><span style="font-size: 12pt">算法一样</span><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn5" name="_ftnref5"><span style="font-size: 12pt">[5]</span></a><span style="font-size: 12pt">。于是抽象惩罚消失了，而这也正是</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">模板库能够真正被工业界广泛用在</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">最擅长的领域（重视效率的领域）的重要原因之一。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">另一方面，对于每一组参数类型组合实例化一个版本出来的做法增加了代码空间，这是一个典型的以空间换时间的例子，不过对于一门静态并追求效率的语言来说，这个代码空间的开销反正也是必不可少的，因为即便你手动为各种不同的参数类型组合编写特定的算法版本的话，也是付出一样的代码空间开销，而且还顺便违反了</span><span style="font-size: 12pt">DRY</span><span style="font-size: 12pt">原则</span><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn6" name="_ftnref6"><span style="font-size: 12pt">[6]</span></a><span style="font-size: 12pt">。此外，由于在抽象的时候不用总想着要建立的接口，所以泛型算法编写起来也更为直观。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">泛型的另一个好处就是，跟面向对象编程的基于继承和虚函数的运行时多态机制不同，</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">模板是非侵入性的。你不需要让你的类继承自某个特定的接口才能用于某个算法，只要支持特定的语法接口就行了（比如只要支持</span><span style="font-size: 12pt">begin()</span><span style="font-size: 12pt">调用）。这也被称为结构一致性（</span><span style="font-size: 12pt">Structural Conformance</span><span style="font-size: 12pt">），意即只要语法结构一致即可。而另一方面，基于接口继承的面向对象多态则必须要显式地声明继承自一个接口，这就是所谓的名字一致性（</span><span style="font-size: 12pt">Named Conformance</span><span style="font-size: 12pt">）。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">当然，泛型支持的静态多态和虚函数支持的动态多态并没有任何程度上绝对的优劣之分。它们适用于不同的场合。当类型信息可得的时候，利用编译期多态能够获得最大的效率和灵活性。当具体的类型信息不可得，就必须诉诸运行期多态了。</span><span style="font-size: 12pt">Bjarne Stroustrup</span><span style="font-size: 12pt">曾经用了一个典型的例子来澄清这个区别：</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">std::vector&lt;Shape*&gt; v;</span></div>
<div><span style="font-size: 12pt">&#8230; // fill v</span></div>
<div><span style="font-size: 12pt">std::for_each(v.begin(), v.end(), std::mem_fun(&amp;Shape::draw));</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">这里，</span><span style="font-size: 12pt">v</span><span style="font-size: 12pt">里面到底将来会存放什么类型的</span><span style="font-size: 12pt">Shape</span><span style="font-size: 12pt">，编译期无法知道，因而必须求助于动态多态。另一方面，编译器倒的确知道它们都继承自</span><span style="font-size: 12pt">Shape</span><span style="font-size: 12pt">，利用这仅有的静态类型信息，我们使用了泛型算法</span><span style="font-size: 12pt">std::for_each</span><span style="font-size: 12pt">和泛型容器</span><span style="font-size: 12pt">std::vector</span><span style="font-size: 12pt">。这里尤其值得注意的是</span><span style="font-size: 12pt">for_each</span><span style="font-size: 12pt">的静态多态行为：</span><span style="font-size: 12pt">for_each</span><span style="font-size: 12pt">只有一份模板实现，然而根据传给它的第三个参数（本例中是</span><span style="font-size: 12pt">std::mem_fun(&amp;Shape::draw)</span><span style="font-size: 12pt">）的不同，</span><span style="font-size: 12pt">for_each</span><span style="font-size: 12pt">的行为也不同（这里最终被</span><span style="font-size: 12pt">for_each</span><span style="font-size: 12pt">调用的是</span><span style="font-size: 12pt">Shape::draw</span><span style="font-size: 12pt">，但实际上你可以包装任何函数，只要这个函数接受一个</span><span style="font-size: 12pt">Shape*</span><span style="font-size: 12pt">型的参数），</span><span style="font-size: 12pt">for_each</span><span style="font-size: 12pt">这种&#8220;行为不同&#8221;是发生在编译期的，所以是静态多态。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">前面说过，模板与接口继承比较，模板是非侵入的。这是</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">泛型与面向对象的多态机制的本质区别之一。但实际上，面向对象未必就意味着一定要用接口来实现动态的多态。一些动态类型的脚本语言，如</span><span style="font-size: 12pt">Ruby</span><span style="font-size: 12pt">，它的多态机制就既是运行期（动态）的，又是非倾入性的（不用通过继承自某个特定的接口来达到复用）。人们把这个叫做</span><span style="font-size: 12pt">Duck Typing<a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn7" name="_ftnref7">[7]</a></span><span style="font-size: 12pt">。如果不是因为效率问题，其实这样的多态机制才是最直观的，从使用方面来说，它既有非侵入性，又没有只能工作在编译期的限制。但效率至少在可见的将来、在某些领域仍是一个顾虑。因此像</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">这种区分编译期和运行期多态的语言，仍有其独特的优势。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">此外，泛型编程的类型安全优势也让它从</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">走入了其它主流的静态类型语言当中，尤其是</span><span style="font-size: 12pt">C</span><span style="font-size: 12pt">家族的</span><span style="font-size: 12pt">Java</span><span style="font-size: 12pt">和</span><span style="font-size: 12pt">C#</span><span style="font-size: 12pt">，在前几年相继接纳泛型。</span></div>
<div>&nbsp;</div>
<div><strong><span style="font-size: 16pt">特化，图灵完备性，元编程</span></strong></div>
<div><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">的模板是支持特化的，这就给了它实现编译期控制结构的可能性，进而带来了一个图灵完备的子语言。模板特化的引入原本只是为了效率目的——针对不同的类型提供不同的实现。但后来却被发现能够实现编译期的</span><span style="font-size: 12pt">if/else</span><span style="font-size: 12pt">和递归等控制结构。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">模板元编程最初由</span><span style="font-size: 12pt">Erwin Unruh</span><span style="font-size: 12pt">在</span><span style="font-size: 12pt">1994</span><span style="font-size: 12pt">年的一次会议上提出；当时他写了一个程序，在编译错误里面打印出一个素数序列。这个事件在</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">历史上的地位就仿佛哥伦布发现新大陆。用</span><span style="font-size: 12pt">Bjarne Stroustrup</span><span style="font-size: 12pt">的话来说就是当时他当时和其他几个人觉得太神奇了。实际上，这个事情正标志了</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">模板系统的图灵完备性被发现；后来</span><span style="font-size: 12pt">Todd Veldhuizen</span><span style="font-size: 12pt">写了一篇</span><span style="font-size: 12pt">paper</span><span style="font-size: 12pt">，用</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">模板构建了一个元图灵机，从而第一次系统证明了</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">模板的图灵完备性。接下来的事情就顺理成章了——一些</span><span style="font-size: 12pt">ad hoc</span><span style="font-size: 12pt">的模板元编程技巧不断被发掘出来，用于建造高效、高适应性的通用组件。最终，</span><span style="font-size: 12pt">David Abrahams</span><span style="font-size: 12pt">编写了</span><span style="font-size: 12pt">boost</span><span style="font-size: 12pt">库中的基本组件之一：</span><span style="font-size: 12pt">Boost.MPL</span><span style="font-size: 12pt">库。</span><span style="font-size: 12pt">Boost.MPL</span><span style="font-size: 12pt">以类型和编译期常量为数据，以模板特化为手段，实现了一个编译期的</span><span style="font-size: 12pt">STL</span><span style="font-size: 12pt">。你可以看到常见的</span><span style="font-size: 12pt">vector</span><span style="font-size: 12pt">，你可以看到</span><span style="font-size: 12pt">transform</span><span style="font-size: 12pt">算法，只不过算法操纵的对象和容器存放的对象不再是运行期的变量或对象，而是编译期的类型和常量。想知道模板元编程是如何用在库构建中的，可以打开一个</span><span style="font-size: 12pt">Boost</span><span style="font-size: 12pt">的子库（比如</span><span style="font-size: 12pt">Boost.Tuple</span><span style="font-size: 12pt">或</span><span style="font-size: 12pt">Boost.Variant</span><span style="font-size: 12pt">）看一看。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">然而，毕竟</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">的模板元编程是一门被发现而不是被发明的子语言。一方面，它在构建泛型库的时候极其有用。然而另一方面，由于它并非语言设计初始时考虑在内的东西，所以不仅在语法上面显得不那么</span><span style="font-size: 12pt">first-class</span><span style="font-size: 12pt">（比较笨拙）；更重要的是，由于本不是一个</span><span style="font-size: 12pt">first-class</span><span style="font-size: 12pt">的语言特性，所以</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">编译器并不知道</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">元编程的存在。这就意味着，比如对下面这样一个编译期的</span><span style="font-size: 12pt">if/else</span><span style="font-size: 12pt">设施</span><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn8" name="_ftnref8"><span style="font-size: 12pt">[8]</span></a><span style="font-size: 12pt">：</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">template&lt;bool b, class X, class Y&gt;</span></div>
<div><span style="font-size: 12pt">struct if_ {</span></div>
<div><span style="font-size: 12pt">&nbsp;typedef X type; // use X if b is true</span></div>
<div><span style="font-size: 12pt">};</span></div>
<div><span style="font-size: 12pt">template&lt;class X, class Y&gt;</span></div>
<div><span style="font-size: 12pt">struct if_&lt;false,X,Y&gt; {</span></div>
<div style="text-indent: 12pt"><span style="font-size: 12pt">typedef Y type; // use Y if b is false</span></div>
<div><span style="font-size: 12pt">};</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">typedef if_&lt;(sizeof(Foobar)&lt;40), Foo, Bar&gt;::type type;</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">编译器并没有真的去进行</span><span style="font-size: 12pt">if/else</span><span style="font-size: 12pt">的分支选择，而是按部就班毫不知情地进行着模板的特化匹配。如果遇到</span><span style="font-size: 12pt">Boost.MPL</span><span style="font-size: 12pt">这样的模板元编程非常重的库，就会严重拖累编译速度，编译器进行了一重一重的特化匹配，实例化了一个又一个的模板实例，就是为了去获取里面定义的一个</span><span style="font-size: 12pt">typedef</span><span style="font-size: 12pt">，完了之后中间所有实例化出来的模板实例类型全都被丢弃</span><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn9" name="_ftnref9"><span style="font-size: 12pt">[9]</span></a><span style="font-size: 12pt">。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">模板元编程最全面深入的介绍是</span><span style="font-size: 12pt">Boost.MPL</span><span style="font-size: 12pt">库的作者</span><span style="font-size: 12pt">David Abrahams</span><span style="font-size: 12pt">的《</span><span style="font-size: 12pt">C++ Template Metaprogramming</span><span style="font-size: 12pt">》，其中的样章（第三章）</span><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn10" name="_ftnref10"><span style="font-size: 12pt">[10]</span></a><span style="font-size: 12pt">对模板元编程作了一个非常高屋建瓴的概览</span><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn11" name="_ftnref11"><span style="font-size: 12pt">[11]</span></a><span style="font-size: 12pt">。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">关于模板元编程，需要提醒的是，它并不属于&#8220;大众技术&#8221;。日常编程中极少需要用到元编程技巧。另一方面，</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">模板里面有大量</span><span style="font-size: 12pt">ad hoc</span><span style="font-size: 12pt">的技巧，如果一头扎进去的话，很容易只见树木不见森林，所以需要提醒初学者的是，即便要学习，也要时刻保持&#8220;高度&#8221;，始终记得元编程的意义和目的，这样才不至于迷失在无穷无尽的语言细节中。</span></div>
<div>&nbsp;</div>
<div><strong><span style="font-size: 16pt">C++09</span></strong><strong><span style="font-size: 16pt">——进化</span></strong></div>
<div><span style="font-size: 12pt">泛型编程在</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">中取得了工业程度上的成功，得益于其高效性和通用性。但同时，在经过了近十年的使用之后，</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">模板，这个作为</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">实现泛型的机制的缺点也逐渐暴露出来。比如其中对于初学者最严重的一个问题就是在使用一个模板库时常常遇到无法理解的编译错误，动辄长达上</span><span style="font-size: 12pt">K</span><span style="font-size: 12pt">字节。这些编译错误很容易把一个初学者吓走。究其本质原因，为什么编译器会报出令人难以卒读的编译错误，是因为在编译器的眼里，只有类型，而没有&#8220;类型的类型&#8221;。比如说，迭代器就是一个类型的类型，</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">里面也把它称为&#8220;概念&#8221;（</span><span style="font-size: 12pt">Concept</span><span style="font-size: 12pt">）。例如，</span><span style="font-size: 12pt">std::sort</span><span style="font-size: 12pt">要求参数必须是随机访问迭代器，如果你一不小心给了它一个非随机访问的迭代器，那么编译器不是抱怨&#8220;嘿！你给我的不是随机访问迭代器&#8221;，而是抱怨找不到某某重载操作符（典型的比如</span><span style="font-size: 12pt">operator+(int)</span><span style="font-size: 12pt">）。因为在编译器眼里，没有&#8220;迭代器&#8221;这么个概念，这个概念只存在于程序员脑子里和</span><span style="font-size: 12pt">STL</span><span style="font-size: 12pt">的文档里。为了帮助编译器产出更友好的信息（当然，还有许多非常重要的其它原因</span><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftn12" name="_ftnref12"><span style="font-size: 12pt">[12]</span></a><span style="font-size: 12pt">），</span><span style="font-size: 12pt">C++09</span><span style="font-size: 12pt">将对&#8220;类型的类型&#8221;加入</span><span style="font-size: 12pt">first-class</span><span style="font-size: 12pt">的支持，其带来的众多好处会将</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">中的泛型编程带向一个新的高度：更友好、更实用、更直观。</span></div>
<div>&nbsp;</div>
<div><span style="font-size: 12pt">此外，</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">的模板元编程尚没有</span><span style="font-size: 12pt">first-class</span><span style="font-size: 12pt">的语言支持，一方面是因为其运用不像一般的模板编程这么广泛，因而没有这么紧急。另一方面，</span><span style="font-size: 12pt">C++09</span><span style="font-size: 12pt">的时间表也等不及一个成熟的提案。如果以后模板元编程被运用得越来越广泛的话，那</span><span style="font-size: 12pt">first-class</span><span style="font-size: 12pt">的语言支持是难免的。</span></div>
<div>&nbsp;</div>
<div><strong><span style="font-size: 16pt">总结</span></strong></div>
<div><span style="font-size: 12pt">本文对</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">模板，以及</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">模板所支持的泛型编程作了一个概览。着重介绍了泛型编程诞生的原因，泛型编程的过程和意义，与其它抽象手段的比较。并对</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">中的模板元编程做了一些介绍。最后介绍了</span><span style="font-size: 12pt">C++</span><span style="font-size: 12pt">模板在</span><span style="font-size: 12pt">C++09</span><span style="font-size: 12pt">中的增强。</span></div>
<div>&nbsp;</div>
<div><br clear="all" />
<hr align="left" width="33%" size="1" />
<div id="ftn1">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref1" name="_ftn1"><span>[1]</span></a> B. Stroustrup: <a href="http://www.research.att.com/%7Ebs/hopl2.pdf">A History of C++: 1979-1991</a>. Proc ACM History of Programming Languages conference (HOPL-2). March 1993.</div>
</div>
<div id="ftn2">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref2" name="_ftn2"><span>[2]</span></a> http://<span style="font-size: 10pt">en.wikipedia.org/wiki/<span>Alexander_Stepanov</span></span></div>
</div>
<div id="ftn3">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref3" name="_ftn3"><span>[3]</span></a> http://www.cs.rpi.edu/~musser</div>
</div>
<div id="ftn4">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref4" name="_ftn4"><span>[4]</span></a> 实际上，STL的区间概念被证明是一个不完美的抽象。你有没有发现，要传递一个区间给一个函数，如std::sort，你需要传递两个参数，一个是区间的开头，一个是区间的末尾。这种分离的参数传递方式被证明是不明智的，在一些场合会带来使用上不必要的麻烦。比如你想迭代一组文件，代表这组文件的区间由一个readdir_sequence函数返回，由于要分离表达一个区间，你就必须写：</div>
<div>readdir_sequence entries(".", readdir_sequence::files);</div>
<div>std::for_each(entries.begin(), entries.end(), ::remove);</div>
<div>如果你只想遍历这个区间一次的话，你也许不想声明entries这个变量，毕竟多一个名字就多一个累赘，你也许只想：</div>
<div>std::for_each(readdir_sequence(".", readdir_sequence::files), ::remove);</div>
<div>下一代C++标准（C++09）会解决这个问题（将区间这个抽象定义为一个整体）。</div>
</div>
<div id="ftn5">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref5" name="_ftn5"><span>[5]</span></a> 当然，语言并没有规定模板实例化的底层实现一定要是对每组参数类型组合实例化一个版本出来。但目前的实现，这种方案是最高效的。完全消除了抽象惩罚。另一方面，One size fit all的方案也不是不可行，但总会有间接调用。这也正说明了静态类型系统的一个典型优点：帮助编译器生成更高效的代码。</div>
</div>
<div id="ftn6">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref6" name="_ftn6"><span>[6]</span></a> http://<span style="font-size: 10pt">en.wikipedia.org/wiki/Don't_<span>repeat_yourself</span></span></div>
</div>
<div id="ftn7">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref7" name="_ftn7"><span>[7]</span></a> http://<span style="font-size: 10pt">en.wikipedia.org/wiki/<span>Duck_typing</span></span></div>
</div>
<div id="ftn8">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref8" name="_ftn8"><span>[8]</span></a> 摘自Bjarne Stroustrup的paper：Evolving a language in and for the real world: C++ 1991-2006</div>
</div>
<div id="ftn9">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref9" name="_ftn9"><span>[9]</span></a> 也正因此，D语言加入了语言直接对模板元编程的支持，比如真正工作在编译期的static if-else语句。</div>
</div>
<div id="ftn10">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref10" name="_ftn10"><span>[10]</span></a> http://www.boost-consulting.com/mplbook/</div>
</div>
<div id="ftn11">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref11" name="_ftn11"><span>[11]</span></a> 第三章的翻译见我的blog：《深度探索元函数》http://blog.csdn.net/pongba/archive/2004/09/01/90642.aspx</div>
</div>
<div id="ftn12">
<div><a title="" href="http://writeblog.csdn.net/Editor/FCKeditor/editor/fckeditor.html?InstanceName=ctl00_ctl00_cphContent_cphDoc_EntryEditor1_richTextEditor_richTextEditor&amp;Toolbar=Default#_ftnref12" name="_ftn12"><span>[12]</span></a> 由于篇幅原因，这里无法展开详述Concept对C++泛型编程的其它重要意义，有兴趣的可以参见我的一篇blog：《C++0x漫谈系列之：Concept! Concept!》。http://blog.csdn.net/pongba/archive/2007/08/04/1726031.aspx</div>
</div>
</div><img src ="http://www.blogjava.net/dongwq/aggbug/249663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2009-01-04 00:28 <a href="http://www.blogjava.net/dongwq/archive/2009/01/04/249663.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zz:vc2005经验</title><link>http://www.blogjava.net/dongwq/archive/2008/12/12/245975.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Fri, 12 Dec 2008 08:07:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2008/12/12/245975.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/245975.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2008/12/12/245975.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/245975.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/245975.html</trackback:ping><description><![CDATA[<div class="posthead">
<h2><a class="singleposttitle" id="AjaxHolder_ctl01_TitleUrl" href="http://www.cnblogs.com/sunrack/articles/588110.html">VS2005运行提示：没有找到 MSVCR80.dll</a> </h2>
添加代码：<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 alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">#pragma&nbsp;comment(linker,&nbsp;</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">manifestdependency:type</span><span style="color: #000000">=</span><span style="color: #000000">'</span><span style="color: #000000">Win32</span><span style="color: #000000">'</span><span style="color: #000000">&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">'</span><span style="color: #000000">Microsoft.VC80.CRT</span><span style="color: #000000">'</span><span style="color: #000000">&nbsp;version</span><span style="color: #000000">=</span><span style="color: #000000">'</span><span style="color: #000000">8.0.50608.0</span><span style="color: #000000">'</span><span style="color: #000000">&nbsp;processorArchitecture</span><span style="color: #000000">=</span><span style="color: #000000">'</span><span style="color: #000000">X86</span><span style="color: #000000">'</span><span style="color: #000000">&nbsp;publicKeyToken</span><span style="color: #000000">=</span><span style="color: #000000">'</span><span style="color: #000000">1fc8b3b9a1e18e3b</span><span style="color: #000000">'</span><span style="color: #000000">&nbsp;language</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">)<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span></div>
<font face="Courier New"><br />
在VS2005中，如果没有上面这行代码，运行会提示：没有找到 MSVCR80.dll</font> <br />
<br />
<br />
<a class="singleposttitle" id="AjaxHolder_ctl01_TitleUrl" href="http://www.cnblogs.com/sunrack/articles/607543.html">Visual C++ 如何：在各种字符串类型之间进行转换</a><br />
<br />
<br />
<a class="singleposttitle" id="AjaxHolder_ctl01_TitleUrl" href="http://www.cnblogs.com/sunrack/articles/599169.html">C++实现单件</a> <br />
<br />
<br />
<a class="singleposttitle" id="AjaxHolder_ctl01_TitleUrl" href="http://www.cnblogs.com/sunrack/articles/1245830.html">c++按位操作符 </a></div><img src ="http://www.blogjava.net/dongwq/aggbug/245975.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2008-12-12 16:07 <a href="http://www.blogjava.net/dongwq/archive/2008/12/12/245975.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>预编译头文件 zz</title><link>http://www.blogjava.net/dongwq/archive/2008/12/12/245966.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Fri, 12 Dec 2008 07:43:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2008/12/12/245966.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/245966.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2008/12/12/245966.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/245966.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/245966.html</trackback:ping><description><![CDATA[<div class="vcerParagraph">
<p><a class="singleposttitle" id="AjaxHolder_ctl01_TitleUrl" href="http://www.cnblogs.com/sunrack/articles/595175.html">预编译头文件</a> <br />
今天在改一个很大的程序，慢慢看，慢慢改。突然发现一个.c文件，里面什么也没有， </p>
<p>就几个头文件，我一看，我靠，这不是把简单的问题搞复杂了吗，随手删掉那个c文件。 </p>
<p>结果不能编译了，我靠： </p>
<p>fatal error C1083: Cannot open precompiled header file: \'Debug/v13_3.pch\': </p>
<p>No such file or directory </p>
<p>怎么rebuild all都不行。 </p>
<p>上网查了一下，才搞懂了： </p>
<p>－－－－－－－－－－－－－－－－总结－－－－－－ </p>
<p>如果工程很大，头文件很多，而有几个头文件又是经常要用的，那么 </p>
<p>1。把这些头文件全部写到一个头文件里面去，比如写到preh.h </p>
<p>2。写一个preh.c，里面只一句话：#include "preh.h" </p>
<p>3。对于preh.c，在project setting里面设置creat precompiled headers，对于其他 </p>
<p>.c文件，设置use precompiled header file </p>
<p>// </p>
<p>哈哈 </p>
<p>我试了一下，效果很明显，不用precompiled header，编译一次我可以去上个厕所，用 </p>
<p>precompiled header，编译的时候，我可以站起来伸个懒腰，活动活动就差不多啦 </p>
<p>－－－－－－－－－转载的文章－－－－－－－－－－ </p>
<p>预编译头的概念： </p>
<p>所谓的预编译头就是把一个工程中的那一部分代码,预先编译好放在一个文件里(通常是 </p>
<p>以.pch为扩展名的)，这个文件就称为预编译头文件这些预先编译好的代码可以是任何的 </p>
<p>C/C++代码--------甚至是inline的函数，但是必须是稳定的，在工程开发的过程中不会 </p>
<p>被经常改变。如果这些代码被修改，则需要重新编译生成预编译头文件。注意生成预编 </p>
<p>译头文件是很耗时间的。同时你得注意预编译头文件通常很大，通常有6-7M大。注意及 </p>
<p>时清理那些没有用的预编译头文件。 </p>
<p>也许你会问：现在的编译器都有Time stamp的功能，编译器在编译整个工程的时候，它 </p>
<p>只会编译那些经过修改的文件，而不会去编译那些从上次编译过，到现在没有被修改过 </p>
<p>的文件。那么为什么还要预编译头文件呢？答案在这里，我们知道编译器是以文件为单 </p>
<p>位编译的，一个文件经过修改后，会重新编译整个文件，当然在这个文件里包含的所有 </p>
<p>头文件中的东西（.eg Macro, Preprocesser ）都要重新处理一遍。VC的预编译头文件 </p>
<p>保存的正是这部分信息。以避免每次都要重新处理这些头文件。 </p>
<p>预编译头的作用： </p>
<p>根据上文介绍，预编译头文件的作用当然就是提高便宜速度了，有了它你没有必要每次 </p>
<p>都编译那些不需要经常改变的代码。编译性能当然就提高了。 </p>
<p>预编译头的使用： </p>
<p>要使用预编译头，我们必须指定一个头文件，这个头文件包含我们不会经常改变的 </p>
<p>代码和其他的头文件，然后我们用这个头文件来生成一个预编译头文件（.pch文件） </p>
<p>想必大家都知道 StdAfx.h这个文件。很多人都认为这是VC提供的一个&#8220;系统级别&#8221;的 </p>
<p>，编译器带的一个头文件。其实不是的，这个文件可以是任何名字的。我们来考察一个 </p>
<p>典型的由AppWizard生成的MFC Dialog Based　程序的预编译头文件。（因为AppWizard </p>
<p>会为我们指定好如何使用预编译头文件，默认的是StdAfx.h，这是VC起的名字）。我们 </p>
<p>会发现这个头文件里包含了以下的头文件： </p>
<p>#include &lt;afxwin.h&gt; // MFC core and standard components </p>
<p>#include &lt;afxext.h&gt; // MFC extensions </p>
<p>#include &lt;afxdisp.h&gt; // MFC Automation classes </p>
<p>#include &lt;afxdtctl.h&gt; // MFC support for Internet Explorer 4 </p>
<p>Common Controls </p>
<p>#include &lt;afxcmn.h&gt; </p>
<p>这些正是使用MFC的必须包含的头文件，当然我们不太可能在我们的工程中修改这些头文 </p>
<p>件的，所以说他们是稳定的。 </p>
<p>那么我们如何指定它来生成预编译头文件。我们知道一个头文件是不能编译的。所以我 </p>
<p>们还需要一个cpp文件来生成.pch 文件。这个文件默认的就是StdAfx.cpp。在这个文件 </p>
<p>里只有一句代码就是：#include &#8220;Stdafx.h&#8221;。原因是理所当然的，我们仅仅是要它能 </p>
<p>够编译而已?D?D?D也就是说，要的只是它的.cpp的扩展名。我们可以用/Yc编译开关来指 </p>
<p>定StdAfx.cpp来生成一个.pch文件，通过/Fp编译开关来指定生成的pch文件的名字。打 </p>
<p>开project -&gt;Setting-&gt;C/C++ 对话框。把Category指向Precompiled Header。在左边的 </p>
<p>树形视图里选择整个工程　 </p>
<p>Project Options(右下角的那个白的地方)可以看到 /Fp &#8220;debug/PCH.pch&#8221;，这就是指 </p>
<p>定生成的.pch文件的名字，默认的通常是　&lt;工程名&gt;.pch（我的示例工程名就是PCH）。 </p>
<p>然后，在左边的树形视图里选择StdAfx.cpp.//这时只能选一个cpp文件！ </p>
<p>这时原来的Project Option变成了 Source File Option（原来是工程，现在是一个文件 </p>
<p>，当然变了）。在这里我们可以看到 /Yc开关，/Yc的作用就是指定这个文件来创建一个 </p>
<p>Pch文件。/Yc后面的文件名是那个包含了稳定代码的头文件，一个工程里只能有一个文 </p>
<p>件的可以有YC开关。VC就根据这个选项把 StdAfx.cpp编译成一个Obj文件和一个PCH文件 </p>
<p>。 </p>
<p>然后我们再选择一个其它的文件来看看，//其他cpp文件 </p>
<p>在这里，Precomplier 选择了 Use ⋯⋯⋯一项，头文件是我们指定创建PCH 文件的stda </p>
<p>fx.h </p>
<p>文件。事实上，这里是使用工程里的设置，（如图1）/Yu&#8221;stdafx.h&#8221;。 </p>
<p>这样，我们就设置好了预编译头文件。也就是说，我们可以使用预编译头功能了。以 </p>
<p>下是注意事项： </p>
<p>1):如果使用了/Yu，就是说使用了预编译，我们在每个.cpp文件的最开头，我强调一遍 </p>
<p>是最开头，包含 你指定产生pch文件的.h文件（默认是stdafx.h）不然就会有问题。如 </p>
<p>果你没有包含这个文件，就告诉你Unexpected file end. 如果你不是在最开头包含的， </p>
<p>你自己试以下就知道了，绝对有很惊人的效果⋯.. </p>
<p>fatal error C1010: unexpected end of file while looking for precompiled </p>
<p>header directive </p>
<p>Generating Code... </p>
<p>2）如果你把pch文件不小心丢了，编译的时候就会产生很多的不正常的行为。根据以上 </p>
<p>的分析，你只要让编译器生成一个pch文件。也就是说把 stdafx.cpp（即指定/Yc的那个 </p>
<p>cpp文件）从新编译一遍。当然你可以傻傻的 Rebuild All。简单一点就是选择那个cpp </p>
<p>文件，按一下Ctrl + F7就可以了。不然可是很浪费时间的哦。 </p>
<p>// </p>
<p>呵呵，如果你居然耐着性子看到了这里，那么再回到帖子最开始看看我的总结吧！
<p>&nbsp;</p>
</div><img src ="http://www.blogjava.net/dongwq/aggbug/245966.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2008-12-12 15:43 <a href="http://www.blogjava.net/dongwq/archive/2008/12/12/245966.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zz VC++技术内幕（第四版）读书笔记</title><link>http://www.blogjava.net/dongwq/archive/2008/08/26/224348.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Mon, 25 Aug 2008 19:27:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2008/08/26/224348.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/224348.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2008/08/26/224348.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/224348.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/224348.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="0" width="98%" align="center" border="0">
    <tbody>
        <tr>
            <td><br />
            <strong><font color="#000066" size="3">『VC++技术内幕』（第四版）读书笔记</font></strong><br />
            <br />
            <font color="#ff0000" size="2">关键字</font><font size="2">：VC++<br />
            <font color="#ff0000">原作者姓名</font>：loose_went<br />
            <font color="#ff0000">文章原出处</font>：vczx.com <br />
            <br />
            <strong>写在前面：</strong><br />
            <br />
            　　站长所看的『VC++技术内幕』版本为--潘爱民和王国印译清华大学出版的第四版，因有时工作忙碌，不能及时更新，请大家见谅！</font> <br />
            <br />
            <table bordercolor="#799ccc" cellspacing="1" cellpadding="2" width="99%" align="center" bgcolor="#799ccc" border="0">
                <tbody>
                    <tr bgcolor="#f5f5f5">
                        <td bgcolor="#f5f5f5"><font size="2"><strong><a href="http://www.vczx.com/minute/vc_jsnm.php#1">第一天 Windows的编程模式</a></strong></font></td>
                        <td><font size="2"><strong><a href="http://www.vczx.com/minute/vc_jsnm.php#2">第二天 MFC应用程序框架</a></strong></font></td>
                    </tr>
                    <tr bgcolor="#f5f5f5">
                        <td><font size="2"><strong><a href="http://www.vczx.com/minute/vc_jsnm.php#3">第三天 消息映射和视图类</a></strong></font></td>
                        <td><font size="2"><strong><a href="http://www.vczx.com/minute/vc_jsnm.php#4">第四天 资源和编译</a></strong></font></td>
                    </tr>
                    <tr bgcolor="#f5f5f5">
                        <td><font size="2"><strong><a href="http://www.vczx.com/minute/vc_jsnm.php#5">第五天 基本事件处理</a></strong></font></td>
                        <td><font size="2"><strong><a href="http://www.vczx.com/minute/vc_jsnm.php#6">第六天 映射模式</a></strong></font></td>
                    </tr>
                    <tr bgcolor="#f5f5f5">
                        <td><font size="2"><strong><a href="http://www.vczx.com/minute/vc_jsnm.php#7">第七天 滚动视窗</a></strong></font></td>
                        <td><font size="2"><strong><a href="http://www.vczx.com/minute/vc_jsnm.php#8">第八天 社备环境类</a></strong></font></td>
                    </tr>
                    <tr bgcolor="#f5f5f5">
                        <td><font size="2"><strong><a href="http://www.vczx.com/minute/vc_jsnm.php#9">第九天 GDI对象</a></strong></font></td>
                        <td><font size="2"><strong><a href="http://www.vczx.com/minute/vc_jsnm.php#10">第十天 windows颜色映射</a></strong></font></td>
                    </tr>
                </tbody>
            </table>
            <br />
            <font size="2"><strong><a name="1"></a>第一天 Windows的编程模式</strong><br />
            <br />
            　　Windows程序中必须要有WinMain函数，因为该函数最重要的任务是创建该应用程序的主窗口。Windows程序与基于MS-DOS程序的最大差别就在于：MS-DOS程序是通过调用操作系统的功能来获得用户输入的，而Windows程序是通过操作系统发送的消息来处理用户输入的。Windows消息都是经过严格定义的，并且适用于所有的程序。<br />
            　　WINDOWS提供通用的图形设备接口（GUI），我们通过调用（GDI）函数和硬件打交道，不必理会设备环境，WINDOWS会自动将设备环境结构映射到相应的物理设备。<br />
            　　Windows程序设计中所需要的数据是存储在资源文件中的，这样，连接器就可以把编译好的二进制代码和二进制资源文件结合起来生成可执行程序。资源文件可以包括位图、图标、菜单定义、对话框设计，甚至可以包含用户自己定义的格式。<br />
            　　Windows程序允许动态的连接目标模块，并且多个应用程序可以共享同一个动态连接库。<br />
            VC++的源程序浏览器能够使我们从类或函数的角度来了解或编辑程序，而不是直接从文件入手。在看别人的源代码时如果能熟练的使用源代码浏览器将会事半功倍。源程序浏览器主要的查看状态有以下几种：<br />
            Definitions and References--选择任何函数、变量、类型、宏定义可以看到它在项目中的定义，并且在何处和什么地方用到它。<br />
            Call Graph/Caller Graph--对于所选择的函数，给出它的调用与被调用函数的图示。<br />
            Derived Class Graph/Base Class Graph--给出类层次关系的图形表示，可以看到所选择的类的派生类和基类以及成员。<br />
            File Outline--对于所选的文件，列出文件中的类、函数和数据成员，同时还显示它们定义的位置和使用位置。<br />
            　　可见Source Brower比起Class View来功能多了很多也更加好用。<br />
            　　对于本章学习loose_went建议大家在VC++6中用AppWizard生成一个空的程序，然后试着看看都有哪些文件，和他们的类层次、函数、宏、结构的定义，我就是这样干的，学编程不动手是不行的。 </font><br />
            <br />
            <table bordercolor="#799ccc" cellspacing="1" cellpadding="2" width="99%" align="center" bgcolor="#799ccc" border="0">
                <tbody>
                    <tr>
                        <td align="right" bgcolor="#f5f5f5"><img height="8" src="http://www.vczx.com/images/top.gif" width="18"  alt="" /><a href="http://www.vczx.com/minute/vc_jsnm.php#top">Top of Page</a></td>
                    </tr>
                </tbody>
            </table>
            <p><font size="2"><strong><a name="2"></a>第二天 MFC应用程序框架</strong><br />
            <br />
            ?MFC是C++的Microsoft Windows API<br />
            ?MFC产生的应用程序使用了标准化的结构。<br />
            ?MFC产生的应用程序短而运行速度快。<br />
            ?VC＋＋工具降低了编码的复杂性，这当然了，很多代码都由它代劳了，呵呵。<br />
            ?MFC库应用程序框架的功能非常丰富。<br />
            　　以上说的都是MFC库的优点，虽然说MFC有着这样多的优点，但我个人认为不能盲目的学习它，要想学好，那么您必须先掌握C++，这是毋庸置疑的。可能刚开始的时候，您觉得收获很大，也很有趣，但要进一步提高，没有C++基础是很难的。所以站长建议大家学习的时候要有先有后，这样才能学好！<br />
            应用程序框架是一种类库的超集。<br />
            　　我们现在先来看一个例子，看看MFC有多么强大！您只需加一行代码，甚至一行都不用加只需要点几下鼠标就可以创建一个windows 程序，不信，试一下：<br />
            1、打开VC++6从菜单选择NEW，给项目命名为"MyApp "。<br />
            2、选择MFC AppWizard[exe] 选项，除STEP 1选择单文档外其他STEP缺省。<br />
            3、在Class View选择CMyAppView类的OnDraw()成员函数双击会在C++编译器看到以下内容</font></p>
            <p><font size="2">void CMyAppView::OnDraw(CDC* pDC)<br />
            {<br />
            CMyAppDoc* pDoc = GetDocument();<br />
            ASSERT_VALID(pDoc);<br />
            // TODO: add draw code for native data here<br />
            }<br />
            在 // TODO: add draw code for native data here的位置增加一行代码<br />
            void CMyAppView::OnDraw(CDC* pDC)<br />
            {<br />
            CMyAppDoc* pDoc = GetDocument();<br />
            ASSERT_VALID(pDoc);<br />
            pDC-&gt;TextOut(10,10,"愿vc在线能成为您学习vc最好的朋友！"); //增加的一行<br />
            // TODO: add draw code for native data here<br />
            }<br />
            　　完了，就这么简单。编译运行。看到了吗？这个程序具备WINDOWS程序的所有特性，例如有菜单、工具条、状态栏、最大化、关闭、甚至还有关于对话框、打印预览.....全了，这就是AppWizard通过MFC动态创建的一个应用程序。从这个小例子可以看出用VC/MFC设计WINDOWS程序多么方便。</font></p>
            <p><font size="2">下面我们看看书上的例子，以便更进一步了解应用程序框架。<br />
            1、先建立一个Win32 Application的应用程序。<br />
            2、选择Project-&gt;Add to project-&gt;Files,分别创建一个名为MyApp.h和一个名为MyApp.cpp的文件。<br />
            3、添加代码：（最好照敲一下代码到编译器，别用Ctrl+C/Ctrl+V）<br />
            //***********************************************<br />
            // MyApp.h <br />
            //</font></p>
            <p><font size="2">class CMyApp:public CWinApp <br />
            {<br />
            public:<br />
            virtual BOOL InitInstance();<br />
            };</font></p>
            <p><font size="2">class CMyFrame:public CFrameWnd<br />
            {<br />
            public:<br />
            CMyFrame();<br />
            protected:<br />
            afx_msg void OnLButtonDown(UINT nFlags,CPoint point);<br />
            afx_msg void OnPaint();<br />
            DECLARE_MESSAGE_MAP()<br />
            };</font></p>
            <p><font size="2">//*****************************************************<br />
            // MyApp.cpp<br />
            //</font></p>
            <p><font size="2">#include "afxwin.h"<br />
            #include "myapp.h"<br />
            CMyApp theApp;//建立一个CMyAPP对象<br />
            BOOL CMyApp::InitInstance ()<br />
            {<br />
            m_pMainWnd=new CMyFrame();<br />
            m_pMainWnd-&gt;ShowWindow (m_nCmdShow);<br />
            m_pMainWnd-&gt;UpdateWindow ();<br />
            return TRUE;<br />
            }</font></p>
            <p><font size="2">BEGIN_MESSAGE_MAP(CMyFrame,CFrameWnd)<br />
            ON_WM_LBUTTONDOWN()<br />
            ON_WM_PAINT()<br />
            END_MESSAGE_MAP()</font></p>
            <p><font size="2">CMyFrame::CMyFrame(){<br />
            Create(NULL,"MYAPP Application");<br />
            }<br />
            void CMyFrame::OnLButtonDown (UINT nFlags,CPoint point)<br />
            {<br />
            TRACE("Entering CMyFrame::OnLButtonDown - %lx,%d,%d\n",<br />
            (long)nFlags,point.x ,point.y);<br />
            }</font></p>
            <p><font size="2">void CMyFrame::OnPaint ()<br />
            {<br />
            CPaintDC dc(this);<br />
            dc.TextOut (0,0,"Hello World!");<br />
            }</font></p>
            <p><font size="2">4、编译运行，报错。为什么呢？原来还没有添加MFC的支持，在Project Setting选项General属性页选择"Use MFC in a Static Library"<br />
            5、再按Ctrl+F5，怎么样，简单吧？<br />
            让我们看看这个程序中的一些元素。<br />
            ①WinMain函数：Windows总是要求每个应用程序都要有WinMain函数的，您之所以看不见，是因为它已经隐藏在应用程序框架内部了。<br />
            ②CMyApp类：CMyApp类的对象代表一个应用程序，CWinApp基类决定它的大部分行为。<br />
            ③应用程序的启动：当开始运行应用程序时WINDOWS会调用WinMain函数，WinMain会查找该应用程序的全局对象theApp。<br />
            ④CMyApp::InitInstance成员函数：发现theApp后自动调用重载的虚函数InitInstance来完成主窗口的构造和显示工作。<br />
            ⑤CWinApp::Run成员函数：WinMain在调用InitInstance之后紧接着调用Run函数，它被隐藏在基类中负责传递应用程序的消息给相映的窗口。<br />
            ⑥CMyFrame类：此类的对象代表着应用程序的主窗口。它的构造函数调用基类CFrameWnd的Create函数创建具体的窗口结构。<br />
            ⑦CMyFrame::OnLButtonDown函数：演示消息处理机制，当鼠标坐键被按下这一事件被映射到CMyFrame的OnLButtonDown函数上，如果你选择F5进行编译运行的话可以在调试窗口看到TRACE宏显示的类似下面的信息<br />
            Entering CMyFrame::OnLButtonDown - 1,309,119<br />
            Entering CMyFrame::OnLButtonDown - 1,408,221<br />
            ⑧CMyFrame::OnPaint函数：应用程序每次重新绘制窗口都需要调用此函数，将显示"Hello World!"放在这里是因为每次窗口发生变化时保证"Hello World!"被显示，你可以试着将语句：<br />
            CPaintDC dc(this);<br />
            dc.TextOut (0,0,"Hello World!");<br />
            写在别出，例如写在<br />
            void CMyFrame::OnLButtonDown (UINT nFlags,CPoint point)<br />
            {<br />
            TRACE("Entering CMyFrame::OnLButtonDown - %lx,%d,%d\n",<br />
            (long)nFlags,point.x ,point.y);<br />
            CPaintDC dc(this);<br />
            dc.TextOut (0,0,"Hello World!");<br />
            }<br />
            运行后当点击左键时显示"Hello World!"，但当窗口最小化再最大化时"Hello World!"不见了。<br />
            ⑧关闭应用程序：用户关闭应用程序时会有一系列事件发生。首先CMyFrame对象被删除，然后退出Run，进而退出WinMain，最后删除CMyApp对象。<br />
            　　通过上面的示例我们看见程序的大部分功能包含在基类CWinApp和CFrameWnd中，我们只写了很少的函数，便可以完成很复杂的功能。所以应用程序框架不仅仅是一种类库，它还定义了应用程序的结构，除了基类外还包括WinMain函数，以及用来支持消息处理、诊断、DLL、等都包含在应用程序框架中。 </font><br />
            <br />
            <table bordercolor="#799ccc" cellspacing="1" cellpadding="2" width="99%" align="center" bgcolor="#799ccc" border="0">
                <tbody>
                    <tr>
                        <td align="right" bgcolor="#f5f5f5"><img height="8" src="http://www.vczx.com/images/top.gif" width="18"  alt="" /><a href="http://www.vczx.com/minute/vc_jsnm.php#top">Top of Page</a></td>
                    </tr>
                </tbody>
            </table>
            <p><font size="2"><strong><a name="3"></a>第三天 消息映射和视图类</strong><br />
            <br />
            　　MFC库应用程序框架没有采用虚函数来处理windows消息，而是通过宏将消息映射到派生类相应的成员函数上。文档－视图结构是应用程序框架的核心，它把数据从用户对数据的观察中分离出来，这样做最大的好处就是同一个数据可以对应多个视图。比如同一个股票报价数据，既可以有报表观察窗口，也可以有图形观察窗口，明白了否？<br />
            　　视图简单来说就是一个普通的窗口，对于程序员来说就是一个从MFC库中Cview类派生出来的类的一个对象。视图类分为两个源文件模块：头文件（H）和源代码文件（CPP）。<br />
            用Appwizard创建一个SDI应用程序，产生了如下文件（假设工程名为Exc01）：<br />
            Exc01.dsp 项目文件，Visual Studio用它来创建应用程序<br />
            Exc01.dsw 工作空间文件，包含一个项目Exc01.dsp<br />
            Exc01.rc ASCII码资源描述文件<br />
            Exc01View.cpp 包含CExc01View类成员函数和视图类文件<br />
            Exc01View.h 包含CExc01View类定义的视图类头文件<br />
            Exc01.opt 二进制文件，告诉Developer Studio本项目的哪些文件是打开的，又是如何排序的<br />
            Readme.txt 用来解释所产生的所有文件的文本文件<br />
            Resource.h 包含#define常量定义的头文件<br />
            　　从Exc01View.cpp和Exc01View.h的代码中可以看出，这两个文件已经完全定义了CExc01View类，而该类正是此应用程序的核心。CExc01View类的对象与应用程序的视窗相关联，应用程序的所有"动作"都会在这个视窗中显示出来。<br />
            　　CExc01View类的两个最重要的基类是CWnd和CView类。CWnd类提供了CExc01View的窗口属性，而CView类则提供了它和应用程序框架的其它部分之间的联系，特别是和文档以及框架窗口之间的联系。这一点一定要记住。<br />
            　　下面我们来看一下如何在视窗内绘图。最重要的一个函数是OnDraw()函数，它是一个虚函数，每次窗口被重画时，应用程序都要先调用这个函数。注意：尽管可以随时对窗口绘制，但最好还是等变化内容积累到一定程度后再教给OnDraw()函数处理，这样效率会高一些。<br />
            在MFC中，设备环境是由C++的CDC类对象来表示的，该对象被作为参数传给Ondraw()函数，这样，我们就可以调用CDC的许多成员函数来完成各种绘制了。<br />
            找到OnDraw()函数，用以下语句替换函数原来的内容：<br />
            pDC-&gt;TextOut( 0, 0, "Hello World!" );<br />
            pDC-&gt;Ellipse(CRect(0,20,100,120));<br />
            再编译运行，看到了什么？<br />
            　　TextOut和Ellipse都是设备环境类CDC的成员函数，MFC库提供了一个用来表示windows矩形的类CRect，在这里CRect的一个临时对象被作为参数传递给 了Ellipse函数，当外接矩形的宽和高相等时，Ellipse函数就画出个圆。 </font><br />
            <br />
            <table bordercolor="#799ccc" cellspacing="1" cellpadding="2" width="99%" align="center" bgcolor="#799ccc" border="0">
                <tbody>
                    <tr>
                        <td align="right" bgcolor="#f5f5f5"><img height="8" src="http://www.vczx.com/images/top.gif" width="18"  alt="" /><a href="http://www.vczx.com/minute/vc_jsnm.php#top">Top of Page</a></td>
                    </tr>
                </tbody>
            </table>
            <p><font size="2"><strong><a name="4"></a>第四天 资源和编译</strong><br />
            <br />
            　　资源文件（就是以应用程序名和扩展名是.rc的文件）很大程度上决定了应用程序的用户界面。在VC++中资源文件包括以下内容： <br />
            Accelerator //模拟菜单和工具栏选择的键盘定义 <br />
            Dialog //对话框的布局及内容 <br />
            Icon //图标有两种一种是16X16一种是32X32。 <br />
            Menu //应用程序的主菜单及所属的弹出式菜单 <br />
            String table //一些字符串，不属于C++源代码部分 <br />
            Toolbar //工具条。 <br />
            Version //程序的描述、版本号、支持语言信息。 <br />
            　　除了以上信息，.rc文件还包含了以下语句： #include "afxres.h" #include "afxres.rc" 它们的作用是把适合于所有应用程序的一些通用MFC库资源包含进来，其中包括字符串、图形按钮以及打印所需的一些元素。 <br />
            　　关于资源编辑器的使用就不多说了，因为它的操作很简单，需要注意的是虽然resource.h是一个ASCII码文件可以用文本编辑器进行编辑，但如果使用文本编辑器进行编辑的话，下次再使用资源编辑器时所做的修改有可能丢失，所以我们应该在尽量在资源编辑器中编辑应用程序的资源，新增的资源内容回自动的添加在我们的程序相应位置，例如resource.h而不用我们操心。 <br />
            　　编译在VC++中有两种模式，一种是Release Build另一种是Debug Build。它们之间的区别在于，Release Build不对源代码进行调试，不考虑MFC的诊断宏，使用的是MFC Release库，编译十对应用程序的速度进行优化，而Debug Build则正好相反，它允许对源代码进行调试，可以定义和使用MFC的诊断宏，采用MFC Debug库，对速度没有优化。所以我们应该在Debug模式下开发应用程序，然后在Release模式下发布应用程序。在我们的工程文件夹下会有一个Debug文件夹和一个Release文件夹分别存放输出文件和中间文件。 <br />
            　　诊断宏是我们编译程序时检测程序状态的有利工具，例如上两篇用到的TRACE宏，可以在Debug窗口获得你需要的诊断信息，而不用设置对话框之类的方法，在发布时Release会自动滤掉此信息。 <br />
            　　为了更好的管理项目，最好理解系统是如何处理预编译头文件的。VC＋＋有两个预编译系统：自动的和手工的。这一部分笔者就不多说了，建议读者好好看看。 </font><br />
            <br />
            <table bordercolor="#799ccc" cellspacing="1" cellpadding="2" width="99%" align="center" bgcolor="#799ccc" border="0">
                <tbody>
                    <tr>
                        <td align="right" bgcolor="#f5f5f5"><img height="8" src="http://www.vczx.com/images/top.gif" width="18"  alt="" /><a href="http://www.vczx.com/minute/vc_jsnm.php#top">Top of Page</a></td>
                    </tr>
                </tbody>
            </table>
            <br />
            <font size="2"><strong><a name="5"></a>第五天 基本事件处理</strong><br />
            <br />
            　　用户在视窗中的任何一个操作，都会引起Windows自动发送一个消息给该视窗。我们以一个例子来说明：比如我们在视窗中按下鼠标左键，Windows就会发送ON_LBUTTONDOWN消息给视窗，那么在视窗类中就必须包含下面的成员函数：<br />
            Void CmyView::OnLButtonDown(UINT nFlags, Cpoint point)<br />
            {<br />
            //event processing code here<br />
            }<br />
            　　在类头文件中也要包含相应的函数声明：<br />
            afx_msg void OnLButtonDown(UINT nFlags, Cpoint point)<br />
            在代码文件中还要有一个消息映射宏，用于将OnLButtonDown函数和应用程序框架联系在一起：<br />
            BEGIN_MESSAGE_MAP(CmyView, CView)<br />
            ON_WM_LBUTTONDOWN()<br />
            // other message map entries<br />
            END_MESSAGE_MAP<br />
            　　最后，在类库头文件中包含如下语句：<br />
            DECLARE_MESSAGE_MAP()<br />
            　　以上这些步骤，我们都可以借助于ClassWizard来完成。这就是消息映射的过程。
            <p>　　MFC库对140种windows消息直接提供了消息控制函数，并且我们还可以自己定义自己的消息，下面列出的五种消息是我们应该特别注意的（MSDN上有更详细的内容）。<br />
            <strong>WM_CREATE</strong><br />
            　　该消息是Windows发给视图的第一个消息。当应用程序框架调用create函数时该消息便会被发送，此时窗口还未创建完成，不可见，因此在消息控制函数OnCreate内不能调用那些依赖窗口处于完全激活状态的Windows函数。如果需要可以在重载的OnInitialUpdate函数内调用。不过注意在SDI应用程序OnInitialUpdate函数可能被多次调用。<br />
            <strong>WM_CLOSE</strong><br />
            　　当用户关闭窗口时，系统会发送WM_CLOSE消息。如果派生类重新定义了OnClose函数，就可以完全控制关闭过程，可以将提醒用户存盘之类的工作放在这里完成。我们可以通过重载CDocument::SaveModified虚函数达到相同的目的。<br />
            <strong>WM_QUERYENDSESSION</strong><br />
            　　从字面的意思看就可以看出，当用户退出Windows时，或者调用了ExitWindows 函数时。Windows会发送WM_QUERYENDSESSION消息给所有的正在运行的应用程序，由OnQueryEndSession消息映射函数对消息进行处理。在它之后应该是WM_ENDSESSION 消息。<br />
            <strong>WM_DESTROY</strong><br />
            　　在Windows发送WM_CLOSE消息后，紧接着会发送WM_DESTROY消息，虽然窗口已经Close但实际上并没有完全清除，在任务管理器中还可以看见应用程序的进程（我想很多木马或病毒都是无窗口的程序，它们的做法是生成了已经活动状态的窗口但不显示出来），利用这个消息控制函数便可以对依赖于当前窗口存在的东西做清除工作，不过一定要注意，应该调用基类的OnDestroy函数，而不能在用户自己的视图的OnDestroy函数中终止窗口的析构过程，终止析构过程应该在OnClose函数中。<br />
            <strong>WM_NCDESTROY</strong><br />
            　　当窗口被取消所发送的最后一个消息就是这个消息。我们可以在OnNcDestroy函数中做一些不依赖该窗口是否处于活动状态的最后的处理工作，（我实在想不出还需要做什么？那位朋友能给个例子），注意一定要调用基类中的OnNcDestroy函数。</p>
            <p>　　MFC库中非静态数据成员的名字以m_为前缀。<br />
            　　一个窗口具有一个矩形的"客户区域"，CWnd中的GetClient成员函数可以给出客户区域的大小，只允许在客户区域内绘图。<br />
            　　标准的windows应用程序会首先登记一个窗口类，这不同于C++类，同时在处理过程中，还需要对每个类指定窗口过程。每次应用程序调用CreateWindow建立一个窗口时，都要指定一个窗口类作为参数，这样就把新建立的窗口和窗口过程函数连接起来了，每次windows给窗口发送消息的时候，这个函数就会被调用，以检查用参数传进来的消息码。<br />
            </p>
            </font>
            <table bordercolor="#799ccc" cellspacing="1" cellpadding="2" width="99%" align="center" bgcolor="#799ccc" border="0">
                <tbody>
                    <tr>
                        <td align="right" bgcolor="#f5f5f5"><img height="8" src="http://www.vczx.com/images/top.gif" width="18"  alt="" /><a href="http://www.vczx.com/minute/vc_jsnm.php#top">Top of Page</a></td>
                    </tr>
                </tbody>
            </table>
            <br />
            <font size="2"><strong><a name="6"></a>第六天 映射模式</strong><br />
            <br />
            　　所谓映射模式，说白了就是坐标系。在默认情况下，Windows所绘图像单位为像素，这是因为设备环境用了默认的映射模式MM_TEXT，所以如下语句所绘图形为长和宽都为200像素的方块： 　　pDC-&gt;Rectangle(CRect(0,0,200,200)); <br />
            　　那么我们要绘制一个长和宽都是4厘米的方块该怎么做呢？这就必须改变设备环境的默认映射模式为MM_HIMETRIC，它的图像单位为1/100mm，而不是像素了。它的y轴方向和MM_TEXT的相反，它的向下为递减的，因此用如下语句就可以绘出4&#215;4cm的方块了： <br />
            pDC-&gt;SetMapMode( MM_HIMETRIC); <br />
            pDC-&gt;Rectangle(CRect(0,0,4000,-4000)); <br />
            　　下面我们再来了解一下Windows都提供了哪些映射模式。<br />
            1、MM_TEXT映射模式 <br />
            　　这种模式下，绘图单位为像素，x轴向右递增，y轴向下递增，我们可以用CDC的SetViewPortOrg和SetWindowOrg函数来改变坐标原点的位置，下面的代码就是把坐标原点设在了（100,100）处，画了一个200&#215;200像素的方块，此时逻辑坐标点（100,100）被映射到了设备坐标点（0,0）处，下一篇的滚动窗口使用的就是这种变换。 <br />
            Void CmyView::OnDraw( CDC *pDC ){ <br />
            pDC-&gt;SetMapMode(MM_TEXT); <br />
            pDC-&gt;SetWindowOrg(Cpoint(100,100)); <br />
            pDC-&gt;Rectangle(CRect(100,100,200,200)); <br />
            } <br />
            2、固定比例映射模式 <br />
            　　Windows提供了一组非常重要的固定比例影视模式，所有这种模式都遵循x轴向右递减，y轴向下递减的规则，而且我们无法将其改变。固定比例模式之间唯一的差别就在于实际的比例因子。下表列出了影视模式和比例因子的对应情况： <br />
            <br />
            </font>
            <table bordercolor="#799ccc" cellspacing="1" cellpadding="2" width="70%" align="center" bgcolor="#799ccc" border="0">
                <tbody>
                    <tr bgcolor="#ffffff">
                        <td><font size="2">映射模式</font></td>
                        <td><font size="2">逻辑单位</font></td>
                    </tr>
                    <tr bgcolor="#ffffff">
                        <td><font size="2">MM_LOENGLISH</font></td>
                        <td><font size="2">0.01英寸</font></td>
                    </tr>
                    <tr bgcolor="#ffffff">
                        <td><font size="2">MM_HIENGLISH</font></td>
                        <td><font size="2">0.001英寸</font></td>
                    </tr>
                    <tr bgcolor="#ffffff">
                        <td><font size="2">MM_LOMETRIC</font></td>
                        <td><font size="2">0.1mm</font></td>
                    </tr>
                    <tr bgcolor="#ffffff">
                        <td><font size="2">MM_HIMETRIC</font></td>
                        <td><font size="2">0.01mm</font></td>
                    </tr>
                    <tr bgcolor="#ffffff">
                        <td><font size="2">MM_TWIPS</font></td>
                        <td><font size="2">1/1440英寸</font></td>
                    </tr>
                </tbody>
            </table>
            <font size="2"><br />
            　　MM_TWIPS模式常用于打印机。 <br />
            3、可变比例映射模式 <br />
            　　Windows还提供了两种映射模式MM_ISOTROPIC和MM_ANISOTROPIC，这两种模式允许我们修改比例因子和坐标原点。在MM_ISOTROPIC模式下，纵横比总是1:1，就像改变图像时锁定比例一样，而MM_ANISOTROPIC模式则可以独立的改变x和y的比例因子，即圆可以变成扁圆。 <br />
            　　以上就是常见的映射模式，笔者建议：我们没必要死记住这些模式，只是到用的时候会用就可以了，哪怕查查MSDN，这个东东真好！ <br />
            　　在设置了映射模式和相应参数之后，我们可以用CDC的LPtoDP函数将逻辑坐标转换为设备坐标，用DptoLP函数将设备坐标转换为逻辑坐标。那么我们什么时候用什么样的坐标呢？有一些规则如下： <br />
            ① 可以认为CDC的所有成员函数都以逻辑坐标为参数 <br />
            ② 可以认为CWnd的所有成员函数都以设备坐标为参数 <br />
            ③ 所有选中测试都应该选用设备坐标，区域的定义应采用设备坐标，某些像CRect::PtInRect之类的函数只有采用设备坐标才能有正确的结果 <br />
            ④ 将一些长期使用的值用逻辑坐标来保存，如果用设备坐标，那么只要用户对窗口进行一下滚动，坐标就不再有效了 <br />
            　　一般情况下，我们在CView的虚函数OnPrepareDC中设置映射模式，应用程序框架在调用OnDraw函数之前调用这个虚函数。 </font><br />
            <br />
            <table bordercolor="#799ccc" cellspacing="1" cellpadding="2" width="99%" align="center" bgcolor="#799ccc" border="0">
                <tbody>
                    <tr>
                        <td align="right" bgcolor="#f5f5f5"><img height="8" src="http://www.vczx.com/images/top.gif" width="18"  alt="" /><a href="http://www.vczx.com/minute/vc_jsnm.php#top">Top of Page</a></td>
                    </tr>
                </tbody>
            </table>
            <br />
            <font size="2"><strong><a name="7"></a>第七天 滚动视窗</strong><br />
            <br />
            　　CView类并不直接支持窗口滚动，如要实现窗口滚动，就要用到CView的派生类CScrollView类，CScrollView的成员函数能够处理滚动条并发送给视图WM_HSCROLL和WM_VSCROLL消息，从而实现窗口的滚动。<br />
            　　在文档－视图结构中，视图窗口建立以后，框架最先调用OnInitialUpdate虚函数，在框架第一次调用OnDraw函数前也是先调用OnInitialUpdate函数，因此在OnInitialUpdate函数中设置滚动视窗的初始化最合适。<br />
            　　下面我们就来创建一个滚动示例程序a：<br />
            　　1、 用AppWizard创建一个文档－视图程序a，注意在第六步时设置CAView的基类应为CScrollView而不是CView。<br />
            　　2、 在CAView中加入数据成员m_rectEllipse和m_nColor。<br />
            　　3、 修改OnInitialUpdate函数如下：<br />
            void CAView::OnInitialUpdate()<br />
            {<br />
            CScrollView::OnInitialUpdate();
            <p>CSize sizeTotal( 20000, 30000 ); //逻辑窗口大小20&#215;30cm<br />
            CSize sizePage( sizeTotal.cx/2, sizeTotal.cy/2 ); <br />
            CSize sizeLine( sizeTotal.cx/50, sizeTotal.cy/50 );<br />
            SetScrollSizes( MM_HIMETRIC, sizeTotal, sizePage, sizeLine );</p>
            <p>}<br />
            4、 用ClassWizard产生对消息WM_KEYDOW控制的OnKeyDown函数，并编辑代码如下：<br />
            void CAView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) <br />
            {<br />
            // TODO: Add your message handler code here and/or call default<br />
            <br />
            switch( cChar ){<br />
            case VK_HOME:<br />
            OnVScroll( SB_TOP, 0, NULL );<br />
            OnHScroll( SB_LEFT, 0, NULL );<br />
            break;<br />
            case VK_END:<br />
            OnVScroll( SB_BOTTOM, 0, NULL );<br />
            OnHScroll( SB_RIGHT, 0, NULL );<br />
            break;<br />
            case VK_UP:<br />
            OnVScroll( SB_LINEUP, 0, NULL );<br />
            break;<br />
            case VK_DOWN:<br />
            OnVScroll( SB_LINEDOWN, 0, NULL );<br />
            break;<br />
            case VK_PRIOR:<br />
            OnVScroll( SB_PAGEUP, 0, NULL );<br />
            break;<br />
            case VK_NEXT:<br />
            OnVScroll( SB_PAGEDOWN, 0, NULL );<br />
            break;<br />
            case VK_LEFT:<br />
            OnHScroll( SB_LINELEFT, 0, NULL );<br />
            break;<br />
            case VK_RIGHT( SB_LINERIGHT, 0, NULL );<br />
            break;<br />
            default:<br />
            break;<br />
            }<br />
            ｝<br />
            5、 编辑构造函数和OnDraw函数如下：<br />
            CAView::CAView():m_rectEllipse( 0, 0, 4000, -4000 )<br />
            {<br />
            // TODO: add construction code here<br />
            m_nColor = GRAY_BRUSH;<br />
            }<br />
            &#8230;<br />
            void CAView::OnDraw(CDC* pDC)<br />
            {<br />
            pDC-&gt;SelectStockObject( m_nColor );<br />
            pDC-&gt;Ellipse( m_rectEllipse );<br />
            }<br />
            6、 映射WM_LBUTTONDOWN消息并编辑消息处理函数OnLButtonDown如下：<br />
            void CAView::OnLButtonDown(UINT nFlags, CPoint point) <br />
            {<br />
            // TODO: Add your message handler code here and/or call default<br />
            <br />
            CClientDC dc( this );<br />
            OnPrepareDC( &amp;dc );<br />
            CRect rectDevice = m_rectEllipse;<br />
            dc.LPtoDP( rectDevice );<br />
            if( rectDevice.PtInRect( point ) ){<br />
            if( m_nColor = GRAY_BRUSH )<br />
            m_nColor = WHITE_BRUSH;<br />
            else<br />
            m_nColor = GRAY_BRUSH;<br />
            }<br />
            InvalidateRect( rectDevice );<br />
            }<br />
            编译并运行看看结果吧。<br />
            另外，我们要特别注意下面五种比较特殊的windows消息：<br />
            1、 WM_CREATE消息<br />
            该消息是windows发给视图的第一个消息，由于应用程序框架调用Create函数时该消息就会被发送，而此时窗口创建还未完成，因此在Create函数内不能调用那些依赖于窗口处于完全激活状态的windows函数。不过对于SDI应用程序，在视图生存期间，OnInitialUpdate函数可以被调用多次。<br />
            2、 WM_CLOSE消息<br />
            当用户从系统菜单中关闭窗口或者父窗口被关闭时，windows会发送WM_CLOSE消息。<br />
            3、 WM_QUERYENDSESSION消息<br />
            当用户退出windows时，windows就会发送WM_QUERYENDSESSION消息给正在运行的程序，处理这个消息的映射函数为OnQueryEndSession。<br />
            4、 WM_DESTROY消息<br />
            Windows在发送完WM_CLOSE消息后，紧接着就发送WM_DESTROY消息，消息映射函数为OnDestroy。当程序接收到该消息时，它将假定此时视窗已经消失，但仍处于活动状态。利用这个消息控制函数，就可以对依赖于当前窗口的所有东西作清除工作，不过一定要记住，应该用基类的OnDestroy而不能在自己视图中的OnDestroy中"终止"窗口的析构过程，终止析构的处理应该在OnClose函数中。<br />
            5、 WM_NCDESTROY消息<br />
            当窗口被取消时发送的最后一个消息就是这个消息，由于此时所有的窗口都被关闭，所以我们可以在OnNcDestroy函数中做一些不依赖于窗口是否处于激活状态的最后处理工作，不过一定要调用基类的OnNcDestroy函数。不要在OnNcDestroy中取消动态申请的窗口对象，这一工作是由CWnd的一个特殊虚函数PostNcDestroy来完成的，它是由基类的OnNcDestroy来调用的。何时取消窗口对象最为合适呢，去看MFC的联机文档吧！<br />
            </p>
            </font>
            <table bordercolor="#799ccc" cellspacing="1" cellpadding="2" width="99%" align="center" bgcolor="#799ccc" border="0">
                <tbody>
                    <tr>
                        <td align="right" bgcolor="#f5f5f5"><img height="8" src="http://www.vczx.com/images/top.gif" width="18"  alt="" /><a href="http://www.vczx.com/minute/vc_jsnm.php#top">Top of Page</a></td>
                    </tr>
                </tbody>
            </table>
            <br />
            <strong><a name="8"></a>第八天 设备环境类</strong><br />
            <br />
            <p><font size="2">　　任何程序在画图时都需要调用图形设备接口（ GDI ）函数， GDI 包含了一些绘制点、线、矩形、椭圆、位图以及文本的函数。 Windows 的设备环境是 GDI 的关键元素，它代表了物理设备，每一个 C++ 设备环境对象都有与之对应的 Windows 设备环境，并通过一个 32 位的 HDC 句柄来标识。 </font></p>
            <p><font size="2">　　MFC 中的基类 CDC 包含了绘图所需要的所有成员函数，并且除了 CMetaFileDC 类外，所有的派生类都只有构造函数和析构函数不同。对于显示器来说，常用的派生类有 CClientDC 和 CWindowDC 。 </font></p>
            <p><font size="2">　　显示设备环境的类 CClientDC 和 CWindowDC ， CClientDC 类绘图只局限于客户区域内，即不包含边框、菜单栏和标题栏，而 CWindowDC 类可以。简单来说，如果创建 CclientDC 对象，点（ 0,0 ）指客户区域的左上角，如果创建的是 CWindowDC 对象，则点（ 0,0 ）指整个屏幕的左上角。 </font></p>
            <p><font size="2">　　在创建 CDC 对象的时候，不要忘记在合适的时候将它删除，不然程序在退出之前有小部分内存就会丢失。要保证设备环境对象能够被适时的删除，可以有两种方法： </font></p>
            <p><font size="2">一种是在堆栈中构造对象，比如在 OnLButtonDown 函数中，它的析构函数在函数返回时自动被调用。 </font></p>
            <p><font size="2">void CMyView::OnLButtonDown(UINT nFlags,CPoint point){ </font></p>
            <p><font size="2">CRect rect; </font></p>
            <p><font size="2">CClientDC dc(this); //constructs dc on the stack </font></p>
            <p><font size="2">&#8230; </font></p>
            <p><font size="2">} //dc automatically destroyed </font></p>
            <p><font size="2">另一种是通过调用 CWnd 的成员函数 GetDC 来获得设备环境指针，但此时必须要调用 RleaseDC 来释放设备环境。 </font></p>
            <p><font size="2">void CMyView::OnLButtonDown(UINT nFlags,CPoint point){ </font></p>
            <p><font size="2">CRect rect; </font></p>
            <p><font size="2">CDC *pDC=GetDC(); </font></p>
            <p><font size="2">pDC-&gt;GetClipBox(rect); </font></p>
            <p><font size="2">ReleaseDC(pDC); // 不要忘了这句 </font></p>
            <p><font size="2">} </font></p>
            <p><font size="2">注意：千万不要删除作为参数以指针形式传递给 OnDraw 函数的 CDC 对象，应用程序框架会自动控制它的删除。 </font></p>
            <p><font size="2">在绘图时我们离不开设备环境，那么在绘图时我们就要依赖于设备环境的当前状态，这种状态包括： </font></p>
            <p><font size="2">&#8226;&nbsp; 被选中的 GDI 绘图对象，如笔、刷子和字体等 </font></p>
            <p><font size="2">&#8226;&nbsp; 绘图时的缩放尺寸的映射模式 </font></p>
            <p><font size="2">&#8226;&nbsp; 其他各种细节，如文本的对齐方式，多边形的填充状态 </font></p>
            <p><font size="2">　　创建设备环境对象时，通常会有些默认的特性，而其他特性都是通过 CDC 类的成员函数来设定的，可以通过重载 SelectObject 函数来将 GDI 对象选进设备环境中。 </font></p>
            <font size="2">　　如果我们要重新编写 OnPaint 函数，就需要使用 CPaintDC 类，这个类是比较特殊的，它的构造函数和析构函数所完成的工作都是针对显示用的，当我们一旦获得一个 CDC 指针，就可以把它当成任何设备环境指针来用。</font> <br />
            <br />
            <table bordercolor="#799ccc" cellspacing="1" cellpadding="2" width="99%" align="center" bgcolor="#799ccc" border="0">
                <tbody>
                    <tr>
                        <td align="right" bgcolor="#f5f5f5"><img height="8" src="http://www.vczx.com/images/top.gif" width="18"  alt="" /><a href="http://www.vczx.com/minute/vc_jsnm.php#top">Top of Page</a></td>
                    </tr>
                </tbody>
            </table>
            <br />
            <font size="2"><strong><a name="9"></a>第九天 GDI对象</strong></font><br />
            <br />
            <p>　　<font size="2">所有 GDI 对象类都是由抽象基类 CGdiObject 派生出来的。下面是 GDI 派生类列表： </font></p>
            <p><font size="2">　　CBitmap － 位图是一种位矩阵，每一个显示像素都对应一个或多个位，我们可以用位图来表示图像，也可以用它来创建刷子。 </font></p>
            <p><font size="2">CBrush － 刷子定义了一种位图形式的像素，用它可以对区域内部填充颜色。 </font></p>
            <p><font size="2">CFont － 字体是一种具有某种风格和尺寸的所有字符的集合。 </font></p>
            <p><font size="2">CPalette － 调色板是一种颜色映射接口。 </font></p>
            <p><font size="2">CPen － 笔是一种画线和有形边框的工具，可以指定画线的宽度，以及画虚线，实线等。 </font></p>
            <p><font size="2">CRgn － 区域是一种范围，可以用它来填充、裁剪以及鼠标点中测试。 </font></p>
            <p><font size="2">　　我们只需要构造 CGdiObject 类的派生类对象，而无需构造它的对象，有些 GDI 派生类允许构造函数一步完成创建对象的任务，如 CPen 和 CBrush 。而有些派生类的对象要两步，如 CFont 和 CRgn ，首先要调用默认的构造函数，然后还要调用相应的创建函数，如 CreateFont 、 CreatePolygonRgn 等。 </font></p>
            <p><font size="2">　　CGdiObject 类有一个虚析构函数，如果构造了一个它的派生类的对象，则在程序退出之前要将其删除，为了删除它，要先将其从设备环境中分离出来。那么如何分离呢？其实， CDC 类的 SelectObject 成员函数在将 GDI 对象选进设备环境的同时，它已经从设备环境中分离出来了，但在未选中新的对象前，还不能将旧的对象分离。所以在选进自己的 GDI 对象时，将原来的 GDI 对象也保存起来，任务完成后，再将其恢复，这样就可以将自己的 GDI 对象分离并删除了。下面看一个例子： </font></p>
            <p><font size="2">void CMyView::OnDraw( CDC *pDC ){ </font></p>
            <p><font size="2">CPen newPen( PS_DASHDOTDOT, 2, (COLORREF)0); //black 2 pixels wide </font></p>
            <p><font size="2">CPen * pOldPen = pDC-&gt;SelectObject( &amp;newPen ); </font></p>
            <p><font size="2">pDC-&gt;MoveTo( 10, 10 ); </font></p>
            <p><font size="2">pDC-&gt;LineTo( 110, 10 ); </font></p>
            <p><font size="2">pDC-&gt;SelectObject( pOldPen ); //newPen 被分离 </font></p>
            <p><font size="2">} //newPen 在函数退出时自动删除 </font></p>
            <p><font size="2">　　对于一些库存的 GDI 对象，由于它们是 windows 系统的一部分，因此我没有必要删除它们。 MFC 库函数 SelectStockObject 可以将一个库存对象选进设备环境中，并返回原先被选中对象的指针，同时使该对象被分离。在上例中，我们就可以用库存对象代替&#8220;旧&#8221;对象： </font></p>
            <p><font size="2">void CMyView::OnDraw( CDC *pDC ){ </font></p>
            <p><font size="2">CPen newPen( PS_DASHDOTDOT, 2, (COLORREF)0); //black 2 pixels wide </font></p>
            <p><font size="2">pDC-&gt;MoveTo( 10, 10 ); </font></p>
            <p><font size="2">pDC-&gt;LineTo( 110, 10 ); </font></p>
            <p><font size="2">pDC-&gt;SelectStockObject( BLACK_PEN ); //newPen 被分离 </font></p>
            <p><font size="2">} //newPen 在函数退出时自动删除 </font></p>
            <p><font size="2">　　对于显示设备环境来说，在每个消息控制函数的入口处，设备环境都是未被初始化的，因此每次都必须从头开始设置设备环境，由于 SelectObject 返回的 GDI 对象指针的临时性，而应用程序框架在函数返回时会删除 C++ 临时对象指针，所以不能简单地将设备环境指针保存在类的数据成员中，而要借助于 GetSafeHandle 成员函数来将它转换为 windows 句柄（唯一能够持久存在的 GDI 标识）。 </font></p>
            <font size="2">　　注意，当删除由 SelectObject 返回的指针所指向的对象时，一定要当心，如果该对象是我们自己申请的，可以删除，如果是临时的，则不能随便删除。 </font></td>
        </tr>
    </tbody>
</table><img src ="http://www.blogjava.net/dongwq/aggbug/224348.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2008-08-26 03:27 <a href="http://www.blogjava.net/dongwq/archive/2008/08/26/224348.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zz:vc常用技巧总结 </title><link>http://www.blogjava.net/dongwq/archive/2008/08/26/224347.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Mon, 25 Aug 2008 18:59:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2008/08/26/224347.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/224347.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2008/08/26/224347.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/224347.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/224347.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: （1） 如何通过代码获得应用程序主窗口的 指针?            主窗口的 指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现。            AfxGetMainWnd() -&gt;ShowWindow(SW_SHOWMAXMIZED)            //使程序最大化.                     ...&nbsp;&nbsp;<a href='http://www.blogjava.net/dongwq/archive/2008/08/26/224347.html'>阅读全文</a><img src ="http://www.blogjava.net/dongwq/aggbug/224347.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2008-08-26 02:59 <a href="http://www.blogjava.net/dongwq/archive/2008/08/26/224347.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zz:编程修养 </title><link>http://www.blogjava.net/dongwq/archive/2007/10/05/150460.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Thu, 04 Oct 2007 16:50:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2007/10/05/150460.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/150460.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2007/10/05/150460.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/150460.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/150460.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 什么是好的程序员？是不是懂得很多技术细节？还是懂底层编程？还是编程速度比较快？我觉得都不是。对于一些技术细节来说和底层的技术，只要看帮助，查资料就能找到，对于速度快，只要编得多也就熟能生巧了。 <br>我认为好的程序员应该有以下几方面的素质： <br>　1、有专研精神，勤学善问、举一反三。 <br>　2、积极向上的态度，有创造性思维。 <br>　3、与人积极交流沟通的能力，有团队精神。 <br>　4、谦虚谨慎，戒骄戒燥。 <br>5、写出的代码质量高。包括：代码的稳定、易读、规范、易维护、专业。<br>这些都是程序员的修养，这里我想谈谈“编程修养”，也就是上述中的第5点&nbsp;&nbsp;<a href='http://www.blogjava.net/dongwq/archive/2007/10/05/150460.html'>阅读全文</a><img src ="http://www.blogjava.net/dongwq/aggbug/150460.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2007-10-05 00:50 <a href="http://www.blogjava.net/dongwq/archive/2007/10/05/150460.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zz:计算机科学与技术学习反思录</title><link>http://www.blogjava.net/dongwq/archive/2007/10/04/150454.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Thu, 04 Oct 2007 15:53:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2007/10/04/150454.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/150454.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2007/10/04/150454.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/150454.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/150454.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 计算机科学与技术学习反思录<br><br>很老的帖子了，也不知道是谁写的<br><br>计算机科学与技术这一门科学深深的吸引着我们这些同学们，上计算机系已经有近三年<br>了，自己也做了一些思考,我一直认为计算机科学与技术这门专业，在本科阶段是不可能<br>切分成计算机科学和计算机技术的，因为计算机科学需要相当多的实践，而实践需要技<br>术；每一个人(包括非计算机专业)，掌握简单的计算机技术都很容易（包括程序设<br>计），但计算机专业的优势就在于，我们掌握许多其他专业并不“深究”的东西，例<br>如，算法，体系结构，等等。非计算机专业的人可以很容易地做一个芯片，写一段程<br>序，但他们做不出计算机专业能够做出来的大型系统。（与司徒彦南兄的谈话）今天我<br>想专门谈一谈计算机科学，并将重点放在计算理论上。 <br><br>&nbsp;&nbsp;<a href='http://www.blogjava.net/dongwq/archive/2007/10/04/150454.html'>阅读全文</a><img src ="http://www.blogjava.net/dongwq/aggbug/150454.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2007-10-04 23:53 <a href="http://www.blogjava.net/dongwq/archive/2007/10/04/150454.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>计算机科学与技术学习心得(zz)</title><link>http://www.blogjava.net/dongwq/archive/2007/10/04/150434.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Thu, 04 Oct 2007 13:52:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2007/10/04/150434.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/150434.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2007/10/04/150434.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/150434.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/150434.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: (几年以前就在BBS上看到别人转的这篇文章，今天读来感触更深，值得保留于此，再三体会）<br><br>计算机科学与技术学习心得<br><br>撰文 曾毅<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/dongwq/archive/2007/10/04/150434.html'>阅读全文</a><img src ="http://www.blogjava.net/dongwq/aggbug/150434.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2007-10-04 21:52 <a href="http://www.blogjava.net/dongwq/archive/2007/10/04/150434.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zz:批处理高级精华总结篇</title><link>http://www.blogjava.net/dongwq/archive/2007/08/13/136259.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Sun, 12 Aug 2007 16:46:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2007/08/13/136259.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/136259.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2007/08/13/136259.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/136259.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/136259.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这是一篇技术教程，我会用很简单的文字表达清楚自己的意思，你要你 识字就能看懂，就能学到知识。写这篇教程的目的，是让每一个看过这些文字的朋友记住一句话：如果爱可以让事情变的更简单，那么就让它简单吧！看这篇教程的 方法，就是慢！慢慢的，如同品一个女人、一杯茗茶，你会发现很多以前就在眼前的东西突然变的很遥远，而有些很遥远的东西却又突然回到了眼前。<br><br>先 概述一下批处理是个什么东东。批处理的定义，至今我也没能给出一个合适的----众多高手们也都没给出----反正我不知道----看了我也不一定信服- ---我是个菜鸟，当然就更不用说了；但我想总结出一个“比较合适的”，而且我也相信自己可以把它解释的很清楚，让更多的菜鸟都知道这是个什么东东，你用 这个东东可以干什么事情。或许你会因为这篇文章而“无条件爱上批处理”，那么我的目的就达到了----我就是要让你爱上它，我就这么拽，你能怎么着？？真 的，爱有时候就这么拽，就是这么没理由，就是这么不要脸！真的！<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/dongwq/archive/2007/08/13/136259.html'>阅读全文</a><img src ="http://www.blogjava.net/dongwq/aggbug/136259.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2007-08-13 00:46 <a href="http://www.blogjava.net/dongwq/archive/2007/08/13/136259.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zz:vc++常见的问题解答</title><link>http://www.blogjava.net/dongwq/archive/2007/08/07/135099.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Tue, 07 Aug 2007 15:16:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2007/08/07/135099.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/135099.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2007/08/07/135099.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/135099.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/135099.html</trackback:ping><description><![CDATA[<div class=tit>vc++常见的问题解答</div>
<div class=date>2007-07-27 11:00</div>
<table style="TABLE-LAYOUT: fixed">
    <tbody>
        <tr>
            <td>
            <div class=cnt>1：fatal error C1010: unexpected end of file while looking for precompiled header directive该如何解决 <br>如果发生错误的文件是由其他的C代码文件添加进入当前工程而引起的，则Alt+F7进入当前工程的Settings，选择C/C++选项卡，从Category组合框中选中Precompiled Headers，选择Not Using Precompiled headers。确定 <br>如果发生错误的文件原本是该工程中的，则检查该文件头部有没有#include "stdafx.h"语句，没有的话添加。 <br>如果还不行，也有可能是定义的类或结构体等最后忘了加分号，注意一下。 <br>2：fatal error RC1015: cannot open include file &#8217;afxres.h&#8217;.该如何解决 <br>#include "afxres.h"语句是在.rc文件中的，而afxres.h文件在VC的安装目录中的.\VC98\MFC\INCLUDE目录中，所以着重查一下Tools菜单中Options对话框中的Directories中的包括文件的路径是否正确，是否在VC的安装路径中，不是的话，改过来，如果这方面没问题，则到其他机器中拷贝afxres.h到相应的目录中 <br>3：Dll分配的内存块,应用程序释放，结果报异常。 <br>用GlobalAlloc()代替new, 用GlobalFree() 代替delete就不会出错了 <br>其实还有一个办法，就是把dll的Settings的C/C++选项卡的Code Generation的Use Run-time liberary改成Debug Multithreaded DLL，在Release版本中改成Multithreaded DLL，就可以直接使用new和delete了，没问题 <br>比较规范点的做法一般是DLL分配的内存由DLL释放。在DLL中加一个函数释放内存不是更好吗。 <br>4：发现打印预览的图形明显比屏幕显示图形小，怎么办？ <br>这多半是CDC映射模式的选择引起的，缺省状态下，选择的是MM_TEXT模式，MM_TEXT以设备的像素点为单位，而不同设备的像素点的大小不同，打印机的分辨率比显示器要高很多，所以导致同样图形在打印时候变小。解决之道是统一使用其他定长的映射模式，比如MM_HIMETRIC等等（CDC::SetMapMode()改变映射模式） <br>5：CString、char*、string、int、_bstr_t、CTime、COleDateTime等等的相互转换，如何判断一个字符串是一个浮点数？ <br><br>#include&lt;string&gt; <br>using namespace std; <br>#include &lt;COMDEF.H&gt; <br><br>{ <br>CString strCString="ABC"; <br>char strchar[256],*pstr; <br><br>pstr=(LPSTR)(LPCTSTR)strCString; //CString----&gt;char* <br>strcpy(strchar,(LPSTR)(LPCTSTR)strCString); //CString----&gt;char[] <br><br>_bstr_t strbstr=pstr; //char*----&gt;_bstr_t <br>WCHAR *strWCHAR=strbstr; //b_str_t---&gt;UNICODE <br><br>strbstr=strWCHAR; <br>pstr=strbstr; //UNICODE----&gt;char* <br><br>strCString="10"; <br>int istr=atoi((LPSTR)(LPCTSTR)strCString); //CString、char[]、char*------&gt;int <br>strCString.Format("%d",istr); //int-----&gt;CString <br>sprintf(strchar,"%d",istr); //int-----&gt;char[] <br><br>pstr=new char[256]; //字符串申请空间 <br>strcpy(pstr,"ABC"); //字符串赋值 <br>delete []pstr; //字符串释放 <br><br>string strstring="ABC"; <br>pstr=(char*)strstring.c_str(); //string----&gt;char* <br><br>strCString="2003-10-27 6:24:37"; //CString---&gt;COleDateTime <br>COleVariant vtime(strCString); <br>vtime.ChangeType(VT_DATE); <br>COleDateTime time4=vtime; <br><br><br><br>COleDateTime time1(1977,4,16,2,2,2); //COleDataTime---&gt;CTime <br>SYSTEMTIME systime; <br>VariantTimeToSystemTime(time1, &amp;systime); <br>CTime tm(systime); <br><br>time_t time2=tm.GetTime(); //CTime---&gt;time_t <br>COleDateTime time3(time2); //time_t---&gt;COleDateTime <br><br>//判断字符串是否是某种类型 <br>CString sValue("123.1"); <br>COleVariant vValue(sValue); <br><br>BOOL bStrIsFloat = (SUCCEEDED(VariantChangeType(&amp;vValue, &amp;vValue, 0, VT_R8)) &amp;&amp; sValue.Find(&#8217;.&#8217;) != -1); <br>if(bStrIsFloat) <br>{ <br>AfxMessageBox("浮点"); <br>} <br>} <br><br>6：如何建立一个UNICODE应用程序？ <br><br>建立一个应用程序，打开Alt+F7 settings选项，选择C/C++选项卡，在Preprocessor definenation中加上_UNICODE，在Link选项卡中，在Category选择框中选择Output，在Entry-point symbol编辑框中，添加wWinMainCRTStartup确定。 <br><br>注意调试UNICODE程序时，需要在安装时VC选择所有选项，否则会缺少动态库和相应的.lib文件 <br><br><br>7：ADO操作数据库表，更新出现问题 <br>在打开数据库前，添加如下语句试一下pRecordSet-&gt;CursorLocation = adUseClient</div>
            </td>
        </tr>
    </tbody>
</table><img src ="http://www.blogjava.net/dongwq/aggbug/135099.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2007-08-07 23:16 <a href="http://www.blogjava.net/dongwq/archive/2007/08/07/135099.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Knowing something of everything and everything of something. 通百艺而专一长。</title><link>http://www.blogjava.net/dongwq/archive/2007/08/07/135098.html</link><dc:creator>小强摩羯座</dc:creator><author>小强摩羯座</author><pubDate>Tue, 07 Aug 2007 15:12:00 GMT</pubDate><guid>http://www.blogjava.net/dongwq/archive/2007/08/07/135098.html</guid><wfw:comment>http://www.blogjava.net/dongwq/comments/135098.html</wfw:comment><comments>http://www.blogjava.net/dongwq/archive/2007/08/07/135098.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dongwq/comments/commentRss/135098.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dongwq/services/trackbacks/135098.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 　　指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。当你对C越来越熟悉时，你会发现，把与指针搅和在一起的"类型"这个概念分成"指针的类型"和"指针所指向的类型"两个概念，是精通指针的关键点之一。我看了不少书，发现有些写得差的书中，就把指针的这两个概念搅在一起了，所以看起书来前后矛盾，越看越糊涂。 &nbsp;&nbsp;<a href='http://www.blogjava.net/dongwq/archive/2007/08/07/135098.html'>阅读全文</a><img src ="http://www.blogjava.net/dongwq/aggbug/135098.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dongwq/" target="_blank">小强摩羯座</a> 2007-08-07 23:12 <a href="http://www.blogjava.net/dongwq/archive/2007/08/07/135098.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>