﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-清源游民的网络笔记本-随笔分类-C++</title><link>http://www.cppblog.com/yuanyajie/category/3707.html</link><description>记录所思所想，收藏所见所闻�?
</description><language>zh-cn</language><lastBuildDate>Thu, 07 May 2009 16:44:02 GMT</lastBuildDate><pubDate>Thu, 07 May 2009 16:44:02 GMT</pubDate><ttl>60</ttl><item><title>试用新版本luabind</title><link>http://www.cppblog.com/yuanyajie/archive/2009/05/07/82117.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Wed, 06 May 2009 16:46:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2009/05/07/82117.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/82117.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2009/05/07/82117.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/82117.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/82117.html</trackback:ping><description><![CDATA[环境xp sp3 , vs2008 sp1, luabind 0.8.1,lua 5.1.4 , boost 1_36_0<br>先把lua, luabind 编成静态库，（下图只是debug,release类似)：<br><br><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/lua_bind_lib.png" border=0><br>做完之后整理，lua, luabind 以sdk 形式组织好，我是这样组织:<br>\luabind_build\sdk\luabind\include<br>\luabind_build\sdk\luabind\msvc-9.0-sp1\lib<br>\luabind_build\sdk\lua\include<br>\luabind_build\sdk\lua\msvc-9.0-sp1\lib<br>这样，把sdk中的东东保存一份，方便以后使用。写一个MFC小程序测试<br><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/mfc_lua.png" border=0><br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #008000">//</span><span style="COLOR: #008000">关键代码<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">mfc&nbsp;class&nbsp;function</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;CMFC_LuaDlg::SetEditText(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;text)<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Edit_1.SetWindowText(text);<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;UpdateData(FALSE);<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">register</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">luabind::module(L)<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;[<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;luabind::class_</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">CMFC_LuaDlg</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">mfc_dlg</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.def</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">set_text</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">CMFC_LuaDlg::SetEditText)<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;];<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">load&nbsp;lua&nbsp;file</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">luaL_dofile(L,filepath))<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">run&nbsp;lua&nbsp;function</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;luabind::call_function</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(L,</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">update_text</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,dlg);<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000"></span></div>
脚本内容:<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #000000">function&nbsp;update_text(dlg)<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;dlg:set_text(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">你好，欢迎来到lua&nbsp;脚本世界</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #000000">end</span></div>
运行结果：<br><img src="http://www.cppblog.com/images/cppblog_com/yuanyajie/mfc_lua_ret.png" border=0><br><br>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/82117.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2009-05-07 00:46 <a href="http://www.cppblog.com/yuanyajie/archive/2009/05/07/82117.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++,要细心不能想当然</title><link>http://www.cppblog.com/yuanyajie/archive/2009/05/06/82091.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Wed, 06 May 2009 13:09:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2009/05/06/82091.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/82091.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2009/05/06/82091.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/82091.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/82091.html</trackback:ping><description><![CDATA[两段想当然写下的代码，你看出问题了吧<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Data;<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">Data</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;FindData();<br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;GetData(Data</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;dataPtr)<br></span><span style="COLOR: #008080">4</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;dataPtr</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">FindData();<br></span><span style="COLOR: #008080">6</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">7</span>&nbsp;<span style="COLOR: #000000">Data</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;data</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">NULL;<br></span><span style="COLOR: #008080">8</span>&nbsp;<span style="COLOR: #000000">GetData(data);<br></span><span style="COLOR: #008080">9</span>&nbsp;<span style="COLOR: #000000">data</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">somefunction();</span></div>
第二段代码，更得仔细点<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;A;<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;B;<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">A&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;GetA();<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">B&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;GetB();<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;GetSpecialValue(T</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;classPtr)<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">3721</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;GetSpecialValue</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000">(A</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;classPtr)<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">37</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;GetSpecialValue</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000">(B</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;classPtr)<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">21</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">A&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;classPtr</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">GetA();<br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;ret</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">GetSpecialValue(classPtr);<br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000">cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">ret</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">endl;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">out&nbsp;3721!&nbsp;why&nbsp;not&nbsp;37?</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #000000"></span></div>
第一段的问题在于看到指针想当然认为是地址，data 可以带回反回值，其实因为这里是值传递，实参data把自己的值赋给了dataPtr,dataPtr后来确实从FindData()得到了想要的值，但这对一点影响也没有，所以函数返回时，data的值没有发生变化，也就是没有带回想要的值。<br>只要不想当然，仔细一想就明白了，解决办法很简单：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;GetData(Data</span><span style="COLOR: #000000">*&amp;</span><span style="COLOR: #000000">&nbsp;dataPtr)<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">&nbsp;{<br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dataPtr</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">FindData();<br></span><span style="COLOR: #008080">4</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">&nbsp;}</span></div>
第二段的问题是没有注意到那个const, T*&nbsp; 和 T const* 是不一样的，不能完全匹配，所以不会找到对A类型的特化版本,解决办法可以这样：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;GetSpecialValue(T&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;classPtr)<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">3721</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;GetSpecialValue</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000">(A&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;classPtr)<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">37</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;GetSpecialValue</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000">(B&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;classPtr)<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">21</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">}</span></div>
能过这两个小例子就可以知道，C++细节很多，要仔细，不能想当然。<br>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/82091.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2009-05-06 21:09 <a href="http://www.cppblog.com/yuanyajie/archive/2009/05/06/82091.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（网摘好文）C++多态技术的实现和反思</title><link>http://www.cppblog.com/yuanyajie/archive/2007/11/09/36260.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Fri, 09 Nov 2007 14:32:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/11/09/36260.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/36260.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/11/09/36260.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/36260.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/36260.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/yuanyajie/archive/2007/11/09/36260.html'>阅读全文</a><img src ="http://www.cppblog.com/yuanyajie/aggbug/36260.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-11-09 22:32 <a href="http://www.cppblog.com/yuanyajie/archive/2007/11/09/36260.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（网摘好文）关于野指针</title><link>http://www.cppblog.com/yuanyajie/archive/2007/11/09/36259.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Fri, 09 Nov 2007 14:21:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/11/09/36259.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/36259.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/11/09/36259.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/36259.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/36259.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/yuanyajie/archive/2007/11/09/36259.html'>阅读全文</a><img src ="http://www.cppblog.com/yuanyajie/aggbug/36259.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-11-09 22:21 <a href="http://www.cppblog.com/yuanyajie/archive/2007/11/09/36259.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网摘：一篇介绍DirectX 10 的文章</title><link>http://www.cppblog.com/yuanyajie/archive/2007/05/31/25201.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Thu, 31 May 2007 07:11:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/05/31/25201.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/25201.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/05/31/25201.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/25201.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/25201.html</trackback:ping><description><![CDATA[Microsoft发布的DirectX 10代表了自从可编程Shader出现以来在3D API方面的最巨大的进步。通过一番脱胎换骨般的重建，DirectX 10展现出一系列非常醒目的新特性，包括高度优化的运行时，强大的Geometry Shader，纹理数组等等，这些特性将引领PC实时三维图形进入一个全新的世界。
<h2>DirectX 发展简史</h2>
<p>　　在过去的十年中，<a href="http://www.highdiy.com/html/av/video/387_11.shtml"><u><font color=#0000ff>DirectX</font></u></a>已经稳步成为了Microsoft Windows平台上进行游戏开发的首选API。每一代的DirectX都带来对新的图形硬件特性的支持，因此每次都能帮助游戏开发者们迈出惊人的一步。</p>
<p>　　微软DirectX API(Application Programming interface :应用程序界面) 最早发布于1995年，其设计目标是为Windows平台软件开发人员提供一个更简便的针对多媒体和游戏应用编程的标准接口。</p>
<p>　　在DirectX出台，开发者针对音频、视频等的操作必须基于硬件进行，——当然，基于OpenGL能够在很大程序上减轻工作量，但OpenGL获得的支持显然远远不够。——而显卡、声卡等的产品种类众多，要编写一款能运行在所有平台上的游戏简直是一件噩梦般的工作。</p>
<p>　　通过提供一系列的针对多媒体应用的API，如图形(包括2D与3D应用)、音频或输入设备等，DirectX提供了一整套的多媒体接口方案，这可以让开发者根据API编写相应的软件程序，而不必考虑具体的硬件，硬件的差别性显得无足轻重，编程人员得以更有效率的开发各种多媒体、游戏软件。</p>
<p>　　当然，DirectX的发展并不是一帆风顺的，最初的版本远谈不上稳定。　</p>
<p>
<table class=atable cellSpacing=1 cellPadding=1 width=440 align=center>
    <tbody>
        <tr class=tbhead>
            <td>版本</td>
            <td>操作系统</td>
            <td>发布日期</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 1.0</td>
            <td>Windows 95a</td>
            <td>9/30/95</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 2.0/2.0a</td>
            <td>Windows 95OSR2/NT4.0</td>
            <td>6/5/96</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 3.0/3.0a</td>
            <td>Windows NT 4.0 SP3</td>
            <td>9/15/96</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 4.0</td>
            <td></td>
            <td>未发布</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 5.0</td>
            <td>Windows NT 4.0/Beta for NT 5.0</td>
            <td>7/16/97</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 5.1</td>
            <td>Windows 95/98/NT4.0</td>
            <td>12/1/97</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 5.2</td>
            <td>Windows 95</td>
            <td>5/5/98</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 6.0</td>
            <td>Windows 98/NT4.0</td>
            <td>8/7/98</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 6.1</td>
            <td>Windows 95/98/98SE</td>
            <td>2/3/99</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 7.0</td>
            <td>Windows 95/98/98SE/2000</td>
            <td>9/22/99</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 7.0a</td>
            <td>Windows 95/98/98SE/2000</td>
            <td>9/99</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 7.1</td>
            <td>Windows 95/98/98SE/ME/2000</td>
            <td>9/16/99</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 8.0/8.0a</td>
            <td>Windows 95/98/98SE/ME/2000</td>
            <td>9/30/2000</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 8.1</td>
            <td>Windows 95/98/98SE/ME/2000/XP</td>
            <td>11/12/01</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 9 <br>Shader Model 2.0</td>
            <td>Windows 95/98/98SE/ME/2000/XP</td>
            <td>12/19/2002</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 9 <br>Shader Model 2.0b</td>
            <td>Windows 98/98SE/ME/2000/XP</td>
            <td>8/13/2003</td>
        </tr>
        <tr class=tbnmal>
            <td class=lbt>DirectX 9<br>Shader Model 3.0</td>
            <td>Windows 98/98SE/ME/2000/XP</td>
            <td>8/9/2004</td>
        </tr>
    </tbody>
</table>
</p>
<h2>DirectX 3D的发展</h2>
<p>　　DirectX中应用在3D图形方面的特定DirectX API即Direct3D，这也是DirectX中最重要的部分。不过，DirectX 3D得到广泛应用是在DirectX 6.0之后：</p>
<p>　　<strong>DirectX 6.0</strong>：加入了双线性过滤、三线性过滤等优化3D图像质量的技术，加入环境影射凹凸贴图，使3D游戏的画面更具有真实感。</p>
<p>　　<strong>DirectX 7.0</strong>：最大的特色就是支持了T&amp;L，中文名称是&#8220;坐标转换和光源&#8221;，3D游戏中坐标和灯光的转换工作从此由CPU转交给了GPU，比DX6.1性能提升20%。这也成就了nVIDIA GeForce 256与ATi Radeon 256的辉煌，令3DFX彻底退出市场竞争。</p>
<p>　　<strong>DirectX 7.0a</strong>：增强了力反馈游戏控制设备的性能和兼容性。</p>
<p>　　<strong>DirectX 7.1</strong>：与Windows Millennium一同发布。</p>
<p>　　<strong>DirectX 8.0/8.0a</strong>：支持Shader Model 1.0和1.1，从此在显卡中引入可编程像素着色器(Pixel Shaders)和顶点着色器(Vertex Shaders)的概念，同时应用在Xbox游戏机中。同硬件T&amp;L仅仅实现的固定光影转换相比，VS和PS单元的灵活性更大，它使GPU真正成为了可编程的处理器。</p>
<p>　　<strong>DirectX 8.1</strong>： Pixel Shader升级到1.2、1.3、1.4版，可以支持最高每时钟28指令执行，其中1.4版当时仅ATi Radeon 8500显卡支持。</p>
<p>　　<strong>DirectX 9.0 Shader Model 2.0</strong>： SM2.0的shader性能更强，支持最高96指令的pixel shader长度，同时DirectPlay和一些音频方面也有大幅提升。</p>
<p>　　<strong>DirectX 9.0 Pixel Shader 2.0b</strong>： ATI Radeon X600/700/800系列显卡首先采纳，开始支持更多指令(最高1536)和更多临时寄存器(32相比之前为12)，同时还加入新的贴面寄存器(facing register)和几何实例(geometry instancing)的支持。</p>
<p>　　<strong>DirectX 9.0 Shader Model 3.0</strong>：支持更多指令，支持指令的流量控制和动态分支，从而使得编程人员可以在shaders中加入循环操作，使得编程更加容易，首次被Geforce 6800显卡采用。</p>
<p>　　从DirectX的发展史中我们可以看到，微软的3D API和硬件一同发展，新硬件带来新的DX特性，新的DX特性加速硬件的发展，在DirectX10上面，又是一个3D图形发展的新境界。</p>
<h2>DirectX 10的架构优势</h2>
<p>　　DirectX之所以在广大的开发者中流行，是得益于它的简单易用和丰富的功能特性。然而，DirectX一直被一个主要的问题所困扰，那就是高CPU负载。</p>
<p>　　在图形编程API出现之前，3D应用程序直接向图形硬件发送命令来完成图形的绘制工作。虽然这样开发工作比较繁重，但硬件效率则能在很大程度上得到保证。</p>
<p>　　而如DirectX和OpenGL这样的图形API则是通过在图形硬件和应用程序之间架起了一个中间层，这样，应用程序可以使用统一的图形编程代码来完成对底层硬件的操作，将程序员们从与大量的图形硬件交互的恶梦中解救出来。但是，这也造成了每次DirectX从应用程序那里接收到一条命令时，就必须先对这条命令进行分析和处理，再向图形硬件发送相对应的硬件命令。由于这个分析和处理的过程由CPU完成，造成了每一条3D绘图命令都会带来CPU的负载。</p>
<p>　　从技术角度，这种CPU负载给3D图象带来两个负面影响：首先，限制了画面中可以同时绘制的物体数量；其次，限制了可以在一个场景中使用的独立的特效的数量。这就使得游戏画面中的细节数量受到了很大的限制，而图像具有真实感的主要要求便是丰富的细节。</p>
<p>　　DirectX 10的主要优势便是最大程度地降低了CPU负载，主要通过三个途径来达到这个目的：第一，修改API核心，使得绘制物体和切换材质特效时的消耗降低，提高绘图效率；第二，引入新的机制，降低图形运算操作对CPU的依赖性，使更多的运算在GPU中完成；第三，使大量的物体可以通过调用单条DirectX绘制命令进行批量绘制。</p>
<p>　　下面我们就来仔细的看一下这三种方式：</p>
<p>　　<strong>提高绘图效率</strong></p>
<p>　　在DirectX 10中，对上代DirectX版本中三维数据和绘制命令的验证过程进行了很大程度的修改。所谓三维数据和命令的验证，是指在DirectX绘制图形之前，对传给它的图形数据和绘制命令进行格式和数据完整性的检查，以保证它们被送到图形硬件时不会导致硬件出问题；这是很必要的一步操作，但是不幸的是这会带来很大的性能开销。</p>
<p><img class=artimg alt="DirectX 9 vs. DirectX 10" src="http://www.highdiy.com/upimg/uploadimg/20061112/055430192.gif"></p>
<p>　　从上表我们可以很容易的看出，在DirectX 9中，每次绘制一帧画面之前，都会对即将使用的相关数据进行一次验证。而DirectX 10中，仅当这些数据被创建后验证一次。这很明显是可以大大提高游戏进行中的效率的。</p>
<strong>降低图形运算对CPU的依赖</strong>
<p>　　在降低图形运算对CPU的依赖方面，DirectX 10 引入的三个重要机制就是：纹理阵列(texture arrays)、绘制预测 (predicated draw)和流式输出(stream out)。不要被这三个晦涩的名词吓倒，实际上它们是三个不难理解的机制。</p>
<p>　　<em>纹理阵列</em></p>
<p>　　传统的DirectX在多张纹理中进行切换的操作是种很给CPU带来很大压力的操作，因为每切换一次，都要调用一次DirectX的API函数。而每绘制一个使用新纹理的物体，就要进行一次这样的切换操作；有时为了实现特殊的材质特效，绘制一个物体时可能就要切换好几次纹理，开销很大。</p>
<p>　　所以，之前游戏中经常会出现将大量的小纹理拼合到一张大的纹理中，通过给不同的三维物体分配这张大纹理的不同局部的方式，以期减少纹理切换，提高游戏运行效率。这种方式实现起来相当复杂，而且DirectX 9中对纹理的尺寸的限制是4048&#215;4048像素，也就是说，如果要容下更多的小纹理块，可能就得加载很多张这样的大纹理。</p>
<p>　　DirectX 10引入的新的纹理阵列机构，将允许在一个由显卡维护的阵列中容纳512张单独的纹理，而且，在shader程序中可以使用一条新的指令来获取这个阵列中的任意一张纹理。而这种shader指令是运行在GPU中的；这样，就把原来要消耗很多CPU时间的纹理切换工作轻松地转给了GPU。由于纹理一般是直接放在显存中的，因此以这样的方式，将工作交与和显存一同位于显卡上的GPU来完成更有效率。如今，在DirectX 10中，只要一开始设置好纹理阵列中的纹理，然后每次绘制一个物体时为它指定一个纹理的索引号，并同物体三维数据一起传递到shader中，就可以放心的让GPU来给物体选纹理了。</p>
<p>　　<em>绘制预测</em></p>
<p>　　在一般的三维场景里，很多物体都是完全被别的物体挡在后面的。这时候如果要显卡绘制这些物体就是白费力气。尽管高级的GPU可以通过硬件算法将场景画面中被挡住的像素(注意是像素)预先剔除，但是仍然会有很多不应进行的多余运算。例如，一个完全被挡住的复杂的角色模型，它的身上可能有几千个顶点，需要做复杂的骨骼皮肤动画处理、顶点光照运算等等，然而，GPU是在处理完这些顶点之后，并要把这个角色模型一个像素一个像素地画到画面中时，才开始判断每个像素是否需要画，而当所有的像素都被剔除了时，之前做的顶点处理也就全白费了。在DirectX 10中的绘制预测便正是针对这种情况的解决，简言之，绘制预测通过用一个可以代表某个复杂物体的简单物体来判断这个物体是否被全部挡住了，例如用一个可以罩住刚才那个角色的大盒子，当绘制这个盒子时，如果发现所有的像素都被屏蔽掉了，也即是说这个盒子肯定完全看不见，那么，里面的角色绘制包括骨骼皮肤运算等之类的操作便完成不必进行。而一个盒子顶多有八个顶点，相比处理几千个顶点，开销小得多。</p>
<p>　　另外，以前这个步骤中有些真运算也需CPU完成的，在DirectX 10中，已经完全交由GPU来做，这也可以在一定程度上减轻CPU的压力。<br><em>数据流式输出</em></p>
<p>　　数据流式输出也是DirectX 10的重要特性，它允许GPU上的Vertex shader或Geometry shader向显存中添加数据，而这在以往的vertex shader中是不可能的。</p>
<p>　　在之前的DirectX版本中，vertex shader只能读取显存中已有的顶点数据；而DirectX 10中引入的新的Geometry shader，不但能读取显存中的顶点数据、几何(点、线段、三角形)数据，还可以生成新的几何数据放回显存。</p>
<strong>批量绘制</strong>
<p>　　在DirectX 9中，对渲染状态的管理一直是个十分信赖于CPU运算能力的操作。所谓渲染状态，是指显卡进行一次绘制操作时所需要设置的各种数据和参数。例如，要绘制一个人物角色，就需要先设置他的几何模型数据的数据格式、纹理过滤模式、半透明混合模式等等，每设置一项，都要调用一次DirectX API，占用大量CPU时间，极大的约束了渲染的性能。</p>
<p>　　为了使这些操作能够批量的进行，DirectX 10中引入了两个新的结构——状态对象(state object)和常量缓冲(constant buffers)。</p>
<p>　　状态对象就是将以前的零散状态按照功能归结为几个整体，这样，当要设置一系列相关状态时，无需为每一个状态来调用一次DirectX API,只需要调用一次将这些状态统统设置到显卡中去。</p>
<p>　　而常量缓冲是另一个十分有意义的机制。在绘制模型前的准备工作中，渲染状态的设置只是一小部分。还是拿绘制人物角色来说，能照亮这个人的光源的颜色、位置、类型、范围等等，都要提前设给显卡；为了通过骨骼来带动他的皮肤做出姿势，还要设置骨骼的位置信息等等，而这些东西主要都是通过GPU中的常量寄存器(constant registers)来传递给它的。每个常量寄存器可以存储一个4维的浮点型向量(即四个浮点数)。常量寄存器是游戏程序向GPU输入游戏场景中数据的重要途径。</p>
<p>　　在DirectX 9中，这种常量寄存器的数量是十分有限的，而且每次更新一个寄存器，都需要调用一次DirectX API函数。DirectX 10通过使用常量缓冲(constant buffer)这种结构，在每个constant buffer中都可以容纳4096个常量，而且只需调用一次API就可以更新一大批常量。</p>
<p>　　比如说，在以前的DirectX版本中，如果程序想在场景里画很多的树木和杂草，可以采用一个类似于&#8220;克隆&#8221;的方法：先做好一棵或几棵树、草的三维模型，然后在画一帧画面时，不停的在不同的位置、方向，用不同的大小为参数，调用DirectX API的绘制函数来画这些模型，就可以画出很多草木来。但是每画一棵，都要设置一大堆参数后调用一次API，这是很耗CPU时间的，所以在以前的游戏中鲜有大规模且细节丰富的森林场景。</p>
<p>　　而在DirectX 10中，我们可以先把树、草的几个模型设给显卡，然后将所有要画的树木的位置、方向和大小一次性的写入到constant buffer中，这样，显卡便一下把所有的树木和草都一起绘制出来了。</p>
<p>　　总之，DirectX 10通过提前数据验证、纹理阵列、绘制预测、流式输出、状态对象、常量缓冲等机制，帮助游戏的效果和效率上升到一个新的高度。这样，也避免了之前DirectX版本因CPU负载过大而无法对图形实施更多细节优化的问题。</p>
<h2>Shader Model 4.0</h2>
<p>　　DirectX 10另一个引人瞩目的特性便是引入了Shader Model 4.0，那么，Shader Model 4.0能够带来怎样的新特性，特别是将它与DirectX 9.0c中Shader Model 3.0相比时？</p>
<p>　　<em>引入新Shader : Geometry shader</em></p>
<p>　　DirectX 10新引入的Geometry Shader，可以简单地编程操纵几何图元，同时， vertex、geometry、pixel shader采用了统一的Sahder架构。</p>
<p>　　Geometry shaders是可编程图形流水线的一大进步。它第一次允许由GPU来动态的生成和销毁几何图元数据。通过和新的数据流输出功能配合使用，许多以前无法实施的算法现在都可以在GPU中使用了。</p>
<p>　　<em>统一的Shader架构</em></p>
<p>　　在DirectX 9中，Pixel shader总是在各个方面落后于vertex shaders，包括常量寄存器个数、可用的指令个数、shader长度等。程序员需要区分对待这两种shader。</p>
<p>　　而在shader model 4中，无论 vertex、geometry和pixel shader，均有统一的指令集、同样的临时/常量寄存器个数，它们将平等的共享GPU中的所有可用资源。这样，在编程时便不必再考虑每种shader自身的限制了。</p>
<p>　　<em>百倍于DirectX 9的可用资源</em></p>
<p>　　对于shader中可用的资源，在Shader model 4.0中比原来有了惊人的扩充。就像早期的程序员们绞尽脑汁的省着用可怜的640k内存一样，在使用以前的DirectX开发游戏的过程中，程序员需要小心翼翼的分配珍贵的shader寄存器资源。寄存器的数量，直接影响着shader程序的复杂度。这和在640k内存的 机器上，怎么也不可能写出Microsoft Office这样的大规模软件是同一个道理。</p>
<p>　　而在DirectX 10中，将临时寄存器由原来的32个扩充到了4096个，将常量寄存器由原来的256个扩充到了65536个。</p>
<p>　　<em>更多的渲染目标(Render Target)</em></p>
<p>　　所谓渲染目标，就是指GPU可以把画面绘制到的目标，我们可以把它理解为GPU的画布。一般来说，渲染目标被输出到屏幕上，这样我们就能看到画好的画面了。但是有时为了实现一些特效，某些渲染结果并不直接画到屏幕上，而是再返给GPU做进一步的特效处理，而且渲染目标中也不一定是画好的画面的颜色信息。</p>
<p>　　根据图形特效的需要，渲染目标可能是每个物体距离屏幕的远近，或者物体表面上每个像素的方向，或者每个物体表面的温度等等，之为了实现特效，可以按需要在其中绘制任何信息。为了提高这种情况下的效率，很多新的显卡都支持在同一遍Shader执行结束后，同时把不同的信息绘制到不同的渲染目标中。在DirectX 9中就已经支持这种机制了，但是它约束最多同时向四个渲染目标绘制。而DirectX 10将这个数量提升了一倍。</p>
<em>更多的纹理</em>
<p>　　在Shader Model 4.0中提供了对纹理阵列(Texture arrays)的支持。在前文中已经对纹理阵列有了比较详细的介绍，在这里只着重介绍一下与shader相关的部分。</p>
<p>　　在每个纹理阵列中，最多可以保存 512张同样大小的纹理。而且每张贴图的分辨率被扩展到了8192&#215;8192。更大的分辨率意味着纹理中更丰富的细节。在一个shader中能够同时访问的纹理个数被增加到了128个，也就是说在每次执行同一个shader时，可以使用一个纹理阵列的512个纹理中的128个。所以说，在DirectX 10中，纹理的多样性和细节程度将会有大幅的提升。</p>
<p>　　<em>新的HDR颜色格式</em></p>
<p>　　要说这些年来在实时图形界炒得最热的概念，应该是<a href="http://www.highdiy.com/html/av/video/387_12.shtml">HDR</a>了。它通过采用浮点格式的颜色格式来为纹理、光照等计算提供极大的精度和颜色范围(以前的纹理一般 都是采用整数型的颜色格式)。尽管最后显示到屏幕上还是每个颜色通道8位的整数格式，但是以前由于在材质、光照计算中纹理也是用每通道8位的格式来参与计算，所以在显示到画面之前，很多细节就在低精度的运算中丢失了。</p>
<p>　　而采用每颜色通道16位浮点数的纹理，能够保证在运算过程中几乎没有颜色细节信息的丢失。另外，采用16位浮点格式的颜色通道，可以表现更大的颜色范围。这些就是HDR的优越性。</p>
<p>　　对用户而言，当游戏中的画面罩上一层HDR效果后，立刻显得和真正的照片一样，有朦胧的光晕、细致的高光和十分自然的色调。</p>
<p>　　然而，采用每个颜色通道16位浮点数的格式，比采用每通道8位的整数格式的纹理要多占据一倍的显存；这给绘制的效率带来了负面的影响。所以在 DirectX 10中引入了两个新的HDR格式。第一种是R11G11B10，表示红色和绿色通道用11位浮点数，而蓝色通道采用10位浮点数表示。那么，为什么不都用 11位呢？这是为了凑32这个整数。学过计算机的人都知道，当内存中一个数据单元的宽度是32位时，对它的操作效率最高；而且在纹理数据中一般要求每个像素的数据宽度是2的倍数，如2,8,16,32,64等等。又因为人眼对蓝色的敏感度不如对红色和绿色，所以它比其他两个通道少用了一位。</p>
<p>　　另外一种格式是采用每通道9位尾数、所有通道共享5位指数的形式(众所周知，在计算机中，浮点数是采用尾数附加指数的形式来表示的)，加起来还是32位。 这些新的格式使得纹理能够与原来占用同样多的显存空间，避免了大的空间和带宽消耗。同时，为了适合需要精确的科学计算的场合，DirectX 10能够支持每通道32位(4个通道加起来128位)精度的浮点数纹理。</p>
<p>　　DirectX 10中带来的这些扩充和提高，使得创建前所未有的细节的实时游戏场景真正成为可能。</p>
<h2>几何着色器与流式输出</h2>
<p>　　在DirectX 10发布之前，图形硬件只有在GPU上操作已有数据的能力。顶点着色器(Vertex Shader)和像素着色器(Pixel Shader)都允许程序操作内存中已有的数据。这种开发模型非常成功，因为它在复杂网格蒙皮和对已有像素进行精确计算方面都表现的很出色。但是，这种开发模型不允许在图像处理器上生成新数据。当一些物体在游戏中被动态的创建时(比如新型武器的外形)，就需要调用CPU。可惜现在大多数游戏已经很给CPU带来了很大的压力，游戏进行时动态创建庞大数量新数据的机会就变得微乎其微了。</p>
<p>　　Shader Model 4.0中引入的几何着色器(Geometry Shader)，第一次允许程序在图像处理器中创建新数据。这一革命性的事件使得GPU在系统中的角色由只可处理已有数据的处理器变成了可以以极快速度既可处理又可生成数据的处理器。在以前图形系统上无法实现的复杂算法现如今变成了现实。</p>
<p>　　几何着色器被放在顶点着色器和光栅化阶段(Rasterizer)中间。所谓光栅化，就是一行一行的扫描每个三角形，把它们一个像素一个像素的绘制到画面 上。几何着色器把经过顶点着色器处理过的顶点当作输入，对于每个顶点，几何着色器可以生成1024个顶点作为输出。这种生成大量数据的能力叫做数据扩大 (Data Amplification)。同样的，几何着色器也可以通过输出更少的顶点来删除顶点，因此，就叫做数据缩小(Data Minimization)。这两个新特性使GPU在改变数据流方面变得异常强大。</p>
<p>　　<em>细分的虚拟位移贴图(Displacement Mapping with Tessellation)</em></p>
<p>　　几何着色器让虚拟位移贴图可以在GPU上生成。虚拟位移贴图是在离线渲染系统中非常流行的一项技术，它可以用一个简单的模型和高度图(Height Map)渲染出非常复杂的模型。高度图是一张用来表示模型上各点高度的灰度图。渲染时，低多边形的模型会被细分成多边形更多的模型，再根据高度图上的信息，把多边形挤出，来表现细节更丰富的模型。</p>
<p>　　而在DirectX 9中，GPU无法生成新的数据，低多边形的模型无法被细分，所以只有小部分功能的虚拟位移贴图可以实现出来。现在，使用DirectX 10的强大力量，数以千计的顶点可以凭空创造出来，也就实现了实时渲染中真正的细分的虚拟位移贴图。</p>
<p>　　<em>基于边缘(Adjacency)的新算法</em></p>
<p>　　几何着色器可以处理三种图元：顶点、线和三角形。同样的，它也可以输出这三种图元中的任何一种，虽然每个着色器只能输出一种。在处理线和三角形时，几何着 色器有取得边缘信息的能力。使用线和三角形边缘上的顶点，可以实现很多强大的算法。比如，边缘信息可以用来计算卡通渲染和真实毛发渲染的模型轮廓。</p>
<p>　　<em>流式输出(Stream Output)</em></p>
<p>　　在DirectX 10之前，几何体必须在写入内存之前被光栅化并送入像素着色器(pixel shader)。DirectX 10引入了一个叫做数据流式输出(Stream Output)的新特性，它允许数据从顶点着色器或几何着色器中直接被传入帧缓冲内存(Frame Buffer Memory)。这种输出可以被传回渲染流水线重新处理。当几何着色器与数据流输出结合使用时，GPU不仅可以处理新的图形算法，还可以提高一般运算和物理运算的效率。</p>
<p>　　 在生成、删除数据和数据流输出这些技术的支持下，一个完整的粒子系统就可以独立地在GPU上运行了。粒子在几何着色器中生成，在数据扩大的过程中被扩大与派生。新的粒子被数据流输出到内存，再被传回到顶点着色器制作动画。过了一段时间，它们开始逐渐消失，最后在几何着色器中被销毁。<br></p>
<h2>高级渲染语言(HLSL 10)</h2>
<p>　　DirectX 10 为以前的DirectX 9中的&#8220;高级着色语言&#8221;(High Level Shading Language )带来了诸多功能强大的新元素。其中包括可以提升常量更新速度的&#8220;常量缓冲器&#8221;(Constant Buffers)，提升渲染流程中操作数据的灵活性的&#8220;视图&#8221;(view)，为更广泛的算法所准备的&#8220;整数与位指令&#8221;(Integer and Bitwise Instructions)，添加了switch语句。</p>
<p>　　<em>常量寄存器(Constant Buffers)</em></p>
<p>　　着色程序同普通的程序一样需要使用常量来定义各种参数，例如光源的位置和颜色，摄像机的位置和投影矩阵以及一些材质的参数(例如反光度)。在整个渲染的过程中，这些常量往往需要频繁的更新，而数以百计的常量的使用以及更新无疑会给CPU带来极大的负载。DirectX 10中新加入的常量缓冲器可以根据他们的使用频率将这些常量分配到指定的缓冲器中并协调的对其进行更新。</p>
<p>　　在一个着色程序中DirectX 10支持最多16个常量缓冲器，每一个缓冲器可以存放4096个常量。与其相比DirectX 9实在是少得可怜，因为它在每个着色程序中同时最多只能支持256个常量。</p>
<p align=center><img class=artimg alt=常量着色器 src="http://www.highdiy.com/upimg/uploadimg/20061112/055617123.gif"></p>
<p>　　相比DirectX 9，DirectX 10不仅提供了更多的常量，最主要的是它大幅的提升了常量更新的速度。对那些被分配到同一个缓冲器中的常量，我们只需进行一次操作就可以将它们全部更新完毕，而非单个单个的去更新。</p>
<p>　　由于不同的常量更新的时间间隔各异，所以跟据使用的频率来对他们进行组织就可以获得更高的效率。举例来说：摄像机的视矩阵只在每一帧之间发生改变，而类似贴图信息这样的材质参数却会在图元切换时发生改变。于是这些常量缓冲器被分成了两个部分：那些每帧更新的常量缓冲器专门存放那些需要在两帧间更新的常数并在两帧间一次把他们全部更新，另外的图元切换更新的常量缓冲器也同理。这样就会将更新常量过程中的一些不必要的工作消除，以便让整个着色器脚本比在 DirectX 9中运行的更加顺畅。</p>
<em>视图(Views)</em>
<p>　　在DirectX 9中，着色器(shader)中的数据的类型是被严格划分开的。例如，顶点着色器用到的顶点缓冲器中的数据不能当作贴图的数据来让像素着色器使用。这样就将特定的资源类型同其相对应的渲染流程中的特定步骤紧密地结合了起来，同时限制了资源资源在整个渲染流程中可以使用的范围。</p>
<p>　　DirectX 10舍弃了&#8220;严格区分的数据类型&#8221;这一概念。当一段数据被创建，那么DirectX 10所做的仅仅是将其简单的当作内存中的一段区域(bit field)来对待。如果要想使用这一段没有定义类型的数据就必须通过使用一个&#8220;view&#8221;。 使用&#8220;view&#8221;，相同的一段数据就可以有各种各样的方法来读取。DirectX 10支持对同一段资源在同时使用两个&#8220;view&#8221;。</p>
<p>　　通过这种多重&#8220;view&#8221;的手段，就可以在整个渲染流程的不同部分以不同目的使用同一段数据。例如：我们可以通过像素着色器将一段几何数据渲染到一张纹理 上，之后顶点着色器通过一个&#8220;view&#8221;将这张纹理视为一个顶点缓冲器并将其中的数据作为几何数据渲染。&#8220;view&#8221;通过在整个渲染流程中的不同步骤重复 使用同一段数据为&#8220;数据处理&#8221;带来了更大的灵活性，帮助开发者实现更多更有创意更精彩的特效。</p>
<p>　　<em>整数与位运算指令(Integer and Bitwise Instructions)</em></p>
<p>　　在新的高级着色器语言中添加了&#8220;整数与位指令&#8221;，这样把&#8220;整数与位运算指令&#8221;的操作加入其基础运算函数的好处在于帮助一些算法在GPU上的实现。开发者终于可以直接使用整数而非从浮点中强转来计算出准确的答案。数组的索引号现在可以轻松的计算出来。GPU无整数运算的时代终于被终结了。这将为shader 程序的开发带来很大的便利。</p>
<p>　　<em>Switch 语句(Switch Statement)</em></p>
<p>　　在DirectX 10中， HLSL可以支持switch语句，这将大幅简化那些有着大量判断(分支)的着色器脚本的编码。一种用法就是建立一个&#8220;航母级的着色器(shader) 程序&#8221;——包含了大量的小型着色器程序并且自身体形巨大的着色器程序。在这个&#8220;航母级的着色器程序&#8221;，我们可以通过设定一个材质ID在switch语句中 判断来轻松的在渲染同一个图元时切换不同的特效。也就是说，现在一个军队中的每个士兵身上都可以拥有各自不同的特效了。</p>
<h2>DirectX 10的其他改进</h2>
<p>　　<em>alpha to coverage</em></p>
<p>　　在游戏中，经常使用带有半透明信息纹理的多边形模型来模拟复杂的物体，例如，草、树叶、铁丝网等。如果使用真正的模型，一颗边缘参差不齐的小草可能就要消耗掉几百个多边形；然而采用透明纹理，可以只用2～3个多边形就解决了。</p>
<p align=center><img class=artimg alt=半透明纹理 src="http://www.highdiy.com/upimg/uploadimg/20061112/055643622.gif"><br>透明纹理示意</p>
<p>　　然而，当使用这种有半透明信息的纹理时候，它的不透明和透明部分的边界线上，常常会出现难看的锯齿。采用半透明混合技术可以解决这个问题，但是它需要把场景中所有这类物体按照由远到近的顺序来绘制，才能保证它们的遮挡关系是正确的，这会给CPU带来很大的压力，并不可取。在以前版本的DirectX中，alpha测试和混合简直就是图形程序员的噩梦。</p>
<p>　　在DirectX 10中，使用了一种新的技术叫做Alpha to coverage。使用这种技术，在透明和不透明交界处的纹理像素会被进行多极取样(Multi-sample)，达到抗锯齿的效果。这就在不引入大的性能开销的情况下简单并有效地解决了这个问题。室外场景的游戏将大大受益于这种技术，树叶、铁丝网、草的边缘将会更加柔和、圆滑。</p>
<p align=center><img class=artimg alt="Alpha to coverage效果" src="http://www.highdiy.com/upimg/uploadimg/20061112/055657855.gif"><br>Alpha to coverage效果</p>
<p>　　<em>shadow map filtering</em></p>
<p>　　阴影图(Shadow map)技术已经逐渐成为了渲染真实感阴影的流行技术。在包括《战争机器》、《分裂细胞：双重特工》、《Ghost Recon》、《刺客信条》等的各大次世代游戏中都能看到它的身影。然而，由于shadow map的尺寸限制，用它实现的阴影边缘往往有明显的锯齿。在DirectX 10中，提供了对shadow map进行过滤的功能的正式支持。经过过滤后，阴影的边缘将会变得更加柔和。</p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/25201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-05-31 15:11 <a href="http://www.cppblog.com/yuanyajie/archive/2007/05/31/25201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>const 用法一摘</title><link>http://www.cppblog.com/yuanyajie/archive/2007/05/14/24097.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Mon, 14 May 2007 07:56:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/05/14/24097.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/24097.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/05/14/24097.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/24097.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/24097.html</trackback:ping><description><![CDATA[<p><span style="COLOR: #0000ff">const 引用是指向const 对象的引用</span></p>
<p>const int ival=1024;<br>const int &amp;refVal=ival; //ok,both reference and object are const<br>int&nbsp; &amp;ref2=ival;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //error! non const reference to a const object<br>可以读取但不能修改refVal,因此，任何对refVal的赋值都是不合法的。这个限制有其意义：不能直接对ival同值，因此不能通过使用refVal来修改ival。<br>同理，用ival初始化ref2也是不合法的：ref2是普通的非const引用，因此可以用来修改ref2 指向的对象的值。能过ref2对ival赋值会导致修改const对象的值。为阻止这样的修改，需要<span style="COLOR: #ff00ff">规定将普通的引用绑定到const对象是不合法的。</span></p>
<p><span style="COLOR: #ff00ff">const 引用可以初始化为不同类型的对象或者初始化为右值</span>，如字面值常量：<br>int i=42;<br>// legal for const reference ONLY!<br>const int &amp;r=42;<br>const int &amp;r2=r+i;</p>
<p>double dval=3.14;<br>const int &amp;r3=dval;<br>编译器展开：<br>int temp=dval;<br>const int &amp;ri=temp;</p>
<p><span style="COLOR: #0000ff">非const引用只能绑定到与该引用同类型的对象。<br>const引用则可以绑定到不同但相关的类型的对象或绑定到右值。</span></p>
<p>在C++中真正的临时对象是看不见的，它们不出现在你的源代码中。建立一个没有命名的非堆（non-heap）对象会产生临时对象。这种未命名的对象通常在两种条件下产生：<span style="COLOR: #ff00ff">为了使函数成功调用而进行隐式类型转换和函数返回对象时。</span>理解如何和为什么建立这些临时对象是很重要的，因为构造和释放它们的开销对于程序的性能来说有着不可忽视的影响。<br>首先考虑为使函数成功调用而建立临时对象这种情况。当传送给函数的对象类型与参数类型不匹配时会产生这种情况。</p>
<p>在字符计数的例子里，能够成功传递char数组到countChar中，但是在这里试图用char数组调用upeercasify函数，则不会成功：。考虑一下这个函数：<br>void uppercasify(string&amp; str);<br>char subtleBookPlug[] = "Effective C++";<br>uppercasify(subtleBookPlug); // 错误!<br>没有为使调用成功而建立临时对象，为什么呢？<br>假设建立一个临时对象，那么临时对象将被传递到upeercasify中，其会修改这个临时对象，把它的字符改成大写。但是对subtleBookPlug函数调用的真正参数没有任何影响；仅仅改变了临时从subtleBookPlug生成的string对象。无疑这不是程序员所希望的。程序员传递subtleBookPlug参数到uppercasify函数中，期望修改subtleBookPlug的值。当程序员期望修改非临时对象时，对非常量引用（references-to-non-const）进行的隐式类型转换却修改临时对象。<span style="COLOR: #ff00ff">这就是为什么C++语言禁止为非常量引用（reference-to-non-const）产生临时对象。</span>这样非常量引用（reference-to-non-const）参数就不会遇到这种问题。<br><br><span style="COLOR: #ff00ff">把一个const对象的地址赋给一个普通的，非const对象的指针也会导致编译时错误</span>：<br>const double pi=3.14;<br>double *ptr=&amp;pi;&nbsp;&nbsp; //error:ptr is a plain pointer<br>const double *cptr=&amp;pi;&nbsp; //ok:cptr is a pointer to const</p>
<p><span style="COLOR: #ff00ff">不能使用void*指针保存const 对象的地址，而必须用const void*类型的指针保存。</span><br>const int universe=42;<br>const void *cpv=&amp;universe; //ok;<br>void *pv=&amp;universe;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //error:universe is const</p>
<p><span style="COLOR: #ff00ff">允许把非const 对象的地址赋给指向const 对象的指针</span>：<br>double dval=3.14;<br>cptr=&amp;dval;<br></p>
typedef string *pstring;<br>const pstring cstr;<br>//cstr is a const pointer to string<br><span style="COLOR: #0000ff">string *const cstr&nbsp; ; // equivalent to const pstring cstr; <br></span><br><br>Sales_item成员函数形参表后面的const后面所起的作用:<span style="COLOR: #ff00ff">const 改变了隐含的this 形参的类型</span>。在调用<br>total.same_isbn(trans)时，隐含的this形参将是一个指向total对象的const Sales_item *类型的指针。<br>由于this 是指向const对象的指针，const 成员函数不能修改调用该函数的对象。<br><span style="COLOR: #ff00ff">const 对象，指向const对象的指针或引用只能用于调用其const成员函数，如果尝试用它们调用非<br>const 成员函数</span>，则是错误的。
<img src ="http://www.cppblog.com/yuanyajie/aggbug/24097.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-05-14 15:56 <a href="http://www.cppblog.com/yuanyajie/archive/2007/05/14/24097.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用C++实现的一种插件体系结构-----概述</title><link>http://www.cppblog.com/yuanyajie/archive/2007/04/17/22134.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Tue, 17 Apr 2007 07:54:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/04/17/22134.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/22134.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/04/17/22134.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/22134.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/22134.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/yuanyajie/archive/2007/04/17/22134.html'>阅读全文</a><img src ="http://www.cppblog.com/yuanyajie/aggbug/22134.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-04-17 15:54 <a href="http://www.cppblog.com/yuanyajie/archive/2007/04/17/22134.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>将类成员函数用做C回调函数</title><link>http://www.cppblog.com/yuanyajie/archive/2007/03/30/20945.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Fri, 30 Mar 2007 08:10:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2007/03/30/20945.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/20945.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2007/03/30/20945.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/20945.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/20945.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#0000ff">提出问题：</font>
				<br />回调函数是基于C编程的Windows SDK的技术，不是针对C++的，程序员可以将一个C函数直接作为回调函数，但是如果试图直接使用C++的成员函数作为回调函数将发生错误，甚至编译就不能通过。<br /><font color="#0000ff">分析原因：</font><br />普通的C++成员函数都隐含了一个传递函数作为参数，亦即“this”指针，C++通过传递一个指向自身的指针给其成员函数从而实现程序函数可以访问C++的数据成员。这也可以理解为什么C++类的多个实例可以共享成员函数但是确有不同的数据成员。由于this指针的作用，使得将一个CALLBACK型的成员函数作为回调函数安装时就会因为隐含的this指针使得函数参数个数不匹配，从而导致回调函数安装失败<br /><font color="#0000ff">解决方案：</font><br />一,不使用成员函数，直接使用<font color="#ff1493">普通C函数</font>，为了实现在C函数中可以访问类的成员变量，可以使用友元操作符(friend)，在C++中将该C函数说明为<font color="#ff1493">类的</font><font color="#ff1493">友元</font>即可。这种处理机制与普通的C编程中使用回调函数一样。<br />二,使用<font color="#ff1493">静态成员函数</font>，静态成员函数不使用this指针作为隐含参数，这样就可以作为回调函数了。静态成员函数具有两大特点：其一，可以在没有类实例的情况下使用；其二，只能访问静态成员变量和静态成员函数，不能访问非静态成员变量和非静态成员函数。由于在C++中使用类成员函数作为回调函数的目的就是为了访问所有的成员变量和成员函数，如果作不到这一点将不具有实际意义。我们通过使用静态成员函数对非静态成员函数<font color="#ff1493">包装</font>的办法来解决问题。类实例可以通过<font color="#ff1493">附加参数</font>或<font color="#ff1493">全局变量</font>的方式的方式传递到静态成员函数中。分别举例如下：<br />1，参数传递的方式<br />   #include &lt;iostream.h&gt;   <br />   class TClassA<br />   {<br />   public:</p>
		<p>      void Display(const char* text) { cout &lt;&lt; text &lt;&lt; endl; };<br />      static void Wrapper_To_Call_Display(void* pt2Object, char* text);<br />     <font color="#008000"> // more....</font><br />   };</p>
		<p>  <font color="#008000"> // 静态包装函数，能够调用成员函数Display(),本身做为回调函数来使用</font><br />   void TClassA::Wrapper_To_Call_Display(void* pt2Object, char* string)<br />   {<br />     <font color="#008000">  // 显式类型转换<br /></font>       TClassA* mySelf = (TClassA*) pt2Object;</p>
		<p>    <font color="#008000">   // 调用普通成员函数<br /></font>       mySelf-&gt;Display(string);<br />   }</p>
		<p>   <font color="#008000">// 回调函数的宿主,在这里回调用函数被使用<br /></font>   void DoItA(void* pt2Object, void (*pt2Function)(void* pt2Object, char* text))<br />   {<br />     <font color="#008000"> // 使用回调函数<br /></font>      pt2Function(pt2Object, "hi, i'm calling back using a argument ;-)");  <br />   }</p>
		<p> <font color="#008000">  // 执行示例<br /></font>   void Callback_Using_Argument()<br />   {<br />      TClassA objA;<br />      DoItA((void*) &amp;objA, TClassA::Wrapper_To_Call_Display);<br />   }</p>
		<p>2，全局变量的方式<br />   #include &lt;iostream.h&gt;   <br />   void* pt2Object;      <font color="#008000">  // 全局变量,可以指向任意对象<br /></font>   class TClassB<br />   {<br />   public:</p>
		<p>      void Display(const char* text) { cout &lt;&lt; text &lt;&lt; endl; };<br />      static void Wrapper_To_Call_Display(char* text);</p>
		<p>   };</p>
		<p>
				<font color="#008000">   // 静态的包装函数<br /></font>   void TClassB::Wrapper_To_Call_Display(char* string)<br />   {<br />      <font color="#008000"> //需要保证全局变量值的正确性<br /></font>       TClassB* mySelf = (TClassB*) pt2Object;<br />       mySelf-&gt;Display(string);<br />   }</p>
		<p> <font color="#008000">  // 回调用函数的宿主,在这里回调用函数被使用<br /></font>   void DoItB(void (*pt2Function)(char* text))<br />   {<br />   <br />      pt2Function("hi, i'm calling back using a global ;-)");   // make callback<br />   }</p>
		<p>   // 执行示例<br />   void Callback_Using_Global()<br />   {<br />      TClassB objB;  <br />      pt2Object = (void*) &amp;objB;<br />      DoItB(TClassB::Wrapper_To_Call_Display);<br />   }</p>
		<p>注意：通过上面两种方法的比较可以看出，第2种方法中静态包装函数可以和普通成员函数保持签名一致，当回调函数的宿主<font color="#ff1493">接口不能改变</font>时，这种方法<font color="#ff1493">特别有用</font>。但因为使用了全局变量，也不是一个好的设计。</p>
		<p> </p>
		<p>
				<br /> </p>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/20945.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2007-03-30 16:10 <a href="http://www.cppblog.com/yuanyajie/archive/2007/03/30/20945.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>game c++</title><link>http://www.cppblog.com/yuanyajie/archive/2006/12/27/16910.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Wed, 27 Dec 2006 07:35:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2006/12/27/16910.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/16910.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2006/12/27/16910.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/16910.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/16910.html</trackback:ping><description><![CDATA[一般而言，比起C程序来说，C++游戏程序是可重用和可维护的。可这真的有价值吗？复杂的C++可以在速度上与传统的C程序相提并论吗？<br />　　如果有一个好的编译器，再加上对语言的了解，真的有可能用C++写出一些有效率的游戏程序来。本文描述了典型的几种你可以用来加速游戏的技术。它假设你已经非常肯定使用C++的好处，并且你也对优化的基本概念相当熟悉。<br />　　第一个经常让人获益的基本概念显然是剖析（profiling）的重要性。缺乏剖析的话，程序员将犯两种错误，其一是优化了错误的代码：如果一个程序的主要指标不是效率，那么一切花在使其更高效上的时间都是浪费。靠直觉来判断哪段代码的主要指标是效率是不可信的，只有直接去测量。第二个概念是程序员经常 "优化"到降低了代码的速度。这在C++是一个典型问题，一个简单的指令行可能会产生巨大数量的机器代码，你应当经常检查你的编译器的输出，并且剖析之。<br />1、对象的构造与析构<br />　　对象的构造与析构是C++的核心概念之一，也是编译器背着你产生代码的一个主要地方。未经认真设计的程序经常花费不少时间在调用构造函数，拷贝对象以及初始化临时对象等等。幸运的是，一般的感觉和几条简单的规则可以让沉重的对象代码跑得和C只有毫厘之差。<br />　　除非需要否则不构造。<br />　　最快的代码是根本不运行的代码。为什么要创建一个你根本不去使用的对象呢？在后面的代码中：<br /><br />　　voide Function(int arg)<br />　　{<br />　　　　Object boj;<br />　　　　If(arg==0)<br />　　　　　　Return;<br />　　　　...<br />　　}<br /><br />　　即便arg为0，我们也付出了调用Object的构造函数的代价。特别是如果arg经常是0，并且Object本身还分配内存，这种浪费会更加严重。显然的，解决方案就是把obj的定义移到判断之后。<br />　　小心在循环中定义复杂变量，如果在循环中按照除非需要否则不构造的原则构造了复杂的对象，那么你在每一次循环的时候都要付出一次构造的代价。最好在循环外构造之以只构造一次。如果一个函数在内循环中被调用，而该函数在栈内构造了一个对象，你可以在外部构造并传递一个应用给它。<br /><br />　　1.1 采用初始化列表<br />　　考虑下面的类：<br /><br />　　class Vehicle<br />　　{<br />　　public<br />　　　　Vehicle(const std::string &amp;name)<br />　　　　{<br />　　　　　　mName=name<br />　　　　}<br />　　private:<br />　　　　std::string mName;<br />　　}<br /><br />　　因为成员变量会在构造函数本体执行前构造，这段代码调用了string mName的构造函数，然后调用了一个=操作符，来拷贝其值。这个例子中的一个典型的不好之处在于string的缺省构造函数会分配内存，但实际上都会分配大大超过实际需要的空间。接下来的代码会好些，并且阻止了对=操作符的调用，进一步的来说，因为给出了更多的信息，非缺省构造函数会更有效，并且编译器可以在构造函数函数体为空的情况下将其优化掉。<br /><br />　　class Vehicle<br />　　{<br />　　public<br />　　　　Vehicle(const std::string &amp;name):mName(name)<br />　　　　{ }<br />　　private:<br />　　　　std::string mName;<br />　　}<br /><br />　　1.2 要前自增不要后自增（即要++I不要I++）<br />　　当写x=y++时产生的问题是自增功能将需要制造一个保持y的原值的拷贝，然后y自增，并把原始的值返回。后自增包括了一个临时对象的构造，而前自增则不要。对于整数，这没有额外的负担，但对于用户自定义类型，这就是浪费，你应该在有可能的情况下运用前自增，在循环变量中，你会常遇到这种情形。<br />　　不使用有返回值的操作符 在C++中经常看到这样写顶点的加法：<br /><br />　　Vector operator+(const Vector &amp;v1,const Vector &amp;v2)<br /><br />　　这个操作将引起返回一个新的Vector对象，它还必须被以值的形式返回。虽然这样可以写v=v1+v2这样的表达式，但象构造临时对象和对象的拷贝这样的负担，对于象顶点加法这样常被调用的事情来说太大了一点。有时候是可以好好规划代码以使编译器可以把临时对象优化掉（这一点就是所谓的返回值优化）。但是更普遍的情形下，你最好放下架子，写一点难看但更快速的代码：<br /><br />　　void Vector::Add(const Vector &amp;v1,const Vector &amp;v2)<br /><br />　　注意+=操作符并没有同样的问题，它只是修改第一个参数，并不需要返回一个临时对象，所以，可能的情况下，你也可以用+=代替+。<br /><br />　　1.3 使用轻量级的构造函数<br />　　在上一个例子中Vector的构造函数是否需要初始化它的元素为0？这个问题可能在你的代码中会有好几处出现。如果是的话，它使得无论是否必要，所有的调用都要付初始化的代价。典型的来说，临时顶点以及成员变量就会要无辜的承受这些额外的开销。<br />　　一个好的编译器可以很好的移除一些这种多余的代码，但是为什么要冒这个险呢？作为一般的规则，你希望构造函数初始化所有的成员变量，因为未初始化的数据将产生错误。但是，在频繁实例化的小类中，特别是一些临时对象，你应该准备向效率规则妥协。首选的情况就是在许多游戏中有的vector和Matrix 类，这些类显然应当提供一些方法置0和识别，但它的缺省构造函数却应当是空的。<br />　　这个概念的推论就是你应当为这种类提供另一个构造函数。如果我们的第二个例子中的Vebicle类是这样写的话：<br /><br />　　class Vehicle<br />　　{<br />　　public:<br />　　　　vehicle()<br />　　　　{<br />　　　　}<br />　　　　void SetName(const std::string &amp;name)<br />　　　　{<br />　　　　　　mName=name;<br />　　　　}<br />　　private:<br />　　　　std::string mName<br />　　};<br /><br />　　我们省去了构造mName的开销，而在稍后用SetName方法设置了其值。相似的，使用拷贝构造函数将比构造一个对象然后用=操作符要好一些。宁愿这样来构造：Vebicle V1(V2)也不要这样来构造：<br /><br />　　Vehicle v1;v1=v2;<br /><br />　　如果你需要阻止编译器帮你拷贝对象，把拷贝构造函数和操作符=声明为私有的，但不要实现其中任何一个。这样，任何企图对该对象的拷贝都将产生一个编译时错误。最好也养成定义单参数构造函数的习惯，除非你是要做类型转换。这样可以防止编译器在做类型转换时产生的隐藏的临时对象。<br /><br />　　1.4 预分配和Cache对象<br />　　一个游戏一般会有一些类会频繁的分配和释放，比如武器什么的。在C程序中，你会分配一个大数组然后在需要的时候使用。在C++中，经过小小的规划以后，你也可以这样干。这个方法是不要一直构造和析构对象而是请求一个新而把旧的返回给Cache。Cache可以实现成一个模板，它就可以为所有的有一个缺省构造函数的类工作。Cache模板的Sample可以在附带的CD中找到。<br />　　你也可以在需要时分配一些对象来填充Cache，或者预先分配好。如果你还要对这些对象维护一个堆栈的话（表示在你删除对象X之前，你先要删除所有在X后面分配的对象），你可以把Cache分配在一个连续的内存块中。<br /><br />2、内存管理<br />　　C++应用程序一般要比C程序更深入到内存管理的细节。在C中，所有的分配都简单的通过malloc和free来进行，而C++则还可以通过构造临时对象和成员变量来隐式的分配内存。很多C++游戏程序需要自己的内存管理程序。由于C++游戏程序要执行很多的分配，所以要特别小心堆的碎片。一个方法是选择一条复杂的路：要么在游戏开始后根本不分配任何内存，要么维护一个巨大的连续内存块，并按期释放（比如在关卡之间）。在现代机器上，如果你想对你的内存使用很警惕的话，很严格的规则是没必要的。<br />　　第一步是重载new和 Delete操作符，使用自己实现的操作符来把游戏最经常的内存分配从malloc定向到预先分配好的内存块去，例如，你发现你任何时候最多有10000 个4字节的内存分配，你可以先分配好40000字节，然后在需要时引用出来。为了跟踪哪些块是空的，可以维护一个由每一个空的块指向下一个空的块的列表 free list。在分配的时候，把前面的block移掉，在释放的时候，把这个空块再放到前面去。图1描述了这个free list如何在一个连续的内存块中，与一系列的分配和释放协作的情形。<br /><br /><br />图1 A linked free list <br />[img]http://mays.soage.com/develop/optimize/200112/image/Other/OptFORCGame.gif[/img]<br /><br />　　你可以很容易的发现一个游戏是有着许多小小的生命短暂的内存分配，你也许希望为很多小块保留空间。为那些现在没有使用到的东西保留大内存块会浪费很多内存。在一定的尺寸上，你应当把内存分配交给一支不同的大内存分配函数或是直接交给malloc()。<br /><br />3、虚函数<br />　　C++游戏程序的批评者总是把矛头对准虚函数，认为它是一个降低效率的神秘特性。概念性的说，虚函数的机制很简单。为了完成一个对象的虚函数调用，编译器访问对象的虚函数表，获得一个成员函数的指针，设置调用环境，然后跳转到该成员函数的地址上。相对于C程序的函数调用，C程序则是设置调用环境，然后跳转到一个既定的地址上。一个虚函数调用的额外负担是虚函数表的间接指向；由于事先并不知道将要跳转的地址，所以也有可能造成处理器不能命中Cache。<br />　　所有真正的C++程序都对虚函数有大量的使用，所以主要的手段是防止在那些极其重视效率的地方的虚函数调用。这里有一个典型的例子：<br /><br />　　Class BaseClass<br />　　{<br />　　public:<br />　　　　virtual char *GetPointer()=0;<br />　　};<br /><br />　　Class Class1: public BaseClass<br />　　{<br />　　　　virtual char *GetPointer();<br />　　};<br /><br />　　Class Class2:public BaseClass<br />　　{<br />　　　　virtual char *GetPointer();<br />　　};<br /><br />　　void Function(BaseClass *pObj)<br />　　{<br />　　　　char *ptr=pObj-&gt;GetPointer();<br />　　}<br /><br />　　如果Function()极其重视效率，我们应当把GetPointer从一个虚函数改成内联函数。一种方式是给BaseClass增加一个新的保护的数据成员，在每一个类中设置该成员的值，在GetPointer这个内联函数中返回该成员给调用者：<br /><br />　　Class BaseClass<br />　　{<br />　　public:<br />　　　　inline char GetPointerFast()<br />　　　　{<br />　　　　　　return mpPointer;<br />　　　　}<br />　　protected:<br />　　　　inline void SetPointer(char *pData)<br />　　　　{<br />　　　　　　mpData = pData;<br />　　　　}<br />　　private:<br />　　　　char *mpData;<br />　　};<br /><br />　　void Function(BaseClass *pObj)<br />　　{<br />　　　　char *ptr= pObj-&gt;GetPointerFast();<br />　　}<br /><br />　　一个更激进的方法是重新规划你的类继承树，如果Class1和Class2只有一点点不同，那么可以把它们捆绑到同一个类中去，而用一个Flag来表明它将象Class1还是象Class2一样工作，同时在BaseClass中把纯虚函数去掉。这样的话，也可以象前面的例子一样把GetPointer写成内联。这种变通看起来不是很高雅，但是在缺少Cache的机器上跑内循环时，你可能会很愿意为了去掉虚函数调用而把事情做得更加难看。<br />　　虽然每一个新的虚函数都只给每个类的虚表增加了一个指针的尺寸（通常是可以忽略的代价），第一个虚函数还是在每一个对象上要求了一个指向虚表的指针。这就是说你在很小的、频繁使用的类上使用任何虚函数而造成了额外的负担，这些都是不能接受的。由于继承一般都要用到一个或几个虚函数（至少有一个虚的析构函数），所以你没必要在小而频繁使用的对象上使用任何继承。<br /><br />4、代码尺寸<br />　　编译器因为C++产生冗长的代码而臭名昭著。由于内存有限，而小的东西往往是快的，所以使你的可执行文件尽可能的小是非常重要的。首先可以做的事情是拿一个编译器来研究。如果你的编译器会在可执行文件中保存 Debug信息的话，那么把它们移除掉。（注意MS VC会把Debug信息放在可执行文件外部，所以没关系）异常处理会产生额外的代码，尽可能的去除异常处理代码。确保连接器配置为去除无用的函数和类。开启编译器的最高优化级别，并尝试设置为尺寸最小化而不是速度最大化 — 有时候，由于Cache命中的提高，会产生更好的运行效果。（注意在使用这项设置时检查instrinsic功能是否也处于打开状态）去掉所有Debug 输出状态下的浪费空间的字符串，使编译器把多个相同的字符串捆绑成一个实例。<br />　　内联通常是造成大函数的首犯。编译器可以自由的选择注意或忽略你写的inline关键字，而且它们还会背着你制造一些内联。这是另一个要你保持轻量级的构造函数的原因，这样堆栈中的对象就不会因为有大量的内联代码而膨胀。同时也要小心重载运算符，即使是最简短的表达式如m1=m2*m3如果m2和m3是矩阵的话，也可能产生大量的内联代码。一定要深入了解你的编译器对于内联的设置。<br />　　启用运行时类型信息（RTTI）需要编译器为每一个类产生一些静态信息。RTTI一般来说是缺省启用的，这样我们的代码可以调用dynamic_cast以及检测一个对象的类型，考虑完全禁止使用RTTI和dynamic_cast以节省空间（进一步的说，有时候 dynamic_cast在某些实现中需要付出很高的代价）另一方面，当你真的需要有基于类型的不同行为的时候，增加一个不同行为的虚函数。这是更好的面向对象设计（注意static_cast与这不同，它的效率和C语言的类型转换一样）。<br /><br />5、标准类库（STL）<br />　　标准类库是一套实现了常见的结构和算法的模板，例如dynamic arrays（称为vector），set，map等等。使用STL可以节省你很多时间来写和调试那些容器。和之前谈到的一样，如果希望系统的效率最大化，你必须要注意你的STL的具体实现的细节。<br />　　为了能够对应于最大范围的应用，STL标准在内存分配这个领域保持了沉默。在STL容器中的每一个操作都有一定的效率保证，例如，给一个set进行插入操作只要O(log n)的时间，但是，对一个容器的内存使用没有任何保证。<br />　　让我们来仔细了解游戏开发中的一个非常普遍的问题：你希望保存一组对象，（我们会称其为对象列表，虽然不一定要保存在STL的列表中）通常你会要求每个对象在这个表有且仅有一个，这样你就不用担心一个偶然产生的在容器中插入一个已存在单元的操作了。STL的set忽略副本，所有的插入、删除和查询的速度都是O(log n)，这是不是就是很好的选择呢？<br />　　虽然在set上的大多数操作的速度都是O(log n)，但是这里面依然存在着潜在的危机。虽然容器的内存使用依赖于实现，但很多实现还是在红黑树的基础上实现的。在红黑树上，树的每一个节点都是容器的一个元素。常见的实现方法是在每一个元素被加入到树时，分配一个节点，而当每个元素被移出树时，释放一个节点。根据你插入和删除的频繁程度，在内存管理器上所花费的时间将或多或少的影响你通过使用set而获得的好处。<br />　　另外一个解决方案是使用vector来存储元素，vector保证在容器的末端添加元素有很高的效率。这表示实际上vector只在很偶然的情况下才重新分配内存，也就是说，当满的时候扩容一倍。当使用vector来保存一个不同元素列表的时候，你首先要检查元素是否已经存在，如果没有，那么加入。而对整个vector检查一遍需要花费O(n)的时间，但是但实际牵涉到的部分应该比较少，这是因为vector的每个元素都在内存中连续存放，所以检查整个vector实际上是一个易于cache的操作。检查整个set将造成cache 不命中，这是因为在红黑树上分别存放的元素可能散布在内存的各个角落。同时，我们也注意到set必须额外维护一组标记以设置整个树。如果你要保存的是对象的指针，set可能要花费vector所要花费的内存的3到4倍。<br />　　Set的删除操作消耗时间O(log n)，看起来是很快，如果你不考虑可能对free()的调用的话。Vector的删除操作消耗O(n)，这是因为从被删除的那个元素开始到结尾处的元素，每一个元素都要被拷贝到前一个位置上。如果元素都只是指针的话，那么这个拷贝将可以依靠一个简单的memcpy()来完成，而这个函数是相当快的。（这也是为什么通常都把对象的指针储存在STL的容器中的一个原因，而不是储存对象本身。如果你直接保存了对象本身，将会在很多操作中造成许多额外的构造函数的调用，例如删除等）。<br />　　set和map通常来说麻烦大于有用，如果你还没有意识到这一点的话，考虑遍历一个容器的代价，例如：<br /><br />　　for(Collection::iterator it = Collection.begin(); it != Collection.end(); ++it)<br /><br />　　如果Collection是vector，那么++it就是一个指针自增。但是当Collection是一个set或者是一个map的话，++it包括了访问红黑树上的下一个节点。这个操作相当复杂而且很容易造成cache不命中，因为树的节点几乎遍布内存的各处。<br />　　当然，如果你要在容器中保存大量的元素，并且进行许多的成员请求，那么set的O(log n)的效率完全可以抵消那些内存方面的消耗。近似的，如果你偶尔才使用容器，那么这里的效率差别就非常的小。你应该做一些效率评估以了解多大的n会使 set变得更快。也许你会惊奇的发现在游戏的大多数典型应用下vector的所有效率都比set要高。<br />　　这还不是STL内存使用的全部。一定要了解当你使用clear方法时，容器是否真的释放掉了它的内存。如果没有，就可能产生内存碎片。比如，如果你开始游戏的时候建立了一个空的vector，在游戏过程中增加元素，然后在游戏restart时调用clear，这时vector未必释放它的全部内存。这个空的vector，可能依然占据了堆中的内存，并使其变成碎片。如果你真的需要这样来实现游戏的话，对这个问题有两种解法。一是你可以在创建vector时调用reserve()，为你可能需要的最大数量的元素保留足够的空间。如果这不可行的话，你可以强迫vector完全释放内存：<br /><br />　　Vector V;<br />　　// ... elements are inserted into V here<br />　　Vector().swap(v);　　// causes v to free its memory<br /><br />　　Set、list以及map都没有这个问题，这是因为他们为每个元素分别分配和释放内存。<br /><br />6、高级特性<br />　　编程语言的某些特性你可能没必要用到。看上去简单的特性可能会导致低下的效率。而看起来复杂的特性没准执行得很好。C++的这些黑暗角落异常依赖于编译器。当你要使用它们时，必须了解它们的代价。<br />　　C++的string就是一个看起来不错的例子，但是在效率极其重要的场合应该避免使用，考虑下面的代码。<br /><br />　　Void Function(const std::string &amp;str)<br />　　{<br />　　}<br />　　Function("hello");<br /><br />　　对Function()的调用包括了对给定const char*参数的构造函数的调用。在普遍的实现中，这个构造函数执行了一个malloc()，一个strlen()，以及一个memcpy()，而析构函数立刻上来做了一些无意义的事情。（由于该例子中的string没有被更多的应用）然后又跟了一个free()。这里的内存分配完全是浪费，因为字符串 "hello"早就在程序的数据段中了。我们早就有它在内存中的副本了。如果Function定义了一个const char*的参数，那么完全没有了上面所说的那些额外的调用。这就是为了使用方便的string而付出的高昂代价。<br />　　模板是效率的对立面的一个例子，根据语言标准，编译器在模板实例化为一个具体的类型时产生代码。理论上，看上去是声明了一个模板，但却实际产生了大量的相似的代码。如果你有了 class1的指针的vector，也有class2的指针的vector，你就在你的可执行文件中做了两份的vector的拷贝。<br />　　事实上，大多数的编译器做得更好，首先，只有实际被使用到的模板成员函数被产生代码。其次，如果事先了解了正确的行为，编译器可以只产生一份代码的拷贝。你可以从vector的例子发现这一点，确实只产生了一份代码（一般是vector）。有了好的编译器，模板还是可以在保持高效的同时提供你一般编程的好处。<br />　　C++的一些特性，比如初始化列表以及前自增，一般来说可以提高效率。而象其它的一些特性比如运算符重载以及RTTI则看起来似乎是清白的，但却有时带来严重的效率问题。STL的容器则描述了盲目相信函数的算法运行时间可以如何让你误入歧途。避免使用潜在的低效率的语言或类库特性，同时花些时间来了解你的编译器的各种选项。你会很快的学会设计高效的代码，并且解决掉你的游戏中的效率问题。<br /><img src ="http://www.cppblog.com/yuanyajie/aggbug/16910.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2006-12-27 15:35 <a href="http://www.cppblog.com/yuanyajie/archive/2006/12/27/16910.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> (转）剖析C++标准库智能指针(std::auto_ptr) </title><link>http://www.cppblog.com/yuanyajie/archive/2006/12/15/16489.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Fri, 15 Dec 2006 09:35:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2006/12/15/16489.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/16489.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2006/12/15/16489.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/16489.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/16489.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1.Do you Smart Pointer?		      Smart Pointer,中文名：智能指针, 舶来品?      不可否认,资源泄露(resource leak)曾经是C++程序的一大噩梦.垃圾回收      机制(Garbage Collection)一时颇受注目.然而垃圾自动回收机制并不能      满足内存管理的即时性和可视性,往往使高傲的程序设计者感到不自在.     ...&nbsp;&nbsp;<a href='http://www.cppblog.com/yuanyajie/archive/2006/12/15/16489.html'>阅读全文</a><img src ="http://www.cppblog.com/yuanyajie/aggbug/16489.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2006-12-15 17:35 <a href="http://www.cppblog.com/yuanyajie/archive/2006/12/15/16489.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何将float转换为string </title><link>http://www.cppblog.com/yuanyajie/archive/2006/12/15/16476.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Fri, 15 Dec 2006 03:18:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2006/12/15/16476.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/16476.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2006/12/15/16476.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/16476.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/16476.html</trackback:ping><description><![CDATA[
		<div class="post">
				<div class="postTitle"> </div>
				<div class="postText">
						<p>     可能有好多人，包括C语言老手都不知道如何将float数据转换为string，我就是这样，今天查了一下MSDN，才知道C提供了_gcvt函数实现这个功能，收获着实不小，为了方便自己查询，也为了那些像我这样的网友能够了解该函数的具体用法，我把MSDN的原文原封不动抄录如下：</p>
						<p>
								<font face="Verdana" size="2">
								</font>
						</p>
						<h1>
								<a name="_crt__gcvt">
								</a>
								<sup>
								</sup>_gcvt</h1>
						<p>Converts a floating-point value to a string, which it stores in a buffer.</p>
						<p>
								<strong>char</strong>
								<strong>*_gcvt(</strong>
								<strong>double</strong>
								<em>value</em>
								<strong>,</strong>
								<strong>int</strong>
								<em>digits</em>
								<strong>,</strong>
								<strong>char</strong>
								<strong>*</strong>
								<em>buffer</em>
								<strong>);</strong>
						</p>
						<p>
						</p>
						<table cols="3" cellpadding="5" rules="rows" border="1" frame="below">
								<tbody>
										<tr valign="top">
												<td class="label" width="16%">
														<strong>Routine</strong>
												</td>
												<td class="label" width="27%">
														<strong>Required Header</strong>
												</td>
												<td class="label" width="57%">
														<strong>Compatibility</strong>
												</td>
										</tr>
										<tr valign="top">
												<td width="16%">
														<strong>_gcvt</strong>
												</td>
												<td width="27%">&lt;stdlib.h&gt;</td>
												<td width="57%">Win 95, Win NT</td>
										</tr>
								</tbody>
						</table>
						<br />
						<p>For additional compatibility information, see <a href="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN98\98VS\2052\vccore.chm::/html/_crt_compatibility.htm">Compatibility</a> in the Introduction.</p>
						<p class="label">
								<strong>Libraries</strong>
						</p>
						<p>
						</p>
						<table cols="2" cellpadding="5" rules="rows" border="1" frame="below">
								<tbody>
										<tr valign="top">
												<td width="24%">LIBC.LIB</td>
												<td width="76%">Single thread static library, retail version</td>
										</tr>
										<tr valign="top">
												<td width="24%">LIBCMT.LIB</td>
												<td width="76%">Multithread static library, retail version</td>
										</tr>
										<tr valign="top">
												<td width="24%">MSVCRT.LIB</td>
												<td width="76%">Import library for MSVCRT.DLL, retail version</td>
										</tr>
								</tbody>
						</table>
						<br />
						<p class="label">
								<strong>Return Value</strong>
						</p>
						<p>
								<strong>_gcvt</strong> returns a pointer to the string of digits. There is no error return.</p>
						<p class="label">
								<strong>Parameters</strong>
						</p>
						<p class="dt">
								<em>value</em>
						</p>
						<p class="indent">Value to be converted</p>
						<p class="dt">
								<em>digits</em>
						</p>
						<p class="indent">Number of significant digits stored</p>
						<p class="dt">
								<em>buffer</em>
						</p>
						<p class="indent">Storage location for result</p>
						<p class="label">
								<strong>Remarks</strong>
						</p>
						<p>The <strong>_gcvt</strong> function converts a floating-point <em>value</em> to a character string (which includes a decimal point and a possible sign byte) and stores the string in <em>buffer</em>. The <em>buffer</em> should be large enough to accommodate the converted value plus a terminating null character, which is appended automatically. If a buffer size of <em>digits</em> + 1 is used, the function overwrites the end of the buffer. This is because the converted string includes a decimal point and can contain sign and exponent information. There is no provision for overflow. <strong>_gcvt</strong> attempts to produce <em>digits</em> digits in decimal format. If it cannot, it produces <em>digits</em> digits in exponential format. Trailing zeros may be suppressed in the conversion.</p>
						<p class="label">
								<strong>Example</strong>
						</p>
						<pre>
								<code>/* _GCVT.C: This program converts -3.1415e5 * to its string representation. */#include &lt;stdlib.h&gt;#include &lt;stdio.h&gt;void main( void ){   char buffer[50];   double source = -3.1415e5;   _gcvt( source, 7, buffer );   printf( "source: %f  buffer: '%s'\n", source, buffer );   _gcvt( source, 7, buffer );   printf( "source: %e  buffer: '%s'\n", source, buffer );}</code>
						</pre>
						<p class="label">
								<strong>Output</strong>
						</p>
						<pre>
								<code>source: -314150.000000  buffer: '-314150.'source: -3.141500e+005  buffer: '-314150.'</code>
						</pre>
						<br />
						<br />
						<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=708935</p>
						<br />
				</div>
				<div class="postFoot">
						<script src="http://localhost:82/PromoteIcon.aspx?id=708935">
						</script>
[<a title="功能强大的网络收藏夹，一秒钟操作就可以轻松实现保存带来的价值、分享带来的快乐" href="javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(saveit=window.open('http://wz.csdn.net/storeit.aspx?t='+escape(d.title)+'&amp;u='+escape(d.location.href)+'&amp;c='+escape(t),'keyit','scrollbars=no,width=590,height=300,left=75,top=20,status=no,resizable=yes'));saveit.focus();">收藏到我的网摘</a>]   skyman_2001发表于 2006年05月05日 11:28:00 </div>
		</div>
		<link href="http://blog.csdn.net/skyman_2001/Services/Pingback.aspx" rel="pingback" />
		<!--<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"xmlns:dc="http://purl.org/dc/elements/1.1/"xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"><rdf:Descriptionrdf:about="http://blog.csdn.net/skyman_2001/archive/2006/05/05/708935.aspx"dc:identifier="http://blog.csdn.net/skyman_2001/archive/2006/05/05/708935.aspx"dc:title="如何将float转换为string"trackback:ping="http://tb.blog.csdn.net/TrackBack.aspx?PostId=708935" /></rdf:RDF>-->
		<script><![CDATA[unction hide(){showComment();}]]&gt;</script>
		<br />
		<br />
		<div class="post" id="csdn_zhaig_ad_yahoo">
		</div>
		<span id="Anthem_Comments.ascx_ltlComments__">
				<span id="Comments.ascx_ltlComments">
						<br />
						<div id="comments">
								<h3>
								</h3>
								<div class="post">
										<div class="postTitle">
												<a title="permalink: 回复：如何将float转换为string" href="http://blog.csdn.net/skyman_2001/archive/2006/05/05/708935.aspx#439785">#</a> <a name="439785"> </a>lanno 发表于2006-05-05 18:26:00  IP: 222.35.68.*</div>
										<div class="postText">长见识了，俺总是这样转化的： <br />char str[260]; <br />float f = -3.1415926; <br />float f1 = 263e-5; <br />sprintf(str,"%f",f); <br />printf("%s\n",str); <br />sprintf(str,"%f",f1); <br />printf("%s\n",str);</div>
								</div>
								<br />
								<div class="post">
										<div class="postTitle">
												<a title="permalink: 回复：如何将float转换为string" href="http://blog.csdn.net/skyman_2001/archive/2006/05/05/708935.aspx#439808">#</a> <a name="439808"> </a>Skyman 发表于2006-05-05 21:35:00  IP: 202.202.10.*</div>
										<div class="postText">你这样做也行 <br />但没有这样灵活 <br />是吧？</div>
								</div>
								<br />
								<div class="post">
										<div class="postTitle">
												<a title="permalink: 回复：如何将float转换为string" href="http://blog.csdn.net/skyman_2001/archive/2006/05/05/708935.aspx#441872">#</a> <a name="441872"> </a>zhnde 发表于2006-05-11 20:15:00  IP: 129.69.212.*</div>
										<div class="postText">灵活吗？ 能具体解释一下吗？</div>
								</div>
								<br />
								<div class="post">
										<div class="postTitle">
												<a title="permalink: 回复：如何将float转换为string" href="http://blog.csdn.net/skyman_2001/archive/2006/05/05/708935.aspx#441903">#</a> <a name="441903"> </a>Skyman 发表于2006-05-11 22:03:00  IP: 202.202.10.*</div>
										<div class="postText">至少可以方便的控制有效数字的位数啊。</div>
								</div>
								<br />
								<div class="post">
										<div class="postTitle">
												<a title="permalink: 回复：如何将float转换为string" href="http://blog.csdn.net/skyman_2001/archive/2006/05/05/708935.aspx#468774">#</a> <a name="468774"> </a><a href="/ztwaker/" target="_blank" rel="nofollow">ztwaker</a> 发表于2006-07-28 12:40:00  IP: 61.144.207.*</div>
										<div class="postText">/*C++ impl*/ <br />string cvt(const float fval) <br />{ <br />stringstream ss; <br />ss &lt;&lt; fval; <br />return ss.str(); <br />} <br /><br />......///</div>
								</div>
								<br />
								<div class="post">
										<div class="postTitle">
												<a title="permalink: 回复：如何将float转换为string" href="http://blog.csdn.net/skyman_2001/archive/2006/05/05/708935.aspx#468778">#</a> <a name="468778"> </a><a href="/ztwaker/" target="_blank" rel="nofollow">ztwaker</a> 发表于2006-07-28 12:46:00  IP: 61.144.207.*</div>
										<div class="postText">加上有效数字位数控制 <br /><br />string cvt(const float f, const int prec) <br />{ <br />stringstream ss; <br />ss.precision(prec); <br />ss &lt;&lt; f; <br />return ss.str(); <br />}</div>
								</div>
								<br />
						</div>
				</span>
		</span>
		<script language="javascript"><![CDATA[
ad_width=468;
ad_height=60;
adcss=2;
unionuser=19;
ad_type='j';
count=5; 
]]&gt;</script>
		<script language="javascript" src="http://tagegg.csdn.net/showads.js" type="text/javascript">
		</script>
		<script language="JavaScript1.1" src="http://tagegg.csdn.net/a.aspx?action=displayad&amp;unionuser=19&amp;unionurl=http%3A%2F%2Fblog.csdn.net%2Fskyman_2001%2Farchive%2F2006%2F05%2F05%2F708935.aspx&amp;adcss=2&amp;ad_type=j&amp;width=468&amp;height=60&amp;ad_color=&amp;ad_color_border=&amp;count=5">
		</script>
		<script language="javascript" src="/js/showgm.js" type="text/javascript">
		</script>
		<script type="text/javascript"><![CDATA[ocument.write("<img src=http://counter.csdn.net/pv.aspx?id=24 border=0 width=0 height=0>");]]&gt;</script>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/16476.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2006-12-15 11:18 <a href="http://www.cppblog.com/yuanyajie/archive/2006/12/15/16476.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>头文件包含问题</title><link>http://www.cppblog.com/yuanyajie/archive/2006/12/14/16445.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Thu, 14 Dec 2006 10:16:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2006/12/14/16445.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/16445.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2006/12/14/16445.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/16445.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/16445.html</trackback:ping><description><![CDATA[
		<div class="postTitle">
				<a href="http://blog.csdn.net/sumless/articles/855694.aspx">
						<img height="13" src="http://blog.csdn.net/images/zhuan.gif" width="15" border="0" /> C++中基础类互相引用带来的问题</a>
		</div>
		<div class="postText">
				<p>
						<font size="3">在一些大的工程中，可能会包含几十个基础类，免不了之间会互相引用</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">(</span>
						</font>
						<font size="3">不满足继承关系，而是组合关系</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">)</span>
						</font>
						<font size="3">。也就是需要互相声明。好了，这时候会带来一些混乱。如果处理得不好，会搞得一团糟，根据我的经验，简单谈谈自已的处理办法：</font>
				</p>
				<p>
						<font size="3">编码时，我们一般会尽量避免</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">include</span>
						</font>
						<font size="3">头文件，而是采用声明 </font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">class XXX</span>
						</font>
						<font size="3">。</font>
						<font size="3">但有时候还是必须用</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">Include</span>
						</font>
						<font size="3">头文件，那么，两者的划分在于什么呢？</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />
										<br />
								</span>
						</font>
						<font size="3">应该是很明确的，但书上好像都少有提及。</font>
				</p>
				<p>
						<font size="3">首先：</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />
								</span>
						</font>
						<font size="3">我们要明白为什么要用声明取代头文件包含：对了，是为了避免无必要的重编译</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">(</span>
						</font>
						<font size="3">在头文件发生变更时</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">)</span>
						</font>
						<font size="3">。</font>
						<font size="3">工程较大，低速机，或基础类经常变更</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">(</span>
						</font>
						<font size="3">不合理的设计吧</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">)</span>
						</font>
						<font size="3">，编译速度还是会在意的，</font>
						<font size="3">另外，更为重要的是，采用声明可降低代码</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">(class)</span>
						</font>
						<font size="3">之间的藕合度，这也是面向对象设计的一大原则。</font>
				</p>
				<p>
						<font size="3">二：一般原则：</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />a. </span>
						</font>
						<font size="3">头文件中尽量少</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">include, </span>
						</font>
						<font size="3">如果可以简单申明 </font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">class clsOld; </span>
						</font>
						<font size="3">解决，那最好。减少没有必要的</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">include；<br />b. </span>
						</font>
						<font size="3">实现文件中也要尽量少</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">include,</span>
						</font>
						<font size="3">不要</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">include</span>
						</font>
						<font size="3">没有用到的头文件。 </font>
				</p>
				<p>
						<font size="3">三：那什么时候可以只是简单声明</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">class clsOld</span>
						</font>
						<font size="3">呢？</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />
								</span>
						</font>
						<font size="3">简单的说：不需要知道</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">clsOld</span>
						</font>
						<font size="3">的内存布局的用法都可以</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">(</span>
						</font>
						<font size="3">静态成员除外</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">)</span>
						</font>
						<font size="3">，也就是讲如果是指针或引用方式的</font>
						<font size="3">都行。</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />
								</span>
						</font>
						<font size="3">比如：</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />   clsOld * m_pOld;    //</span>
						</font>
						<font size="3">指针占</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">4</span>
						</font>
						<font size="3">个字节长</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />   clsOld &amp; test(clsOld * pOld) {return *pOld};<br />  </span>
						</font>
						<font size="3">一切</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">OK</span>
						</font>
						<font size="3">。</font>
				</p>
				<p>
						<font size="3">四：什么时候不能简单声明</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">class clsOld</span>
						</font>
						<font size="3">，必须</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">include</span>
						</font>
						<font size="3">呢？</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />
								</span>
						</font>
						<font size="3">不满足三的情况下：</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br /> </span>
						</font>
						<font size="3">比如：</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />         clsOld m_Objold;  //</span>
						</font>
						<font size="3">不知道占据大小，必须要通过它的具体声明来计算</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />
								</span>
						</font>
						<font size="3">原因很简单，想想你要计算</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">sizeof(classNew)</span>
						</font>
						<font size="3">，但连</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">clsOld</span>
						</font>
						<font size="3">的</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">size</span>
						</font>
						<font size="3">都不知道，编译器显然会无能为力。</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />
										<br />
								</span>
						</font>
						<font size="3">特殊情况：</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />          int test() { return clsOld::m_sInt;}<br />    </span>
						</font>
						<font size="3">静态成员调用，想来应该是不需要知道内存布局的，但因为需要知道</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">m_sInt</span>
						</font>
						<font size="3">是属于</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">clsOld</span>
						</font>
						<font size="3">命名空间</font>
						<font size="3">的，如果只声明</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">class xxx</span>
						</font>
						<font size="3">显然是不足以说明的，所以必须包含头文件。</font>
				</p>
				<p>
						<font size="3">综上所述，我有以下几点建议：</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
										<br />1</span>
						</font>
						<font size="3">：如果有共同相关依赖</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">(</span>
						</font>
						<font size="3">必须</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">include)</span>
						</font>
						<font size="3">的类，比如 </font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">A,B</span>
						</font>
						<font size="3">都依赖</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">D </span>
						</font>
						<font size="3">可以放在一起，然后直接 </font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">Include "d" </span>
						</font>
						<font size="3">类的使用者只需关心与本类暴露出的相关类型，内部用到的类型不用去管</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">(</span>
						</font>
						<font size="3">不用自已去</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">include d)</span>
						</font>
						<font size="3">。这样</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
								</span>
						</font>
						<font size="3">给出的</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">class</span>
						</font>
						<font size="3">，调用者才更好用</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">(</span>
						</font>
						<font size="3">不用去看代码查找，是不是还需要包含其它头文件</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">)</span>
						</font>
						<font size="3">。</font>
				</p>
				<p>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">2</span>
						</font>
						<font size="3">：如果</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">A</span>
						</font>
						<font size="3">类依赖</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">D B</span>
						</font>
						<font size="3">类不依赖</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">D</span>
						</font>
						<font size="3">，可以把它们分开两个头文件。各自</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">Include</span>
						</font>
						<font size="3">。这样可避免当</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">D</span>
						</font>
						<font size="3">发生变化时，</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
								</span>
						</font>
						<font size="3">避免不必要重编译。</font>
				</p>
				<p>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">3</span>
						</font>
						<font size="3">：类中尽量采用指针或引用方式调用其它类，这样就可以只声明</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">class xxx</span>
						</font>
						<font size="3">了。并且这也符合资源最优</font>
						<font face="Times New Roman, serif" size="3">
								<span lang="en-US">
								</span>
						</font>
						<font size="3">利用，更利于使用多态。<br /><br />/--------------------------------------------------/////////////////////////////////////////////////////////////////////////////<br /></font>
				</p>
				<div class="postTitle">
						<a href="http://blog.csdn.net/sumless/archive/2006/05/07/711965.aspx">
								<img height="13" src="http://blog.csdn.net/images/authorship.gif" width="15" border="0" />
								<font color="#009933"> 对于VC++中的头文件包含值得注意的一点</font>
						</a>
				</div>
				<div class="postText">
						<p class="MsoNormal" style="MARGIN-BOTTOM: 15.6pt">
								<span style="FONT-FAMILY: 宋体">　　</span>
								<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">今天用<span lang="EN-US">VC++</span>编译我这昨天写的代码时发现总是通不过，看到大部分的错误都是与一个类的定义有关。<span lang="EN-US"><?XML:NAMESPACE PREFIX = O /?><o:p></o:p></span></span>
						</p>
						<p class="MsoNormal" style="MARGIN-BOTTOM: 15.6pt">
								<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">　　明明我已经在这个类中定义了一个成员变量，可编译器偏要说那个变量不是这个类的成员。没办法，找了半天原因还是没有头绪。再三地确认不是我<span lang="EN-US">C++</span>的语法错误之后。我开始怀疑是不是头文件的问题。因为当我把一些<strong><span lang="EN-US">#include "..."</span></strong>搬到<strong><span lang="EN-US">#pragma once</span></strong>之前或者之后，错误报告就会发生变化。有时就只是说我的一个类<strong>重复定义</strong>了。<span lang="EN-US"><o:p></o:p></span></span>
						</p>
						<p class="MsoNormal" style="MARGIN-BOTTOM: 15.6pt; TEXT-INDENT: 24pt">
								<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">以前用<span lang="EN-US">C</span>写头文件的时候都是用宏定义来避免重复包含<strong>头文件</strong>。<span lang="EN-US">C++</span>里虽然也还可用这个方法，但<span lang="EN-US">VC++</span>就是不用，它用的是<strong><span lang="EN-US">#pragma once</span></strong>。这一变化对我来说真是有点摸不着头脑了，我不清楚<strong><span lang="EN-US">#pragma once</span></strong>的工作方式是如何的。而我现在遇到的问题又与这个有关。找找网上的内容看吧。上<span lang="EN-US">google</span>搜了半天，那些论坛里的回答基本上都是“防止重复包含<strong>头文件</strong>的，你不用管他。”这样的。可是不管他真的行吗？我刚学的<span lang="EN-US">VC++</span>，我看的书上是没有讲过这个内容的。怎么在网上也搜不到呢？经过我不懈的努力，终于让我找到了一篇<span lang="EN-US"><a href="http://www.yesky.com/127/1736627_3.shtml"><font color="#009933">http://www.yesky.com/127/1736627_3.shtml</font></a></span>。<span lang="EN-US"><o:p></o:p></span></span>
						</p>
						<p class="MsoNormal" style="MARGIN-BOTTOM: 15.6pt; TEXT-INDENT: 24pt">
								<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">作者<span lang="EN-US">Adding</span>的这段话对我的帮助最大：“</span>
								<span style="FONT-SIZE: 12pt; FONT-FAMILY: 楷体_GB2312">既然使用了包含文件，为什么还要在<span lang="EN-US">class CMainFrame</span>前添加<span lang="EN-US">"<strong>class CViewerView;</strong>"</span>等代码？如果用包含文件代替它，行不行？　　很多<span lang="EN-US">Visual C++</span>书籍对这些问题避而不谈，但实际上这是一个重要的问题。如果不能理解上述代码，我们很可能为无法通过编译而大伤脑筋。这些问题的出现是基于这样的一些事实：在我们用标准<span lang="EN-US">C/C++</span>设计程序时，有一个原则即两个代码文件不能相互包含，而且多次包含还会造成重复定义的错误。为了解决这个难题，<span lang="EN-US"> Visual C++</span>使用<span lang="EN-US">#pragma once</span>来通知编译器在生成时只包含<span lang="EN-US">(</span>打开<span lang="EN-US">)</span>一次，也就是说，在第一次<span lang="EN-US">#include</span>之后，编译器重新生成时不会再对这些包含文件进行包含<span lang="EN-US">(</span>打开<span lang="EN-US">)</span>和读取，因此我们看到在用向导创建的所有类的头文件中有<strong><span lang="EN-US">#pragma once</span></strong>语句就不会觉得奇怪了。然而<span style="COLOR: red">正是由于这个语句而造成了在第二次<span lang="EN-US">#include</span>后编译器无法正确识别所引用的类。因此，我们在相互包含时还需要加入类似<span lang="EN-US">class CViewerView</span>这样的语句来通知编译器这个类是一个实际的调用。</span></span>
								<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">”<span lang="EN-US"><o:p></o:p></span></span>
						</p>
						<p class="MsoNormal" style="MARGIN-BOTTOM: 15.6pt; TEXT-INDENT: 24pt">
								<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">看来就是这个问题了。把我的代码一加上那些类的声明以后果然通过了编译。我感觉这个问题在<span lang="EN-US">VC++</span>里面来说应该是值得注意的。可能是由于我刚学<span lang="EN-US">VC++</span>，见识太少的原故吧。无论如何先记下来，说不定也有人在为这个<strong><span lang="EN-US">#pragma once</span></strong>伤脑筋呢。<span lang="EN-US"><o:p></o:p></span></span>
						</p>
				</div>
		</div>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/16445.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2006-12-14 18:16 <a href="http://www.cppblog.com/yuanyajie/archive/2006/12/14/16445.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>烦人的类型转换</title><link>http://www.cppblog.com/yuanyajie/archive/2006/12/14/16429.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Thu, 14 Dec 2006 06:22:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2006/12/14/16429.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/16429.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2006/12/14/16429.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/16429.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/16429.html</trackback:ping><description><![CDATA[
		<h4 class="TextColor1" id="subjcns!F1593BEB77A25884!108" style="MARGIN-BOTTOM: 0px">对有关数据类型转换的整理</h4>
		<div id="msgcns!F1593BEB77A25884!108">
				<div>
						<p>int i = 100;<br />long l = 2001;<br />float f=300.2;<br />double d=12345.119;<br />char username[]="程佩君";<br />char temp[200];<br />char *buf;<br />CString str;<br />_variant_t v1;<br />_bstr_t v2;<br /><br /><font color="#6699ff"><b>一、其它数据类型转换为字符串</b></font><br /></p>
						<ul>
								<li>
										<font color="#6699ff">短整型(int)</font>
										<br />itoa(i,temp,10);///将i转换为字符串放入temp中,最后一个数字表示十进制<br />itoa(i,temp,2); ///按二进制方式转换 
</li>
								<li>
										<font color="#6699ff">长整型(long)</font>
										<br />ltoa(l,temp,10); 
</li>
								<li>
										<font color="#6699ff">浮点数(float,double)</font>
										<br />用fcvt可以完成转换,这是MSDN中的例子:<br />int decimal, sign; <br />char *buffer; <br />double source = 3.1415926535; <br />buffer = _fcvt( source, 7, &amp;decimal, &amp;sign ); <br />运行结果:source: 3.1415926535 buffer: '31415927' decimal: 1 sign: 0<br />decimal表示小数点的位置,sign表示符号:0为正数，1为负数 
</li>
								<li>
										<font color="#6699ff">CString变量</font>
										<br />str = "2008北京奥运";<br />buf = (LPSTR)(LPCTSTR)str; 
</li>
								<li>
										<font color="#6699ff">BSTR变量</font>
										<br />BSTR bstrValue = ::SysAllocString(L"程序员"); <br />char * buf = _com_util::ConvertBSTRToString(bstrValue); <br />SysFreeString(bstrValue); <br />AfxMessageBox(buf); <br />delete(buf); 
</li>
								<li>
										<font color="#6699ff">CComBSTR变量</font>
										<br />CComBSTR bstrVar("test"); <br />char *buf = _com_util::ConvertBSTRToString(bstrVar.m_str); <br />AfxMessageBox(buf); <br />delete(buf); <br /></li>
								<li>
										<font color="#6699ff">_bstr_t变量</font>
										<br />_bstr_t类型是对BSTR的封装，因为已经重载了=操作符，所以很容易使用<br />_bstr_t bstrVar("test"); <br />const char *buf = bstrVar;///不要修改buf中的内容 <br />AfxMessageBox(buf); <br /><br /></li>
								<li>
										<font color="#6699ff">通用方法(针对非COM数据类型)</font>
										<br />用sprintf完成转换<br /><pre>char buffer[200]; char c = '1'; int i = 35; long j = 1000; float f = 1.7320534f; sprintf( buffer, "%c",c); sprintf( buffer, "%d",i); sprintf( buffer, "%d",j); sprintf( buffer, "%f",f); </pre></li>
						</ul>
						<p>
								<b>
										<font color="#6699ff">二、字符串转换为其它数据类型</font>
								</b>
								<br />strcpy(temp,"123"); </p>
						<ul>
								<li>
										<font color="#6699ff">短整型(int)</font>
										<br />i = atoi(temp); 
</li>
								<li>
										<font color="#6699ff">长整型(long)</font>
										<br />l = atol(temp); 
</li>
								<li>
										<font color="#6699ff">浮点(double)</font>
										<br />d = atof(temp); 
</li>
								<li>
										<font color="#6699ff">CString变量</font>
										<br />CString name = temp; 
</li>
								<li>
										<font color="#6699ff">BSTR变量</font>
										<br />BSTR bstrValue = ::SysAllocString(L"程序员"); <br />...///完成对bstrValue的使用<br />SysFreeString(bstrValue); <br /></li>
								<li>
										<font color="#6699ff">CComBSTR变量</font>
										<br />CComBSTR类型变量可以直接赋值<br />CComBSTR bstrVar1("test");<br />CComBSTR bstrVar2(temp);<br /></li>
								<li>
										<font color="#6699ff">_bstr_t变量</font>
										<br />_bstr_t类型的变量可以直接赋值<br />_bstr_t bstrVar1("test"); <br />_bstr_t bstrVar2(temp); <br /><br /></li>
						</ul>
						<p>
								<b>
										<font color="#6699ff">三、其它数据类型转换到CString</font>
								</b>
								<br />使用CString的成员函数Format来转换,例如:<br /></p>
						<ul>
								<li>整数(int)<br />str.Format("%d",i); 
</li>
								<li>浮点数(float)<br />str.Format("%f",i); 
</li>
								<li>字符串指针(char *)等已经被CString构造函数支持的数据类型可以直接赋值<br />str = username; 
</li>
								<li>对于Format所不支持的数据类型，可以通过上面所说的关于其它数据类型转化到char *的方法先转到char *，然后赋值给CString变量。<br /></li>
						</ul>
						<p>
								<b>
										<font color="#6699ff">四、BSTR、_bstr_t与CComBSTR</font>
								</b>
								<br />
						</p>
						<ul>
								<li>CComBSTR 是ATL对BSTR的封装，_bstr_t是C++对BSTR的封装,BSTR是32位指针,但并不直接指向字串的缓冲区。<br />char *转换到BSTR可以这样: <br />BSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上comutil.h和comsupp.lib<br />SysFreeString(bstrValue); <br />反之可以使用<br />char *p=_com_util::ConvertBSTRToString(b);<br />delete p;<br />具体可以参考一，二段落里的具体说明。<br /><br />CComBSTR与_bstr_t对大量的操作符进行了重载，可以直接进行=,!=,==等操作，所以使用非常方便。<br />特别是_bstr_t,建议大家使用它。<br /></li>
						</ul>
						<p>
								<b>
										<font color="#6699ff">五、VARIANT 、_variant_t 与 COleVariant</font>
								</b>
								<br />
						</p>
						<ul>
								<li>VARIANT的结构可以参考头文件VC98\Include\OAIDL.H中关于结构体tagVARIANT的定义。<br />对于VARIANT变量的赋值：首先给vt成员赋值，指明数据类型，再对联合结构中相同数据类型的变量赋值，举个例子：<br />VARIANT va;<br />int a=2001;<br />va.vt=VT_I4;///指明整型数据<br />va.lVal=a; ///赋值 
</li>
								<li>
								</li>
								<li>
								</li>
								<li>_variant_t是VARIANT的封装类，其赋值可以使用强制类型转换，其构造函数会自动处理这些数据类型。<br />使用时需加上#include &lt;comdef.h&gt;<br />例如：<br />long l=222;<br />ing i=100;<br />_variant_t lVal(l);<br />lVal = (long)i; 
</li>
								<li>
										<br />COleVariant的使用与_variant_t的方法基本一样，请参考如下例子：<br />COleVariant v3 = "字符串", v4 = (long)1999;<br />CString str =(BSTR)v3.pbstrVal;<br />long i = v4.lVal;<br /><br />////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
</li>
								<li>
										<p>本主题演示如何将各种 C++ 字符串类型转换为其他字符串。可以转换的字符串类型包括 <strong>char *</strong>、<strong>wchar_t*</strong>、<a onclick="javascript:TrackThisClick('ctl00_LibFrame_ctl02','ctl00_LibFrame_ctl03',this);" href="http://msdn2.microsoft.com/zh-CN/library/zthfhkd6.aspx"><font color="#000080">_bstr_t</font></a>、<a onclick="javascript:TrackThisClick('ctl00_LibFrame_ctl02','ctl00_LibFrame_ctl04',this);" href="http://msdn2.microsoft.com/zh-CN/library/zh7x9w3f.aspx"><font color="#000080">CComBSTR</font></a>、<a onclick="javascript:TrackThisClick('ctl00_LibFrame_ctl02','ctl00_LibFrame_ctl05',this);" href="http://msdn2.microsoft.com/zh-CN/library/ms174288.aspx"><font color="#000080">CString</font></a>、<a onclick="javascript:TrackThisClick('ctl00_LibFrame_ctl02','ctl00_LibFrame_ctl06',this);" href="http://msdn2.microsoft.com/zh-CN/library/syxtdd4f.aspx"><font color="#000080">basic_string</font></a> 和 <a onclick="javascript:TrackThisClick('ctl00_LibFrame_ctl02','ctl00_LibFrame_ctl07',this);" href="http://msdn2.microsoft.com/zh-CN/library/system.string.aspx"><font color="#000080">System.String</font></a>。在所有情况下，在将字符串转换为新类型时，都会创建字符串的副本。对新字符串进行的任何更改都不会影响原始字符串，反之亦然。</p>
										<h1 class="heading">从 char * 转换</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection0">
										</div>
										<h1 class="heading">示例</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection1">
												<h3 class="subHeading">说明</h3>
												<div class="subSection">
														<p>此示例演示如何从 <strong>char *</strong> 转换为上面列出的其他字符串类型。</p>
												</div>
												<div class="subSection">
														<div class="code" id="ctl00_LibFrame_ctl08_other">
																<div class="CodeSnippetTitleBar">
																		<div class="CodeDisplayLanguage">
																		</div>
																</div>
																<pre class="code" id="ctl00_LibFrame_ctl08other" space="preserve">// convert_from_char.cpp
// compile with /clr /link comsuppw.lib

#include &lt;iostream&gt;
#include &lt;stdlib.h&gt;
#include &lt;string&gt;

#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"

using namespace std;
using namespace System;

int main()
{
    char *orig = "Hello, World!";
    cout &lt;&lt; orig &lt;&lt; " (char *)" &lt;&lt; endl;

    // Convert to a wchar_t*
    size_t origsize = strlen(orig) + 1;
    const size_t newsize = 100;
    size_t convertedChars = 0;
    wchar_t wcstring[newsize];
    mbstowcs_s(&amp;convertedChars, wcstring, origsize, orig, _TRUNCATE);
    wcscat_s(wcstring, L" (wchar_t *)");
    wcout &lt;&lt; wcstring &lt;&lt; endl;

    // Convert to a _bstr_t
    _bstr_t bstrt(orig);
    bstrt += " (_bstr_t)";
    cout &lt;&lt; bstrt &lt;&lt; endl;

    // Convert to a CComBSTR
    CComBSTR ccombstr(orig);
    if (ccombstr.Append(L" (CComBSTR)") == S_OK)
    {
        CW2A printstr(ccombstr);
        cout &lt;&lt; printstr &lt;&lt; endl;
    }

    // Convert to a CString
    CString cstring(orig);
    cstring += " (CString)";
    cout &lt;&lt; cstring &lt;&lt; endl;

    // Convert to a basic_string
    string basicstring(orig);
    basicstring += " (basic_string)";
    cout &lt;&lt; basicstring &lt;&lt; endl;

    // Convert to a System::String
    String ^systemstring = gcnew String(orig);
    systemstring += " (System::String)";
    Console::WriteLine("{0}", systemstring);
    delete systemstring;
}</pre>
														</div>
												</div>
												<h3 class="subHeading">输出</h3>
												<div class="subSection">
														<pre>Hello, World! (char *)
Hello, World! (wchar_t *)
Hello, World! (_bstr_t)
Hello, World! (CComBSTR)
Hello, World! (CString)
Hello, World! (basic_string)
Hello, World! (System::String)</pre>
												</div>
										</div>
										<h1 class="heading">从 wchar_t * 转换</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection2">
										</div>
										<h1 class="heading">示例</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection3">
												<h3 class="subHeading">说明</h3>
												<div class="subSection">
														<p>此示例演示如何从 <strong>wchar_t *</strong> 转换为上面列出的其他字符串类型。</p>
												</div>
												<div class="subSection">
														<div class="code" id="ctl00_LibFrame_ctl09_other">
																<div class="CodeSnippetTitleBar">
																		<div class="CodeDisplayLanguage">
																		</div>
																</div>
																<pre class="code" id="ctl00_LibFrame_ctl09other" space="preserve">// convert_from_wchar_t.cpp
// compile with /clr /link comsuppw.lib

#include &lt;iostream&gt;
#include &lt;stdlib.h&gt;
#include &lt;string&gt;

#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"

using namespace std;
using namespace System;

int main()
{
    wchar_t *orig = L"Hello, World!";
    wcout &lt;&lt; orig &lt;&lt; L" (wchar_t *)" &lt;&lt; endl;

    // Convert to a char*
    size_t origsize = wcslen(orig) + 1;
    const size_t newsize = 100;
    size_t convertedChars = 0;
    char nstring[newsize];
    wcstombs_s(&amp;convertedChars, nstring, origsize, orig, _TRUNCATE);
    strcat_s(nstring, " (char *)");
    cout &lt;&lt; nstring &lt;&lt; endl;

    // Convert to a _bstr_t
    _bstr_t bstrt(orig);
    bstrt += " (_bstr_t)";
    cout &lt;&lt; bstrt &lt;&lt; endl;

    // Convert to a CComBSTR
    CComBSTR ccombstr(orig);
    if (ccombstr.Append(L" (CComBSTR)") == S_OK)
    {
        CW2A printstr(ccombstr);
        cout &lt;&lt; printstr &lt;&lt; endl;
    }

    // Convert to a CString
    CString cstring(orig);
    cstring += " (CString)";
    cout &lt;&lt; cstring &lt;&lt; endl;

    // Convert to a basic_string
    wstring basicstring(orig);
    basicstring += L" (basic_string)";
    wcout &lt;&lt; basicstring &lt;&lt; endl;

    // Convert to a System::String
    String ^systemstring = gcnew String(orig);
    systemstring += " (System::String)";
    Console::WriteLine("{0}", systemstring);
    delete systemstring;
}</pre>
														</div>
												</div>
												<h3 class="subHeading">输出</h3>
												<div class="subSection">
														<pre>Hello, World! (wchar_t *)
Hello, World! (char *)
Hello, World! (_bstr_t)
Hello, World! (CComBSTR)
Hello, World! (CString)
Hello, World! (basic_string)
Hello, World! (System::String)</pre>
												</div>
										</div>
										<h1 class="heading">从 _bstr_t 转换</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection4">
										</div>
										<h1 class="heading">示例</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection5">
												<h3 class="subHeading">说明</h3>
												<div class="subSection">
														<p>此示例演示如何从 <strong>_bstr_t</strong> 转换为上面列出的其他字符串类型。</p>
												</div>
												<div class="subSection">
														<div class="code" id="ctl00_LibFrame_ctl10_other">
																<div class="CodeSnippetTitleBar">
																		<div class="CodeDisplayLanguage">
																		</div>
																</div>
																<pre class="code" id="ctl00_LibFrame_ctl10other" space="preserve">// convert_from_bstr_t.cpp
// compile with /clr /link comsuppw.lib

#include &lt;iostream&gt;
#include &lt;stdlib.h&gt;
#include &lt;string&gt;

#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"

using namespace std;
using namespace System;

int main()
{
    _bstr_t orig("Hello, World!");
    wcout &lt;&lt; orig &lt;&lt; " (_bstr_t)" &lt;&lt; endl;

    // Convert to a char*
    const size_t newsize = 100;
    char nstring[newsize];
    strcpy_s(nstring, (char *)orig);
    strcat_s(nstring, " (char *)");
    cout &lt;&lt; nstring &lt;&lt; endl;

    // Convert to a wchar_t*
    wchar_t wcstring[newsize];
    wcscpy_s(wcstring, (wchar_t *)orig);
    wcscat_s(wcstring, L" (wchar_t *)");
    wcout &lt;&lt; wcstring &lt;&lt; endl;

    // Convert to a CComBSTR
    CComBSTR ccombstr((char *)orig);
    if (ccombstr.Append(L" (CComBSTR)") == S_OK)
    {
        CW2A printstr(ccombstr);
        cout &lt;&lt; printstr &lt;&lt; endl;
    }

    // Convert to a CString
    CString cstring((char *)orig);
    cstring += " (CString)";
    cout &lt;&lt; cstring &lt;&lt; endl;

    // Convert to a basic_string
    string basicstring((char *)orig);
    basicstring += " (basic_string)";
    cout &lt;&lt; basicstring &lt;&lt; endl;

    // Convert to a System::String
    String ^systemstring = gcnew String((char *)orig);
    systemstring += " (System::String)";
    Console::WriteLine("{0}", systemstring);
    delete systemstring;
}</pre>
														</div>
												</div>
												<h3 class="subHeading">输出</h3>
												<div class="subSection">
														<pre>Hello, World! (_bstr_t)
Hello, World! (char *)
Hello, World! (wchar_t *)
Hello, World! (CComBSTR)
Hello, World! (CString)
Hello, World! (basic_string)
Hello, World! (System::String)</pre>
												</div>
										</div>
										<h1 class="heading">从 CComBSTR 转换</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection6">
										</div>
										<h1 class="heading">示例</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection7">
												<h3 class="subHeading">说明</h3>
												<div class="subSection">
														<p>此示例演示如何从 <strong>CComBSTR</strong> 转换为上面列出的其他字符串类型。</p>
												</div>
												<div class="subSection">
														<div class="code" id="ctl00_LibFrame_ctl11_other">
																<div class="CodeSnippetTitleBar">
																		<div class="CodeDisplayLanguage">
																		</div>
																</div>
																<pre class="code" id="ctl00_LibFrame_ctl11other" space="preserve">// convert_from_ccombstr.cpp
// compile with /clr /link comsuppw.lib

#include &lt;iostream&gt;
#include &lt;stdlib.h&gt;
#include &lt;string&gt;

#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"
#include "vcclr.h"

using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;

int main()
{
    CComBSTR orig("Hello, World!");
    CW2A printstr(orig);
    cout &lt;&lt; printstr &lt;&lt; " (CComBSTR)" &lt;&lt; endl;

    // Convert to a char*
    const size_t newsize = 100;
    char nstring[newsize];
    CW2A tmpstr1(orig);
    strcpy_s(nstring, tmpstr1);
    strcat_s(nstring, " (char *)");
    cout &lt;&lt; nstring &lt;&lt; endl;

    // Convert to a wchar_t*
    wchar_t wcstring[newsize];
    wcscpy_s(wcstring, orig);
    wcscat_s(wcstring, L" (wchar_t *)");
    wcout &lt;&lt; wcstring &lt;&lt; endl;

    // Convert to a _bstr_t
    _bstr_t bstrt(orig);
    bstrt += " (_bstr_t)";
    cout &lt;&lt; bstrt &lt;&lt; endl;

    // Convert to a CString
    CString cstring(orig);
    cstring += " (CString)";
    cout &lt;&lt; cstring &lt;&lt; endl;

    // Convert to a basic_string
    wstring basicstring(orig);
    basicstring += L" (basic_string)";
    wcout &lt;&lt; basicstring &lt;&lt; endl;

    // Convert to a System::String
    String ^systemstring = gcnew String(orig);
    systemstring += " (System::String)";
    Console::WriteLine("{0}", systemstring);
    delete systemstring;
}</pre>
														</div>
												</div>
												<h3 class="subHeading">输出</h3>
												<div class="subSection">
														<pre>Hello, World! (CComBSTR)
Hello, World! (char *)
Hello, World! (wchar_t *)
Hello, World! (_bstr_t)
Hello, World! (CString)
Hello, World! (basic_string)
Hello, World! (System::String)</pre>
												</div>
										</div>
										<h1 class="heading">从 CString 转换</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection8">
										</div>
										<h1 class="heading">示例</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection9">
												<h3 class="subHeading">说明</h3>
												<div class="subSection">
														<p>此示例演示如何从 <strong>CString</strong> 转换为上面列出的其他字符串类型。</p>
												</div>
												<div class="subSection">
														<div class="code" id="ctl00_LibFrame_ctl12_other">
																<div class="CodeSnippetTitleBar">
																		<div class="CodeDisplayLanguage">
																		</div>
																</div>
																<pre class="code" id="ctl00_LibFrame_ctl12other" space="preserve">// convert_from_cstring.cpp
// compile with /clr /link comsuppw.lib

#include &lt;iostream&gt;
#include &lt;stdlib.h&gt;
#include &lt;string&gt;

#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"

using namespace std;
using namespace System;

int main()
{
    CString orig("Hello, World!");
    wcout &lt;&lt; orig &lt;&lt; " (CString)" &lt;&lt; endl;

    // Convert to a char*
    const size_t newsize = 100;
    char nstring[newsize];
    strcpy_s(nstring, orig);
    strcat_s(nstring, " (char *)");
    cout &lt;&lt; nstring &lt;&lt; endl;

    // Convert to a wchar_t*
    // You must first convert to a char * for this to work.
    size_t origsize = strlen(orig) + 1;
    size_t convertedChars = 0;
    wchar_t wcstring[newsize];
    mbstowcs_s(&amp;convertedChars, wcstring, origsize, orig, _TRUNCATE);
    wcscat_s(wcstring, L" (wchar_t *)");
    wcout &lt;&lt; wcstring &lt;&lt; endl;

    // Convert to a _bstr_t
    _bstr_t bstrt(orig);
    bstrt += " (_bstr_t)";
    cout &lt;&lt; bstrt &lt;&lt; endl;

    // Convert to a CComBSTR
    CComBSTR ccombstr(orig);
    if (ccombstr.Append(L" (CComBSTR)") == S_OK)
    {
        CW2A printstr(ccombstr);
        cout &lt;&lt; printstr &lt;&lt; endl;
    }

    // Convert to a basic_string
    string basicstring(orig);
    basicstring += " (basic_string)";
    cout &lt;&lt; basicstring &lt;&lt; endl;

    // Convert to a System::String
    String ^systemstring = gcnew String(orig);
    systemstring += " (System::String)";
    Console::WriteLine("{0}", systemstring);
    delete systemstring;
}</pre>
														</div>
												</div>
												<h3 class="subHeading">输出</h3>
												<div class="subSection">
														<pre>Hello, World! (CString)
Hello, World! (char *)
Hello, World! (wchar_t *)
Hello, World! (_bstr_t)
Hello, World! (CComBSTR)
Hello, World! (basic_string)
Hello, World! (System::String)</pre>
												</div>
										</div>
										<h1 class="heading">从 basic_string 转换</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection10">
										</div>
										<h1 class="heading">示例</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection11">
												<h3 class="subHeading">说明</h3>
												<div class="subSection">
														<p>此示例演示如何从 <strong>basic_string</strong> 转换为上面列出的其他字符串类型。</p>
												</div>
												<div class="subSection">
														<div class="code" id="ctl00_LibFrame_ctl13_other">
																<div class="CodeSnippetTitleBar">
																		<div class="CodeDisplayLanguage">
																		</div>
																</div>
																<pre class="code" id="ctl00_LibFrame_ctl13other" space="preserve">// convert_from_basic_string.cpp
// compile with /clr /link comsuppw.lib

#include &lt;iostream&gt;
#include &lt;stdlib.h&gt;
#include &lt;string&gt;

#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"

using namespace std;
using namespace System;

int main()
{
    string orig("Hello, World!");
    cout &lt;&lt; orig &lt;&lt; " (basic_string)" &lt;&lt; endl;

    // Convert to a char*
    const size_t newsize = 100;
    char nstring[newsize];
    strcpy_s(nstring, orig.c_str());
    strcat_s(nstring, " (char *)");
    cout &lt;&lt; nstring &lt;&lt; endl;

    // Convert to a wchar_t*
    // You must first convert to a char * for this to work.
    size_t origsize = strlen(orig.c_str()) + 1;
    size_t convertedChars = 0;
    wchar_t wcstring[newsize];
    mbstowcs_s(&amp;convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE);
    wcscat_s(wcstring, L" (wchar_t *)");
    wcout &lt;&lt; wcstring &lt;&lt; endl;

    // Convert to a _bstr_t
    _bstr_t bstrt(orig.c_str());
    bstrt += " (_bstr_t)";
    cout &lt;&lt; bstrt &lt;&lt; endl;

    // Convert to a CComBSTR
    CComBSTR ccombstr(orig.c_str());
    if (ccombstr.Append(L" (CComBSTR)") == S_OK)
    {
        CW2A printstr(ccombstr);
        cout &lt;&lt; printstr &lt;&lt; endl;
    }

    // Convert to a CString
    CString cstring(orig.c_str());
    cstring += " (CString)";
    cout &lt;&lt; cstring &lt;&lt; endl;

    // Convert to a System::String
    String ^systemstring = gcnew String(orig.c_str());
    systemstring += " (System::String)";
    Console::WriteLine("{0}", systemstring);
    delete systemstring;
}</pre>
														</div>
												</div>
												<h3 class="subHeading">输出</h3>
												<div class="subSection">
														<pre>Hello, World! (basic_string)
Hello, World! (char *)
Hello, World! (wchar_t *)
Hello, World! (_bstr_t)
Hello, World! (CComBSTR)
Hello, World! (CString)
Hello, World! (System::String)</pre>
												</div>
										</div>
										<h1 class="heading">从 System::String 转换</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection12">
										</div>
										<h1 class="heading">示例</h1>
										<div class="seeAlsoNoToggleSection" id="sectionSection13">
												<h3 class="subHeading">说明</h3>
												<div class="subSection">
														<p>此示例演示如何从 <strong>System.String</strong> 转换为上面列出的其他字符串类型。</p>
												</div>
												<div class="subSection">
														<div class="code" id="ctl00_LibFrame_ctl14_other">
																<div class="CodeSnippetTitleBar">
																		<div class="CodeDisplayLanguage">
																		</div>
																</div>
																<pre class="code" id="ctl00_LibFrame_ctl14other" space="preserve">// convert_from_system_string.cpp
// compile with /clr /link comsuppw.lib

#include &lt;iostream&gt;
#include &lt;stdlib.h&gt;
#include &lt;string&gt;

#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"
#include "vcclr.h"

using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;

int main()
{
    String ^orig = gcnew String("Hello, World!");
    Console::WriteLine("{0} (System::String)", orig);

    pin_ptr&lt;const wchar_t&gt; wch = PtrToStringChars(orig);

    // Convert to a char*
    size_t origsize = wcslen(wch) + 1;
    const size_t newsize = 100;
    size_t convertedChars = 0;
    char nstring[newsize];
    wcstombs_s(&amp;convertedChars, nstring, origsize, wch, _TRUNCATE);
    strcat_s(nstring, " (char *)");
    cout &lt;&lt; nstring &lt;&lt; endl;

    // Convert to a wchar_t*
    wchar_t wcstring[newsize];
    wcscpy_s(wcstring, wch);
    wcscat_s(wcstring, L" (wchar_t *)");
    wcout &lt;&lt; wcstring &lt;&lt; endl;

    // Convert to a _bstr_t
    _bstr_t bstrt(wch);
    bstrt += " (_bstr_t)";
    cout &lt;&lt; bstrt &lt;&lt; endl;

    // Convert to a CComBSTR
    CComBSTR ccombstr(wch);
    if (ccombstr.Append(L" (CComBSTR)") == S_OK)
    {
        CW2A printstr(ccombstr);
        cout &lt;&lt; printstr &lt;&lt; endl;
    }

    // Convert to a CString
    CString cstring(wch);
    cstring += " (CString)";
    cout &lt;&lt; cstring &lt;&lt; endl;

    // Convert to a basic_string
    wstring basicstring(wch);
    basicstring += L" (basic_string)";
    wcout &lt;&lt; basicstring &lt;&lt; endl;

    delete orig;
}</pre>
														</div>
												</div>
												<h3 class="subHeading">输出</h3>
												<div class="subSection">
														<pre>Hello, World! (System::String)
Hello, World! (char *)
Hello, World! (wchar_t *)
Hello, World! (_bstr_t)
Hello, World! (CComBSTR)
Hello, World! (CString)
Hello, World! (basic_string)</pre>
												</div>
										</div>
								</li>
						</ul>
				</div>
		</div>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/16429.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2006-12-14 14:22 <a href="http://www.cppblog.com/yuanyajie/archive/2006/12/14/16429.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CString和string的互相转换</title><link>http://www.cppblog.com/yuanyajie/archive/2006/12/14/16427.html</link><dc:creator>清源游民</dc:creator><author>清源游民</author><pubDate>Thu, 14 Dec 2006 06:11:00 GMT</pubDate><guid>http://www.cppblog.com/yuanyajie/archive/2006/12/14/16427.html</guid><wfw:comment>http://www.cppblog.com/yuanyajie/comments/16427.html</wfw:comment><comments>http://www.cppblog.com/yuanyajie/archive/2006/12/14/16427.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yuanyajie/comments/commentRss/16427.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yuanyajie/services/trackbacks/16427.html</trackback:ping><description><![CDATA[
		<h4 class="TextColor1" id="subjcns!944d768f73c602d6!193" style="MARGIN-BOTTOM: 0px"> </h4>
		<div id="msgcns!944d768f73c602d6!193">
				<div>CString-&gt;std::string 例子：<br /><br />CString strMfc=“test“;<br /><br />std::string strStl;<br /><br />strStl=strMfc.GetBuffer(0);<br /><br />std::string-&gt;CString  例子：<br /><br />CString strMfc；<br /><br />std::string strStl=“test“;<br /><br />strMfc=strStl.c_str(); </div>
		</div>
<img src ="http://www.cppblog.com/yuanyajie/aggbug/16427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yuanyajie/" target="_blank">清源游民</a> 2006-12-14 14:11 <a href="http://www.cppblog.com/yuanyajie/archive/2006/12/14/16427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>