﻿<?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++ Programmer's Cookbook</title><link>http://www.cppblog.com/mzty/</link><description>&lt;br/&gt;  
&lt;br/&gt;
&lt;a href = "http://www.cppblog.com/mzty/archive/2007/03/02/19109.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{C++ 基础}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "http://www.cppblog.com/mzty/archive/2007/08/13/29922.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{C++ 高级}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "http://www.cppblog.com/mzty/archive/2007/04/16/22064.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{C#界面，C++核心算法}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "http://www.cppblog.com/mzty/archive/2007/03/04/19163.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{设计模式}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "
http://www.cppblog.com/mzty/archive/2007/03/04/19167.html"&gt;&lt;font size = 5 color ="#FF0000"&gt;{C#基础}&lt;font/&gt;&lt;/a&gt;





</description><language>zh-cn</language><lastBuildDate>Fri, 10 Oct 2008 18:52:08 GMT</lastBuildDate><pubDate>Fri, 10 Oct 2008 18:52:08 GMT</pubDate><ttl>60</ttl><item><title>Google Chrome Source Code 源码下载（转载）</title><link>http://www.cppblog.com/mzty/archive/2008/09/16/62004.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 16 Sep 2008 13:00:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2008/09/16/62004.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/62004.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2008/09/16/62004.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/62004.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/62004.html</trackback:ping><description><![CDATA[<br>转载来自：<a  href="http://www.xiaohui.com/">http://www.XiaoHui.com</a><br><br>Goolgle 于 2008.09.02 <a  href="http://www.xiaohui.com/dev/server/20080903-google-chrome.htm">发布了浏览器 Google Chrome</a>。Google Chrome 使用的<strong>内核源码</strong>来自<a  href="http://www.xiaohui.com/dev/server/20080903-webkit-opensource-project.htm">开源浏览器引擎 WebKit Open Source Project</a>。Google Chrome 的源码，同样亦是开源的。在 <a  href="http://googlechinablog.com/2008/09/chromium.html" target="_blank" class="external">Google 的中文官方 Blog － Google 黑板报</a>中，提到：
<p>QUOTE: <em>我们对很多开发开源项目的人心存感激，我们承诺会沿着前人的路继续前行。 我们借鉴了一些源自 Apple WebKit
和 Mozilla Firefox 的技术，怀着同样开源的精神，谷歌浏览器所有的代码全部开源。我们希望能与整个业界合作从而促进互联网的健康发展。</em></p>
<p>　　目前 <strong>Google Chrome 源码</strong>已经公布了，有兴趣的<strong>软件开发者</strong>、<strong>程序员</strong>可以从 chromium.org 服务器使用 SVN checkout <strong>Google Chrome Source Code</strong>，自定义自己的浏览器。 </p>
<h2>Google Chrome 源码下载地址 (Google Chrome Source Code Download)</h2>
<p>　　地址： <a  href="http://www.xiaohui.com/dev/vccool/internet/google-chrome-source-code-download.htm">http://www.xiaohui.com/dev/vccool/internet/google-chrome-source-code-download.htm</a></p>
<p>　　1. <strong>Google Chrome 源码 SVN 地址</strong>：<a  href="http://src.chromium.org/svn" target="_blank" class="external">http://src.chromium.org/svn</a>。包含有 Chrome、Gears、Webkit、GCC 等源码以及编译依赖工具。Chrome 浏览器项目的源码，位于目录 <a  href="http://src.chromium.org/svn/trunk/src/chrome/" target="_blank" class="exnternal">http://src.chromium.org/svn/trunk/src/chrome/</a></p>
<p>　　2. <strong>Google Chrome 源码 Web 浏览地址</strong>：<a  href="http://src.chromium.org/viewvc/" target="_blank" class="external">http://src.chromium.org/viewvc/</a></p>
<p>　　3. <strong>Google Chrome 所使用的 JavaScript V8 的源码下载地址</strong>：<a  href="http://code.google.com/p/v8/" target="_blank" class="external">http://code.google.com/p/v8/</a></p>
<h2>Google Chrome 源码下载相关资源</h2>
<ul>
    <li>站内文章：<a  href="http://www.xiaohui.com/dev/server/20080903-webkit-opensource-project.htm">Google Chrome 的内核引擎 WebKit 介绍</a> - WebKit Open Source Project</li>
    <li>站内文章：<a  href="http://www.xiaohui.com/dev/server/20080903-google-chrome.htm">Google 浏览器 Google Chrome 最新试用手记</a> - 第一时间试用 Google Chrome 的感受</li>
    <li>外部连接：<a  href="http://webkit.org/" target="_blank" class="external">WebKit.org</a> - WebKit Open Source Project</li>
    <li>外部连接：<a  href="http://www.osxcn.com/apple/installing-and-running-webkit-in-linux.html" target="_blank" class="external">在 Linux 上使用 WebKit 引擎浏览器</a> - 来自 Nicky's Blog 的文章</li>
    <li>外部链接：<a  href="http://googlechinablog.com/2008/09/chromium.html" target="_blank" class="external">Google 官方 Blog 的文章</a> - 谷歌浏览器（Google Chrome）, Chromium 以及竞争</li>
    <li>外部链接：<a  href="http://googlechinablog.com/2008/09/blog-post_02.html" target="_blank" class="external">Google 官方 Blog 的文章</a> - 浏览器的新视角</li>
    <li>外部链接：<a  href="http://www.chromefans.org/chrome-themes/" target="_blank" class="external" title="Free download the google themes to enhance your chrome browser">Google Chrome Themes</a> - 下载 Google Chrome Themes </li>
</ul>
<br><br><img src ="http://www.cppblog.com/mzty/aggbug/62004.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2008-09-16 21:00 <a href="http://www.cppblog.com/mzty/archive/2008/09/16/62004.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《windows via C++》之windows线程同步</title><link>http://www.cppblog.com/mzty/archive/2008/07/29/57470.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 29 Jul 2008 14:54:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2008/07/29/57470.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/57470.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2008/07/29/57470.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/57470.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/57470.html</trackback:ping><description><![CDATA[<p><br>来自：梦在天涯C++博客(<a href="http://www.cppblog.com/mzty/">http://www.cppblog.com/mzty/</a>)</p>
<p>一 线程</p>
<p>1）如果你正在编写C/C++代码，决不应该调用CreateThread。相反，应该使用VisualC++运行期库函数_beginthreadex，退出也应该使用_endthreadex。如果不使用Microsoft的VisualC++编译器，你的编译器供应商有它自己的CreateThred替代函数。不管这个替代函数是什么，你都必须使用。</p>
<p><br>2）因为_beginthreadex和_endthreadex是CRT线程函数，所以必须注意编译选项runtimelibaray的选择，使用MT或MTD。</p>
<p>3) _beginthreadex函数的参数列表与CreateThread函数的参数列表是相同的，但是参数名和类型并不完全相同。这是因为Microsoft的C/C++运行期库的开发小组认为，C/C++运行期函数不应该对Windows数据类型有任何依赖。_beginthreadex函数也像CreateThread那样，返回新创建的线程的句柄。</p>
<p>4）下面是关于_beginthreadex的一些要点：</p>
<p>&#8226;每个线程均获得由C/C++运行期库的堆栈分配的自己的tiddata内存结构。（tiddata结构位于Mtdll.h文件中的VisualC++源代码中）。</p>
<p>&#8226;传递给_beginthreadex的线程函数的地址保存在tiddata内存块中。传递给该函数的参数也保存在该数据块中。</p>
<p>&#8226;_beginthreadex确实从内部调用CreateThread，因为这是操作系统了解如何创建新线程的唯一方法。</p>
<p>&#8226;当调用CreatetThread时，它被告知通过调用_threadstartex而不是pfnStartAddr来启动执行新线程。还有，传递给线程函数的参数是tiddata结构而不是pvParam的地址。</p>
<p>&#8226;如果一切顺利，就会像CreateThread那样返回线程句柄。如果任何操作失败了，便返回NULL。</p>
<p>5) _endthreadex的一些要点：</p>
<p>&#8226;C运行期库的_getptd函数内部调用操作系统的TlsGetValue函数，该函数负责检索调用线程的tiddata内存块的地址。</p>
<p>&#8226;然后该数据块被释放，而操作系统的ExitThread函数被调用，以便真正撤消该线程。当然，退出代码要正确地设置和传递。</p>
<p>6) 虽然也提供了简化版的的_beginthread和_endthread，但是可控制性太差，所以一般不使用。</p>
<p>6）线程handle因为是内核对象，所以需要在最后close handle。</p>
<p>7）C++主线程的终止，同时也会终止所有主线程创建的子线程，不管子线程有没有执行完毕。</p>
<p>8）如果某线程挂起，然后有调用WaitForSingleObject等待该线程，就会导致死锁。</p>
<p>二 线程同步之Critical Sections</p>
<p>1） 因为Critical Sections不是内核对象，所以只能用来同一进程内线程间的同步，不能用来多个不同进程间的线程的同步。</p>
<p>2） 如果在Critical Sections中间突然程序crash或是exit而没有调用LeaveCriticalSection，则结果是该线程所对应的内核不能被释放，该线程成为死线程。</p>
<p>3） 要比其他的内核对象的速度要快。</p>
<p>4）很好的封装：</p>
<p>class CritSect<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; friend class Lock;<br>&nbsp;&nbsp;&nbsp; CritSect() { InitializeCriticalSection(&amp;_critSection); }<br>&nbsp;&nbsp;&nbsp; ~CritSect() { DeleteCriticalSection(&amp;_critSection); }<br>private:<br>&nbsp;&nbsp;&nbsp; void Acquire(){EnterCriticalSection(&amp;_critSection);}<br>&nbsp;&nbsp;&nbsp; void Release(){LeaveCriticalSection(&amp;_critSection);}</p>
<p>&nbsp;&nbsp;&nbsp; CRITICAL_SECTION _critSection;<br>};</p>
<p>class Lock<br>{<br>public:<br>&nbsp;&nbsp;&nbsp;&nbsp; Lock(CritSect&amp; critSect):_critSect(critSect) {&nbsp;&nbsp;&nbsp; _critSect.Acquire(); }<br>&nbsp;&nbsp;&nbsp;&nbsp; ~Lock(){_critSect.Release();}<br>private:<br>&nbsp;&nbsp;&nbsp; CritSect&amp; _critSect;<br>};<br>调用：CritSect sect;Lock lock(sect);</p>
<p>三 线程同步之Mutex<br>&nbsp;&nbsp;&nbsp; <br>1）互斥对象（mutex）内核对象能够确保线程拥有对单个资源的互斥访问权。实际上互斥对象是因此而得名的。互斥对象包含一个使用数量，一个线程ID和一个递归计数器。<br>&nbsp;2） 互斥对象的行为特性与关键代码段相同，但是互斥对象属于内核对象，而关键代码段则属于用户方式对象。这意味着互斥对象的运行速度比关键代码段要慢。但是这也意味着不同进程中的多个线程能够访问单个互斥对象，并且这意味着线程在等待访问资源时可以设定一个超时值。</p>
<p>&nbsp;3） ID用于标识系统中的哪个线程当前拥有互斥对象，递归计数器用于指明该线程拥有互斥对象的次数。</p>
<p>&nbsp;4） 互斥对象有许多用途，属于最常用的内核对象之一。通常来说，它们用于保护由多个线程访问的内存块。如果多个线程要同时访问内存块，内存块中的数据就可能遭到破坏。互斥对象能够保证访问内存块的任何线程拥有对该内存块的独占访问权，这样就能够保证数据的完整性。</p>
<p>5）互斥对象的使用规则如下：</p>
<p>&#8226; 如果线程ID是0（这是个无效ID），互斥对象不被任何线程所拥有，并且发出该互斥对象的通知信号。</p>
<p>&#8226; 如果ID是个非0数字，那么一个线程就拥有互斥对象，并且不发出该互斥对象的通知信号。</p>
<p>&#8226; 与所有其他内核对象不同， 互斥对象在操作系统中拥有特殊的代码，允许它们违反正常的规则。</p>
<p><br>四 线程同步之Event</p>
<p>1）在所有的内核对象中，事件内核对象是个最基本的对象。它们包含一个使用计数（与所有内核对象一样），一个用于指明该事件是个自动重置的事件还是一个人工重置的事件的布尔值，另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。 </p>
<p>2）事件能够通知一个操作已经完成。有两种不同类型的事件对象。一种是人工重置的事件，另一种是自动重置的事件。当人工重置的事件得到通知时，等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时，等待该事件的线程中只有一个线程变为可调度线程。 </p>
<p>3）当一个线程执行初始化操作，然后通知另一个线程执行剩余的操作时，事件使用得最多。事件初始化为未通知状态，然后，当该线程完成它的初始化操作后，它就将事件设置为已通知状态。这时，一直在等待该事件的另一个线程发现该事件已经得到通知，因此它就变成可调度线程。</p>
<p>&nbsp;4）Microsoft为自动重置的事件定义了应该成功等待的副作用规则，即当线程成功地等待到该对象时，自动重置的事件就会自动重置到未通知状态。这就是自动重置的事件如何获得它们的名字的方法。通常没有必要为自动重置的事件调用ResetEvent函数，因为系统会自动对事件进行重置。但是，Microsoft没有为人工重置的事件定义成功等待的副作用，所以需要调用ResetEvent()。</p>
<p>五 线程同步之其他</p>
<p>1）线程局部存储 （TLS），同一进程中的所有线程共享相同的虚拟地址空间。不同的线程中的局部变量有不同的副本，但是static和globl变量是同一进程中的所有线程共享的。使用TLS技术可以为static和globl的变量，根据当前进程的线程数量创建一个array，每个线程可以通过array的index来访问对应的变量，这样也就保证了static和global的变量为每一个线程都创建不同的副本。</p>
<p>2）互锁函数的家族十分的庞大，例如InterlockedExchangeAdd（）。。。，使用互锁函数的优点是：他的速度要比其他的CriticalSection,Mutex,Event,Semaphore快很多。</p>
<p>3）等待函数，例如WaitForSingleObject 函数用来检测 hHandle 事件的信号状态，当函数的执行时间超过 dwMilliseconds 就返回，但如果参数 dwMilliseconds 为 INFINITE 时函数将直到相应时间事件变成有信号状态才返回，否则就一直等待下去，直到 WaitForSingleObject 有返回直才执行后面的代码。</p>
<p>六 《Windows核心编程（英文版&#183;第5版）》<br>最好的windows多线程编程参考，更多更详细请看原书。</p><img src ="http://www.cppblog.com/mzty/aggbug/57470.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2008-07-29 22:54 <a href="http://www.cppblog.com/mzty/archive/2008/07/29/57470.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>超越 C++ 下一代 C++ — C++/CLI简介（转载）</title><link>http://www.cppblog.com/mzty/archive/2008/07/18/56536.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Fri, 18 Jul 2008 14:28:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2008/07/18/56536.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/56536.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2008/07/18/56536.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/56536.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/56536.html</trackback:ping><description><![CDATA[<span class=a14c id=zoom>&nbsp;<br>
<p><strong>一、绪论</strong>
<p>当微软推出VS.NET7实现了可扩展的托管C++后，C++程序员们反映不一。尽管大部分的程序员对于能够继续使用C++感到很欣慰，但几乎所有的人对于托管C++提供的晦涩语法感到很痛苦。微软明显从反馈中感觉到托管C++不是那么成功。
<p>2003年10月6日，ECMA（欧洲计算机制造商协会）宣布成立专家组，负责结合ISO标准C++与通用语言，开发一个可扩展语言的标准，这个新的可扩展语言被称为C++/CLI标准。这个标准将被VS.NET2005的C++编译器支持。
<p><strong>二、老语法存在的问题</strong>
<p>1、晦涩繁琐的语法和文法--这两个"双重底线"问题加重了阅读的负担。
<p>2、二流的CLI支持--相对与C#与VB.NET，MC++使用不方便的工作区来提供CLI支持，例如，它没有一个一一对应的结构来列举.NET的集合。
<p>3、C++与.NET粗陋地结合--对于CLI类型，你不能使用C++的特色，例如模板；同样，对于C++类型，你不能使用CLI的特色，例如碎片帐集。
<p>4、令人混淆的指针--非托管的C++的指针及托管的引用指针都使用*语法，这非常令人混淆，因为-gc指针与托管指针在本质和行为上完全不同。
<p>5、MFC编译器不能产生可校验的代码。
<p><strong>三、C++/CLI给我们提供了什么？</strong>
<p>1、优雅流畅的语法和文法--C++/CLI为C++开发人员书写托管代码提供了一种非常自然的感觉，并且它提供了非托管代码到托管代码的平滑过度。以前所谓的"双重底线"问题现在已经荡然无存。
<p>2、一流的CLI支持--CLI特色，例如属性、碎片集合和属类得到了直接支持，此外，C++/CLI还准许将这些特色用于本地非托管的类。
<p>3、一流的C++类支持--C++特色，例如模板和析构函数对于拖管和非拖管类继续有效。实际上，C++/CLI是你可以"表面上"在栈或C++本地堆上声明一个.NET类型唯一的.NET语言。
<p>4、在.NET与C++之间的沟壑上架起了一座桥梁--C++开发人员在抨击BCL时不再象离开水的鱼。
<p>5、C++/CLI编译器产生的可执行文件完全是可校验的。
<p><strong>四、"Hello World"小程序</strong>
<p><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>using namespace System;
            void _tmain()
            {
            Console::WriteLine("Hello World");
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr>
<p>上述代码除了不需要引用mscorlib.dll库外，与老的语法没有太大的区别，因为无论你什么时候使用/clr进行编辑，编译器都可以暗中进行引用（现在默认的是/clr:newSyntax）。
<p><strong>五、句柄</strong>
<p>与老的语法主要的混淆是我们习惯于使用*符号来声明拖管引用或非拖管指针，在C++/CLI里微软引入了句柄的概念。
<p><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>void _tmain()
            {
            //The ^ punctuator represents a handle
            String^ str = "Hello World";
            Console::WriteLine(str);
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr>
<p>^符号代表一个托管对象（声明时看上去象个帽子），按照CLI的规定，句柄代表一个拖管对象的引用。句柄在CLI中是新的语法，相当于C++中的-gc指针。句柄与指针不再混淆，在本质上两者完全不同。
<p><strong>六、句柄与指针是怎样区分开来的？</strong>
<p>1、指针声明时使用*符号，而句柄使用^符号。
<p>2、句柄是针对拖管堆上对象的拖管引用，而指针仅仅指向内存中的一个地址。
<p>3、指针很稳定，GC循环不会影响到它；句柄在基于GC或内存紧张的情况下，可以指向不同的内存位置。
<p>4、对于指针，程序开发人员必须"显式"地删除，否则会面临泄露的危险，而对于句柄，是否进行显式删除则完全根据程序人员的爱好了。
<p>5、句柄一定要指向一个具体的类型，即所谓的类型安全性，而指针明显不是这样，你决不可以将一个句柄指向Void^类型。
<p>6、正如new操作符返回一个指针一样，gcnew返回一个句柄。
<p><strong>七、CLR对象示例</strong>
<p><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>void _tmain()
            {
            String^ str = gcnew String("Hello World");
            Object^ o1 = gcnew Object();
            Console::WriteLine(str);
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr>
<p>关键字gcnew用来实例化一个CLI对象，而且它返回一个指向在CLR堆上的对象的句柄，gcnew的优点在于它可以方便的让我们区分拖管和非拖管的实例对象。
<p>大部分情况下，gcnew关键字和^操作符提供了你用来进行BCL的一切手段，但是很明显你需要创建和声明属于自己的拖管类和接口。
<p><strong>八、声明类型 </strong>
<p>CLR类型有一个形容词前缀用来说明类型的种类，下面是C++/CLI中的类型声明示例：
<p><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>1、 CLR types
            o Reference types
            &#167; ref class RefClass;
            &#167; ref struct RefClass;
            2、 Value types
            &#167; value class ValClass;
            &#167; value struct ValClass;
            o Interfaces
            &#167; interface class IType;
            &#167; interface struct IType;
            o Enumerations
            &#167; enum class Color;
            &#167; enum struct Color;
            3、 Native types
            o class Native;
            o struct Native;
            示例：
            using namespace System;
            interface class IDog
            {
            void Bark();
            };
            ref class Dog : IDog
            {
            public:
            void Bark()
            {
            Console::WriteLine("Bow wow wow");
            }
            };
            void _tmain()
            {
            Dog^ d = gcnew Dog();
            d-&gt;Bark();
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr>
<p>上述程序中的代码与老的C++语言相比看上去非常简洁，在以往的C++代码中，至少要用到-gc和-interface这两个关键词。
<p><strong>九、装箱/拆箱操作</strong>
<p>在C++/CLI中，加箱是隐含的，而且类型是安全的，一个二进制的拷贝被执行并在CLR堆上形成一个对象，去箱是显式的，仅仅需要使用reinterpret_cast操作符来解除引用。
<p><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>void _tmain()
            {
            int z = 44;
            Object^ o = z; //implicit boxing
            int y = *reinterpret_cast&lt;int^&gt;(o); //unboxing
            Console::WriteLine("  ",o,z,y);
            z = 66;
            Console::WriteLine("  ",o,z,y);
            }
            // 输出结果如下：
            // 44 44 44
            // 44 66 44</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr>
<p>在上述代码中，"o"对象是一个加箱的拷贝，从第二个语句Console::WriteLine.的输出可以很明显地看到，它并没有涉及到int类型的整数值。
<p>当你对一种数值类型进行加箱操作时，返回的对象记住了最初的数值类型。
<p><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>void _tmain()
            {
            int z = 44;
            float f = 33.567;
            Object^ o1 = z;
            Object^ o2 = f;
            Console::WriteLine(o1-&gt;GetType());
            Console::WriteLine(o2-&gt;GetType());
            }
            // Output
            // System.Int32
            // System.Single</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr>
<p>因此不能对不同类型的对象进行去箱操作。
<p><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>void _tmain()
            {
            int z = 44;
            float f = 33.567;
            Object^ o1 = z;
            Object^ o2 = f;
            int y = *reinterpret_cast&lt;int^&gt;(o2);//System.InvalidCastException
            float g = *reinterpret_cast&lt;float^&gt;(o1);//System.InvalidCastException
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr>
<p>如果你非尝试这么做，那么你将得到一个System.InvalidCastException。让我们来探讨一下完美的类型安全性，如果你要看内部代码，你将看到微软的内部箱在实际中的运用。例如：
<p><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>void Box2()
            {
            float y=45;
            Object^ o1 = y;
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr>
<p>编译后的代码是：
<p><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>.maxstack 1
            .locals (float32 V_0, object V_1)
            ldnull
            stloc.1
            ldc.r4 45.
            stloc.0
            ldloc.0
            box [mscorlib]System.Single
            stloc.1
            ret</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr>
<p>根据微软的内部文档，箱操作将未加工的类型转换为一个具体类型的实例，这项工作的完成通过创建一个新的对象并将数据拷贝到这个新分配的对象。
<p><strong>十、写在后面的话</strong>
<p>为什么很多人已经可以使用C、C++、.NET来开发程序但还在积极学习C++/CLI呢，我想有四个方面的原因：
<p>1、从编译器直到内层都还在支持C++代码；
<p>2、C++/CLI对于其他标准来说无意是具有毁灭性地；
<p>3、与生俱来的内部支持胜过所有其他CLI语言
<p>4、所有在MFC中出现的下划线都已不再存在。</p>
</span><img src ="http://www.cppblog.com/mzty/aggbug/56536.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2008-07-18 22:28 <a href="http://www.cppblog.com/mzty/archive/2008/07/18/56536.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++/CLI：第一流的CLI语言(转载)</title><link>http://www.cppblog.com/mzty/archive/2008/07/18/56531.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Fri, 18 Jul 2008 14:12:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2008/07/18/56531.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/56531.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2008/07/18/56531.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/56531.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/56531.html</trackback:ping><description><![CDATA[<h1 id=artibodyTitle>&nbsp;</h1>
<h1>C++/CLI：第一流的CLI语言 <br>2005-08-25 11:25 作者： 朱先忠编译 出处： 天极网 责任编辑：方舟 </h1>
<p><strong>1. 简介<br><br></strong>　　本文并不是为了奉承C++/CLI的辉煌，也不是为了贬低其它如C#或者VB.NET等语言，相反，这只是一个非官方的、以一个喜欢这种语言的非<a class=bluekey href="http://com.chinabyte.com/microsoft/" target=_blank><u><font color=#0000ff>微软</font></u></a>雇员身份来论证C++/CLI有它的自己的唯一的角色，可作为第一流的.NET编程语言。<br><br>　　一个不断在新闻组和技术论坛上出现的问题是，当象C#和VB.NET这样的语言更适合于这种用途时，为什么要使用C++来开发.NET应用<a class=bluekey href="http://product.yesky.com/software/" target=_blank><u><font color=#0000ff>软件</font></u></a>。通常这样一些问题后面的评论说是，C++语法是怎样的复杂和令人费解，C++现在是怎样一种过时的语言，还有什么VS.NET<a class=bluekey href="http://design.yesky.com/" target=_blank><u><font color=#0000ff>设计</font></u></a>者已不再像支持C#和VB.NET一样继续支持C++。其中一些猜疑是完全荒谬的，但有些说法部分正确。希望本文有助于澄清所有这些围绕C++/CLI语言及其在VS.NET语言层次中的地位的疑惑，神秘和不信任。请记住，本作者既不为微软工作也没有从微软那里取得报酬，只是想从技术上对C++/CLI作一评判。<br><br>　　<strong>2. 快速简洁的本机interop</strong><br><br>　　除了P/Invoke机制可用在另外的象C#或VB.NET这样的语言外，C++提供了一种独有的interop机制，称作C++ interop。C++ interop比P/Invoke直观得多，因为你只是简单地#include需要的头文件，并与需要的库进行链接就能象在本机C++中一样调用任何函数。另外，它比P/Invoke速度快--这是很容易能证明的。现在，可争辩的是在实际应用软件的开发中，经由C++ interop获得的性能好处与花在用户接口交互、数据库存取、<a class=bluekey href="http://product.yesky.com/net/" target=_blank><u><font color=#0000ff>网络</font></u></a>数据转储、复杂数学算法等方面的时间相比可以被忽略，但是事实是在有些情况下，甚至通过每次interop调用节省的几个纳秒也能给全局应用<a class=bluekey href="http://dev.yesky.com/" target=_blank><u><font color=#0000ff>程序</font></u></a>性能/响应造成巨大影响，这是绝对不能被忽视的。下面有两部分代码片断(一个是使用P/Invoke机制的C#程序，一个是使用C++ Interop机制的C++程序)，我分别记录了其各自代码重复执行消耗的时间(毫秒)。不管你如何解释这些数据，不管这会对你的应用程序产生什么影响，全是你的事。我仅打算事实性地指出，C++代码的执行速度要比C#(其中使用了较多的本机interop调用)快。<br><br>　　1) C#程序(使用P/Invoke)<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>[SuppressUnmanagedCodeSecurity] <br>[DllImport("kernel32.dll")]<br>static extern uint GetTickCount();<br>[SuppressUnmanagedCodeSecurity] <br>[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]<br>static extern uint GetWindowsDirectory(<br>[Out] StringBuilder lpBuffer, uint uSize);<br>static void Test(int x)<br>{<br>StringBuilder sb = new StringBuilder(512);<br>for (int i = 0; i &lt; x; i++)<br>GetWindowsDirectory(sb, 511);<br>}<br>static void DoTest(int x)<br>{<br>uint init = GetTickCount();<br>Test(x);<br>uint tot = GetTickCount() - init;<br>Console.WriteLine("Took {0} milli-seconds for {1} iterations",tot, x);<br>}<br>static void Main(string[] args)<br>{<br>DoTest(50000);DoTest(500000);DoTest(1000000);DoTest(5000000);<br>Console.ReadKey(true);<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　2) C++程序(使用C++ Interop)<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>void Test(int x)<br>{<br>TCHAR buff[512];<br>for(int i=0; i&lt;x; i++)<br>GetWindowsDirectory(buff, 511);<br>}<br>void DoTest(int x)<br>{<br>DWORD init = GetTickCount();<br>Test(x);<br>DWORD tot = GetTickCount() - init;<br>Console::WriteLine("Took {0} milli-seconds for {1} iterations",tot, x);<br>}<br>int main(array&lt;System::String ^&gt; ^args)<br>{ <br>DoTest(50000);DoTest(500000);DoTest(1000000);DoTest(5000000);<br>Console::ReadKey(true);<br>return 0;<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　3) 速度比较<br><br>
<table cellSpacing=0 cellPadding=2 width="90%" align=center border=1>
    <tbody>
        <tr>
            <td>重复次数 </td>
            <td>C# 程序</td>
            <td>C++程序</td>
        </tr>
        <tr>
            <td>50,000</td>
            <td>61 </td>
            <td>10</td>
        </tr>
        <tr>
            <td>500,000</td>
            <td>600 </td>
            <td>70</td>
        </tr>
        <tr>
            <td>1,000,000</td>
            <td>1162</td>
            <td>140</td>
        </tr>
        <tr>
            <td>5,000,000</td>
            <td>6369</td>
            <td>721</td>
        </tr>
    </tbody>
</table>
　　 <br>　　其性能差别真是令人惊愕！这的确是说明为什么要使用C++/CLI的一个好理由，如果你在使用本机interop进行开发，那么性能！完全由于性能，我就将被迫借助本机interop来实现并非基于web的.NET应用程序。当然，为什么我想要使用.NET来开发需要大量本机interop技术的应用程序完全是另外一个问题。<br><br>　　如果你仍怀疑这种性能优势，有另外的理由来说明你为什么不得不使用C++/CLI而不是C#或VB.NET——源码膨胀！下面是一个C++函数的例子，它使用了IP帮助者API来枚举一台机器上的网络适配器并且列出与每个适配器相联系的所有IP地址。<br><br>　　4) 枚举n/w适配器的C++代码<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>void ShowAdapInfo()<br>{<br>PIP_ADAPTER_INFO pAdapterInfo = NULL;<br>ULONG OutBufLen = 0;<br>//得到需要的缓冲区大小<br>if(GetAdaptersInfo(NULL,&amp;OutBufLen)==ERROR_BUFFER_OVERFLOW)<br>{<br>int divisor = sizeof IP_ADAPTER_INFO;<br>#if _MSC_VER &gt;= 1400<br>if( sizeof time_t == 8 ) divisor -= 8;<br>#endif<br>pAdapterInfo = new IP_ADAPTER_INFO[OutBufLen/divisor];<br>//取得适配器信息<br>if( GetAdaptersInfo(pAdapterInfo, &amp;OutBufLen) != ERROR_SUCCESS )<br>{//调用失败 }<br>else <br>{<br>int index = 0;<br>while(pAdapterInfo)<br>{<br>Console::WriteLine(gcnew String(pAdapterInfo-&gt;Description));<br>Console::WriteLine("IP Address list : ");<br>PIP_ADDR_STRING pIpStr = &amp;pAdapterInfo-&gt;IpAddressList;<br>while(pIpStr)<br>{<br>Console::WriteLine(gcnew tring(pIpStr-&gt;IpAddress.String));<br>pIpStr = pIpStr-&gt;Next;<br>}<br>pAdapterInfo = pAdapterInfo-&gt;Next;<br>Console::WriteLine();<br>}<br>}<br>delete[] pAdapterInfo;<br>}<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　现在让我们看一个使用P/Invoke的C#版本。<br><br>　　5) 使用P/Invoke技术的C#版本<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>const int MAX_ADAPTER_NAME_LENGTH = 256;<br>const int MAX_ADAPTER_DESCRIPTION_LENGTH = 128;<br>const int MAX_ADAPTER_ADDRESS_LENGTH = 8;<br>const int ERROR_BUFFER_OVERFLOW = 111;<br>const int ERROR_SUCCESS = 0;<br>[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]<br>public struct IP_ADDRESS_STRING<br>{<br>[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]<br>public string Address;<br>}<br>[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]<br>public struct IP_ADDR_STRING<br>{<br>public IntPtr Next;<br>public IP_ADDRESS_STRING IpAddress;<br>public IP_ADDRESS_STRING Mask;<br>public Int32 Context;<br>}<br>[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]<br>public struct IP_ADAPTER_INFO<br>{<br>public IntPtr Next;<br>public Int32 ComboIndex;<br>[MarshalAs(UnmanagedType.ByValTStr, <br>SizeConst = MAX_ADAPTER_NAME_LENGTH + 4)]<br>public string AdapterName;<br>[MarshalAs(UnmanagedType.ByValTStr, <br>SizeConst = MAX_ADAPTER_DESCRIPTION_LENGTH + 4)]<br>public string AdapterDescription;<br>public UInt32 AddressLength;<br>[MarshalAs(UnmanagedType.ByValArray, <br>SizeConst = MAX_ADAPTER_ADDRESS_LENGTH)]<br>public byte[] Address;<br>public Int32 Index;<br>public UInt32 Type;<br>public UInt32 DhcpEnabled;<br>public IntPtr CurrentIpAddress;<br>public IP_ADDR_STRING IpAddressList;<br>public IP_ADDR_STRING GatewayList;<br>public IP_ADDR_STRING DhcpServer;<br>public bool HaveWins;<br>public IP_ADDR_STRING PrimaryWinsServer;<br>public IP_ADDR_STRING SecondaryWinsServer;<br>public Int32 LeaseObtained;<br>public Int32 LeaseExpires;<br>}<br>[DllImport("iphlpapi.dll", CharSet = CharSet.Ansi)]<br>public static extern int GetAdaptersInfo(IntPtr pAdapterInfo, ref int pBufOutLen);<br>static void ShowAdapInfo()<br>{<br>int OutBufLen = 0; <br>//得到需要的缓冲区大小<br>if( GetAdaptersInfo(IntPtr.Zero, ref OutBufLen) == <br>ERROR_BUFFER_OVERFLOW )<br>{<br>IntPtr pAdapterInfo = Marshal.AllocHGlobal(OutBufLen); <br>//取得适配器信息<br>if( GetAdaptersInfo(pAdapterInfo, ref OutBufLen) != ERROR_SUCCESS )<br>{ //调用失败了 }<br>else{<br>while(pAdapterInfo != IntPtr.Zero)<br>{<br>IP_ADAPTER_INFO adapinfo = <br>(IP_ADAPTER_INFO)Marshal.PtrToStructure(<br>pAdapterInfo, typeof(IP_ADAPTER_INFO));<br>Console.WriteLine(adapinfo.AdapterDescription);<br>Console.WriteLine("IP Address list : ");<br>IP_ADDR_STRING pIpStr = adapinfo.IpAddressList;<br>while (true){<br>Console.WriteLine(pIpStr.IpAddress.Address);<br>IntPtr pNext = pIpStr.Next;<br>if (pNext == IntPtr.Zero)<br>break;<br>pIpStr = (IP_ADDR_STRING)Marshal.PtrToStructure(<br>pNext, typeof(IP_ADDR_STRING));<br>}<br>pAdapterInfo = adapinfo.Next;<br>Console.WriteLine(); <br>}<br>}<br>Marshal.FreeHGlobal(pAdapterInfo);<br>}<br>}</td>
        </tr>
    </tbody>
</table>
<br><br>3. 栈语义和确定性的析构<br><br>　　C++经由栈语义模仿给了我们确定性的析构。简言之，栈语义是Dispose模式的良好的语法替代品。但是它在语义上比C# using块语法更直观些。请看下列的C#和C++代码段（都做一样的事情-连接两个文件的内容并把它写到第三个文件中）。<br><br>　　1) C#代码--使用块语义<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>public static void ConcatFilestoFile(String file1, String file2, String outfile)<br>{<br>String str;<br>try{<br>using (StreamReader tr1 = new StreamReader(file1))<br>{<br>using (StreamReader tr2 = new StreamReader(file2))<br>{<br>using (StreamWriter sw = new StreamWriter(outfile))<br>{<br>while ((str = tr1.ReadLine()) != null)<br>sw.WriteLine(str);<br>while ((str = tr2.ReadLine()) != null)<br>sw.WriteLine(str);<br>}<br>}<br>}<br>}<br>catch (Exception e)<br>{ Console.WriteLine(e.Message); }<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　2) C++代码--栈语义<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>static void ConcatFilestoFile(String^ file1, String^ file2, String^ outfile)<br>{<br>String^ str;<br>try{<br>StreamReader tr1(file1);<br>StreamReader tr2(file2);<br>StreamWriter sw(outfile);<br>while(str = tr1.ReadLine())<br>sw.WriteLine(str);<br>while(str = tr2.ReadLine())<br>sw.WriteLine(str);<br>}<br>catch(Exception^ e)<br>{ Console::WriteLine(e-&gt;Message); }<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　C#代码与相等的C++ 代码相比不仅免不了冗长，而且using块语法让程序员自己明确地指定他想在哪儿调用Dispose（using块的结束处），而使用C++/CLI的栈语义，只需让编译器使用常规的范围规则来处理它即可。事实上，这使得在C#中修改代码比在C++中更乏味-作为一实例，让我们修改这些代码以便即使仅存在一个输入文件也能创建输出文件。请看下面修改后的C#和C++代码。<br><br>　　3) 修改后的C#代码<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>public static void ConcatFilestoFile(String file1, String file2, String outfile)<br>{<br>String str;<br>try{<br>using (StreamWriter sw = new StreamWriter(outfile))<br>{<br>try{<br>using (StreamReader tr1 = new StreamReader(file1))<br>{<br>while ((str = tr1.ReadLine()) != null)<br>sw.WriteLine(str);<br>}<br>}<br>catch (Exception) { }<br>using (StreamReader tr2 = new StreamReader(file2))<br>{<br>while ((str = tr2.ReadLine()) != null)<br>sw.WriteLine(str);<br>}<br>}<br>}<br>catch (Exception e){ }<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　把针对StreamWriter的using块放到顶层需要重新调整using块结构--这在上面情况下显然不是个大问题，但是对于实际开发中的修改，这可能是相当模糊的且易导致逻辑错误的。<br><br>　　4) 修改后的C++代码<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>static void ConcatFilestoFile(String^ file1, String^ file2, String^ outfile)<br>{<br>String^ str;<br>try{<br>StreamWriter sw(outfile);<br>try{<br>StreamReader tr1(file1); <br>while(str = tr1.ReadLine())<br>sw.WriteLine(str); <br>}<br>catch(Exception^){} <br>StreamReader tr2(file2); <br>while(str = tr2.ReadLine())<br>sw.WriteLine(str); <br>}<br>catch(Exception^){}<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　这样不是比在C#中的做更容易些吗？我恰好把StreamWriter声明移到了顶部并增加了一个额外的try块，就这些。甚至对于象在我的示例代码片断中的琐碎事情，如果所涉及的复杂性在C++中大大减少，那么，当你工作于更大的工程时你能想象使用栈语义对你的编码效率千万的影响。<br><br>　　还不确信？好，让我们看一下成员对象和它们的析构吧。Imagine CLI GC类R1和R2，二者都实现了Idisposable接口且都有函数F()，还有一个CLI GC类R，它有R1和R2成员和一个函数F()-它内部地调用R1和R2上的F()成员函数。让我们先看C#实现。<br><br>　　5) 一个disposable类继承层次的C#实现<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>class R1 : IDisposable{<br>public void Dispose() { }<br>public void F() { }<br>}<br>class R2 : IDisposable{<br>public void Dispose() { }<br>public void F() { }<br>}<br>class R : IDisposable{<br>R1 m_r1 = new R1();<br>R2 m_r2 = new R2();<br>public void Dispose() <br>{ <br>m_r1.Dispose();<br>m_r2.Dispose();<br>}<br>public void F() <br>{<br>m_r1.F();<br>m_r2.F();<br>}<br>public static void CallR()<br>{<br>using(R r = new R())<br>{r.F();}<br>}<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　这里有几件事情要做：必须为每个disposable 类手工实现IDisposable接口，对于具有成员R1和R2的类R，Dispose方法也需要调用成员类上的Dispose。现在让我们分析上面几个类的C++实现。<br><br>　　6) 等价的C++实现<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>ref class R1<br>{<br>public:<br>~R1(){}<br>void F(){}<br>};<br>ref class R2<br>{<br>public:<br>~R2(){}<br>void F(){}<br>};<br>ref class R<br>{<br>R1 m_r1;<br>R2 m_r2;<br>public:<br>~R(){}<br>void F()<br>{<br>m_r1.F();<br>m_r2.F();<br>}<br>static void CallR()<br>{<br>R r;<br>r.F();<br>}<br>};</td>
        </tr>
    </tbody>
</table>
<br>　　注意，这里不再有手工的Idisposable接口实现(我们的类中仅建立了析构器)而且最好的部分--类R的析构器(Dispose方法)并没有在该类可能含有的可释放的成员上调用Dispose-它没有必要这样做，编译器自动为之生成所有的代码！ <br><br>4. 混合类型<br><br>　　我们知道，C++支持本机类型-总是如此；C++支持CLI类型-本文正是特别强调这一点；它还支持混合类型-具有CLI成员的本机类型和具有本机成员的CLI类型！请尽管考虑所有你能的可能需求。<br><br>　　注意，谈到Whidbey，混合类型实现还不完整；就我从Brandon，Herb和Ronald发表的材料的理解得知，存在这种相当酷的类型--统一模型，它将在Orcas中实现--你能够在本机C++堆上new/delete CLI类型，而且也能够在CLI堆上gcnew/delete本机类型。但既然这是Whidbey以后的东西，本文不讨论统一模型。<br><br>　　在我谈论你何时使用混合类型以前，我想向你说明什么是混合类型。如果你理解混合类型，请跳过下面几段。这里引用Brandon Bray的说法："一种混合类型，或者是本机类ref类（需要有对象成员），或者是通过声明或继承被分配在垃圾回收堆或本机堆上的。"因此如果你有一个托管类型或者有一个有托管成员的本机类型，你就有了一个混合类型。VC++ Whidbey不直接支持混合类型(统一类型模型是一种Whidbey之后的概念)，但是它给我们划定了实现混合类型的条件。让我们开始讨论包含托管成员的本机类型。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>ref class R<br>{<br>public:<br>void F(){}<br>//假定 non-trivial ctor/dtor<br>R(){}<br>~R(){}<br>};</td>
        </tr>
    </tbody>
</table>
<br>　　在我的例子中，设想该托管类型R有一个non-trivial构造器和一个non-trivial析构器。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>class Native<br>{<br>private:<br>gcroot&lt;R^&gt; m_ref; <br>public:<br>Native():<br>m_ref(gcnew R()){} <br>~Native()<br>{ delete m_ref; }<br>void DoF()<br>{ m_ref-&gt;F(); }<br>};</td>
        </tr>
    </tbody>
</table>
<br>　　既然，我不能在我的类中拥有一个R成员，我使用了gcroot模板类(在gcroot.h中声明，但是你要用"#include vcclr.h")，它包装了System::Runtime::InteropServices::GCHandle结构。它是个象类一样的灵敏指针，它重载了运算符-&gt;以返回用作模板参数的托管类型。因此在上面类中，我可以使用m_ref，就好象我已经声明它是R^，而且你能在DoF函数中看到这正在起作用。实际上你可以节省delete，这可以通过使用auto_gcroot(类似于std::auto_ptr，在msclr\auto_gcroot.h文件中声明)代替gcroot来实现。下面是一个更好些的使用auto_gcroot的实现。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>class NativeEx<br>{<br>private:<br>msclr::auto_gcroot&lt;R^&gt; m_ref; <br>public:<br>NativeEx() : m_ref(gcnew R()){}<br>void DoF()<br>{ m_ref-&gt;F(); }<br>};</td>
        </tr>
    </tbody>
</table>
<br>　　下面让我们看相反的情形：一个CLI类的本机成员。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>ref class Managed<br>{<br>private:<br>Native* m_nat;<br>public:<br>Managed():m_nat(new Native()){ }<br>~Managed()<br>{ delete m_nat; }<br>!Managed()<br>{ delete m_nat;<br>#ifdef _DEBUG<br>throw gcnew Exception("Oh, finalizer got called!");<br>#endif<br>}<br>void DoF()<br>{ m_nat-&gt;DoF(); }<br>};</td>
        </tr>
    </tbody>
</table>
<br>　　我不能定义一个Native对象来作为一个ref类成员，因此需要使用一个Native*对象来代替。我在构造器中new该Native对象，然后在析构器和finalizer中delete它。如果你运行该工程的调试版，在执行到finalizer时将抛出一个异常- 因此开发者可以马上添加一个对delete的调用或为他的CLI类型使用栈语义技术。奇怪的是，库开发小组没有建立一个gcroot的反向实现-但这不是个大问题，我们可以自己写。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>template&lt;typename T&gt; ref class nativeroot<br>{<br>T* m_t;<br>public:<br>nativeroot():m_t(new T){}<br>nativeroot(T* t):m_t(t){}<br>T* operator-&gt;()<br>{ return m_t; }<br>protected:<br>~nativeroot()<br>{ delete m_t; }<br>!nativeroot()<br>{<br>delete m_t;<br>#ifdef _DEBUG<br>throw gcnew Exception("Uh oh, finalizer got called!");<br>#endif<br>}<br>};</td>
        </tr>
    </tbody>
</table>
<br>　　这仅是个相当简单的灵敏指针实现，就象一个负责本机对象分配/回收的ref类。不管怎样，借助nativeroot模板类，我们可以如下修改托管类：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>ref class ManagedEx<br>{<br>private:<br>nativeroot&lt;Native&gt; m_nat;<br>public:<br>void DoF()<br>{ m_nat-&gt;DoF(); }<br>};</td>
        </tr>
    </tbody>
</table>
<br>　　好，关于混合类型的最大问题是什么呢？你可能问。最大问题是，现在你能混合使用你的MFC、ATL、WTL、STL代码仓库和.NET框架，并用可能的最直接的方式-只需写你的混合模式代码并编译实现!你可以建立在一个DLL库中建立MFC 类，然后建立一个.NET应用程序来调用这个DLL，还需要把.NET类成员添加到你的MFC类（也实现可以相反的情况）。<br><br>　　作为一例，设想你有一MFC对话框--它通过一个多行的编辑框接受来自用户的数据-现在，你有一新的要求-显示一个只读编辑框，它将显示当前在该多行编辑框中文本的md5哈希结果。你的队友正在悲叹他们将必须花费几个小时钻研crypto API，而你的上司在担忧你们可能必须要买一个第三方加密库；那正是你在他们面前树立形象的时候，你宣布你将在15分钟内做完这项任务。下面是解决的办法：<br><br>　　添加一个新的编辑框到你的对话框资源中，并且添加相应的DDX变量。选择/clr编译模式并且添加下列代码到你的对话框的头文件中： <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>#include &lt;msclr\auto_gcroot.h&gt;<br>using namespace System::Security::Cryptography;</td>
        </tr>
    </tbody>
</table>
<br>　　使用auto_gcroot模板来声明一个MD5CryptoServiceProvider成员：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>protected:<br>msclr::auto_gcroot&lt;MD5CryptoServiceProvider^&gt; md5;</td>
        </tr>
    </tbody>
</table>
<br>　　在OnInitDialog过程中，gcnew MD5CryptoServiceProvider成员。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>md5 = gcnew MD5CryptoServiceProvider();</td>
        </tr>
    </tbody>
</table>
<br>　　并且为多行编辑框添加一个EN_CHANGE处理器：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>void CXxxxxxDlg::OnEnChangeEdit1()<br>{<br>using namespace System;<br>CString str;<br>m_mesgedit.GetWindowText(str);<br>array&lt;Byte&gt;^ data = gcnew array&lt;Byte&gt;(str.GetLength());<br>for(int i=0; i&lt;str.GetLength(); i++)<br>data[i] = static_cast&lt;Byte&gt;(str[i]);<br>array&lt;Byte&gt;^ hash = md5-&gt;ComputeHash(data);<br>CString strhash;<br>for each(Byte b in hash)<br>{<br>str.Format(_T("%2X "),b);<br>strhash += str;<br>}<br>m_md5edit.SetWindowText(strhash);<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　这里使用了混合类型：一个本机Cdialog派生类，该类含有一个MD5CryptoServiceProvider成员(CLI类型)。你可以轻易地试验相反的情况（如早期的代码片断已显示的）——可以建立一个Windows表单应用程序而且可能想利用一个本机类库--这不成问题，使用上面定义的模板nativeroot即可。<br><br>5. 托管模板<br><br>　　也许你对泛型的概念已很清楚了，它帮助你避免进入C++的模板梦魇，它是实现模板的最佳方式，等等。好，假设这些全部正确，C++/CLI支持泛型就象任何其它CLI语言一样-但是它有而其它一些CLI语言还没有的是它还支持托管模板-也就是模板化的ref和value类。如果你以前从未使用过模板，你不能一下欣赏这么多优点，但是如果你有模板使用背景而且你已发现了泛型中存在的可能限制你编码的方式，托管模板将会大大减轻你的负担。你能联合使用泛型和模板- 事实上有可能用一个托管类型的模板参数来实例化一个泛型类型(尽管相反的情形是不可能的，因为运行时刻实例化由泛型所用)。STL.NET (或STL/CLR)以后讨论，请很好地利用泛型和托管模板的混合编程吧。<br><br>　　泛型使用的子类型约束机制将防止你写出下面的代码：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>generic&lt;typename T&gt; T Add(T t1, T t2)<br>{ return t1 + t2; }</td>
        </tr>
    </tbody>
</table>
<br>　　编译错误：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>error C2676: binary &#8217;+&#8217; : &#8217;T&#8217; does not define this operator or a conversion to a type acceptable to the predefined operator</td>
        </tr>
    </tbody>
</table>
<br>　　现在请看相应的模板版本：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>template&lt;typename T&gt; T Add(T t1, T t2)<br>{ return t1 + t2; }</td>
        </tr>
    </tbody>
</table>
<br>　　那么就可以这样做：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>int x1 = 10, x2 = 20;<br>int xsum = Add&lt;int&gt;(x1, x2);</td>
        </tr>
    </tbody>
</table>
<br>　　还可以这样做：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>ref class R<br>{<br>int x; <br>public:<br>R(int n):x(n){}<br>R^ operator+(R^ r)<br>{ return gcnew R(x + r-&gt;x); }<br>};<br>//...<br>R^ r1 = gcnew R(10);<br>R^ r2 = gcnew R(20);<br>R^ rsum = Add&lt;R^&gt;(r1, r2);</td>
        </tr>
    </tbody>
</table>
<br>　　这在一个象int的本机类型以及一个ref类型(只要ref类型有一个+运算符)情况下都能工作良好。这个泛型缺点不是一个调试错误或缺陷-它是设计造成的。泛型的实例化是在运行时通过调用配件集实现的，因此编译器不能确知一特定操作能被施行于一个泛型参数，除非它匹配一个子类型约束，因此编译器在定义泛型时解决这个问题。当你使用泛型时的另外一个妨碍是，它不会允许你使用非类型参数。下列泛型类定义不会编译：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>generic&lt;typename T, int x&gt; ref class G{};</td>
        </tr>
    </tbody>
</table>
<br>　　编译错：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>error C2978: syntax error : expected &#8217;typename&#8217; or &#8217;class&#8217;; found type &#8217;int&#8217;; non-type parameters are not supported in generics</td>
        </tr>
    </tbody>
</table>
<br>　　与托管模板相比较：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>template&lt;typename T, int x = 0&gt; ref class R{};</td>
        </tr>
    </tbody>
</table>
<br>　　如果你开始感激C++向你提供了泛型和托管模板，那么请看下面这一个例子： <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>template&lt;typename T&gt; ref class R{<br>public:<br>void F()<br>{ Console::WriteLine("hey"); }<br>}; <br>template&lt;&gt; ref class R&lt;int&gt;<br>{<br>public:<br>void F()<br>{ Console::WriteLine("int"); }<br>};</td>
        </tr>
    </tbody>
</table>
<br>　　你不能用泛型这样编码；否则，将产生：<br><br>　　编译错：error C2979: explicit specializations are not supported in generics<br><br>　　但可以在继承链中混合使用模板和泛型：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>generic&lt;typename T&gt; ref class Base<br>{<br>public:<br>void F1(T){}<br>};<br>template&lt;typename T&gt; ref class Derived : Base&lt;T&gt;<br>{<br>public:<br>void F2(T){}<br>};<br>//...<br>Derived&lt;int&gt; d;<br>d.F1(10);<br>d.F2(10);</td>
        </tr>
    </tbody>
</table>
<br>　　最后，你不能从一个泛型参数类型派生一个泛型类。<br><br>　　下列代码不会成功编译：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>generic&lt;typename T&gt; ref class R : T<br>{};</td>
        </tr>
    </tbody>
</table>
<br>　　error C3234: a generic class may not derive from a generic type parameter<br><br>　　模板让你这样做(好像你还不知道这些)：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>ref class Base{<br>public:<br>void F(){}<br>};<br>generic&lt;typename T&gt; ref class R : T<br>{};<br>//...<br>R&lt;Base&gt; r1;<br>r1.F();</td>
        </tr>
    </tbody>
</table>
<br>　　这样，当你下次遇到对泛型的贬谤时，你就知道该怎么做了。<br><br>　　6. STL/CLR<br><br>　　当大量使用STL的C++开发者转向.NET1/1.1时一定感觉非常别扭，他们中的许多可能会放弃并转回到原来的本机编码。从技术上讲，你能结合.NET类型(using gcroot)使用本机STL，但是产生的结果代码可能相当低效，更不用说是丑陋了：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>std::vector&lt; gcroot&lt;IntPtr&gt; &gt;* m_vec_hglobal;<br>//...<br>for each(gcroot&lt;IntPtr&gt; ptr in *m_vec_hglobal)<br>{ Marshal::FreeHGlobal(ptr);}</td>
        </tr>
    </tbody>
</table>
<br>　　大概VC++小组考虑到了这些并决定在Whidbey以后，他们会提供STL.NET（或STL/CLR）并可以单独从网上下载。<br><br>　　你可能问为什么？Stan Lippman，在他的MSDN文章(STL.NET Primer)中给出了3条原因：<br><br>　　&#183;可扩展性--STL设计把算法和容器隔离到自己的应用空间-也就是你可以有一组容器和一组算法，并且你能在任何一个容器上使用这些算法；同时你能在任何一个算法中使用这些容器。因此，如果你添加一种新的算法，你能在任何一种容器中使用它；同样，一个新的容器也可以与现有算法配合使用。<br><br>　　&#183;统一性--所有核心C++开发者集中在一起，汇集起他们精妙的STL专长，再使用他们的专长则轻车熟路。要较好地使用STL需要花费时间-然而一旦你掌握了它，你就有了在.NET世界中使用你的技巧的明显优势。不是吗？<br><br>　　&#183;性能--STL.NET通过使用实现泛型接口的托管模板实现。并且既然它的核心已用C++和托管模板编码，可以期盼它比在BCL上使用的泛型容器更具有性能优势。<br><br>　　使用过STL的人不需要任何示范，所以下面代码有益于以前没有使用过STL的人。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>vector&lt;String^&gt; vecstr;<br>vecstr.push_back("wally");<br>vecstr.push_back("nish");<br>vecstr.push_back("smitha");<br>vecstr.push_back("nivi");<br>deque&lt;String^&gt; deqstr;<br>deqstr.push_back("wally");<br>deqstr.push_back("nish");<br>deqstr.push_back("smitha");<br>deqstr.push_back("nivi");</td>
        </tr>
    </tbody>
</table>
<br>　　我使用了两个STL.NET容器-vector和deque，并装满两个容器，使其看起来相同(在两个容器中都使用了push_back)。现在，我将在两个容器上使用replace算法-我们再次看到，这些代码是很相同的。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>replace(vecstr.begin(), vecstr.end(),<br>gcnew String("nish"), gcnew String("jambo"));<br>replace(deqstr.begin(), deqstr.end(),<br>gcnew String("nish"), gcnew String("chris")); </td>
        </tr>
    </tbody>
</table>
<br>　　这里特别要注意的是我使用了"同样"的算法--replace并在两个不同STL容器上使用相同的函数调用。这是当Stan谈及"可扩展性"时的意思。下面我用一个简单函数来证明：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>template&lt;typename ForwardIterator&gt; void Capitalize(<br>ForwardIterator first，ForwardIterator end)<br>{<br>for(ForwardIterator it = first; it &lt; end; it++) <br>*it = (*it)-&gt;ToUpper(); <br>}</td>
        </tr>
    </tbody>
</table>
<br>　　它遍历一个System::String^容器并把其中的每个字符串转化为大写。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>Capitalize(vecstr.begin(), vecstr.end());<br>Capitalize(deqstr.begin(), deqstr.end());<br>for(vector&lt;String^&gt;::iterator it = vecstr.begin(); <br>it &lt; vecstr.end(); it++)<br>Console::WriteLine(*it);<br>Console::WriteLine();<br>for(deque&lt;String^&gt;::iterator it = deqstr.begin(); <br>it &lt; deqstr.end(); it++)<br>Console::WriteLine(*it);</td>
        </tr>
    </tbody>
</table>
<br>　　上面我的算法能够与vector和deque容器工作良好。至此，不再细谈；否则，guru站上的STL爱好者们会对我群起攻击，而非STL人可能感到厌烦。如果你还没使用过STL，可以参考有关资料。<br><br>7. 熟悉的语法<br><br>　　开发者经常迷恋他们所用的编程语言，而很少是出于实用的目的。还记得当微软宣布不再为VB6提供官方支持时，VB6人的反抗吗？非VB6人对此可能非常震惊，而老道的VB6人早已为他们的语言作好葬礼准备了。事实上，如果VB.NET从来没被发明，多数VB6人将会离开.NET，因为C#将会对他们非常陌生，而它的祖先就是C++。如今，许多VB.NET人可能已经转向了C#，但是他们不会从VB6直接转向C#；VB.NET起到一个桥梁作用让他们的思想脱离开原来VB6思想。相应地，如果微软仅发行VB.NET(而没有C#)，那么.NET可能成为了新的面向对象VB，且带有一个更大的类库-C++社团的人可能对此嗤之以鼻-他们甚至不会麻烦地检验.NET基础类库。为什么任何使用一种特定语言的开发者会对另外一个团体的使用另外开发语言的开发者嗤之以鼻？这不是我要回答的问题。--要回答该问题也许要先回答为什么有的人喜欢威士忌，有的人喜欢可口可乐，而还有人喜欢牛奶。所有我要说的是，对开发者来说，语法家族是个大问题。<br><br>　　你认为对于一个具有C++背景的人，下面的代码具有怎样的直觉性？<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>char[] arr =new char[128];</td>
        </tr>
    </tbody>
</table>
<br>　　他/她可能回答的第一件事是，方括号放错了位置。下面这句又如何？<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>int y=arr.Length;</td>
        </tr>
    </tbody>
</table>
<br>　　"呀!"-最可能的反映。现在把下面与前面相比较：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>char natarr[128];<br>array&lt;char&gt;^ refarr=gcnew array&lt;char&gt;(128);<br>int y=refarr-&gt;Length;</td>
        </tr>
    </tbody>
</table>
<br>　　请注意声明一个本机数组和一个托管数组时的语法区别。这里不同的模板形式的语法可视化地告诫开发者这一事实--refarr并不是典型的C++数组而且它可能是某种CLI类的派生物(事实上确是如此)，所以极有可能可以把方法和属性应用于它。<br><br>　　C#的finalizer语法最有可能引起转向C#的C++程序员的混淆。请看见下列C#代码：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>class R<br>{ ~R(){} }</td>
        </tr>
    </tbody>
</table>
<br>　　好，这样~R看起来象一个析构器但实际是个finalizer。为什么？请与下面的C++代码比较：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>ref class R<br>{<br>~R(){ }<br>!R(){ }<br>};</td>
        </tr>
    </tbody>
</table>
<br>　　这里~R是析构器（实际上等价于一个析构器的Dispose模式-但对C++人员来说，这它的行为象个析构器）而新的!R语法是为finalizer建立的-这样就不再有混淆而且语法看上去也与本机C++相匹配。<br><br>　　请看一下C#泛型语法：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>class R&lt;T&gt;{};</td>
        </tr>
    </tbody>
</table>
<br>　　再请看一下C++的语法：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>generic&lt;typename T&gt; ref class R{};</td>
        </tr>
    </tbody>
</table>
<br>　　曾经使用过模板的人马上就看出这种C++语法，而C#语法不能保证其没有混淆性且也不直观。我的观点是，如果你以前具有C++背景，C++/CLI语法将最贴近于你以前所用。C#(以及J#)看上去象C++，但是还有相当多的极为使人烦火的奇怪语义差别而且如果你没有完全放弃C++，语法差别将永远不停地带给你混乱和挫折。从这种意义上说，我认为VB.NET更好些，至少它有自己唯一的语法，所以那些共用C++和VB.NET的人不会产生语法混乱。<br><br>　　8. 结论<br><br>　　最后，至于你用什么语言编程，这可能依赖许多因素——如：你在学校学习的是什么语言，你是用什么语言开发的现有代码仓库，是否你的客户对你有具体的语言要求等。本文的主要目的是帮助你确定使用C++/CLI的几个明确的场所--这里，它比另外CLI语言更具有明显优势。如果你开发的应用程序有90%的使用时间是涉及本机interop，为何还要考虑使用另外的而不是C++？如果你想开发一个通用集合，为什么仅把你自己限制在泛型上，而不是结合泛型和模板的优势呢？如果你已经用C++工作，为什么还要学习一种新的语言?我常觉得象C#和VB.NET这样的语言总是尽量向开发者隐藏CLR，而C++不仅让你品味CLR，甚至可以让你去亲吻CLR!&nbsp;<br></p><img src ="http://www.cppblog.com/mzty/aggbug/56531.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2008-07-18 22:12 <a href="http://www.cppblog.com/mzty/archive/2008/07/18/56531.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Windwos via C++》之精华</title><link>http://www.cppblog.com/mzty/archive/2008/07/13/56001.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Sun, 13 Jul 2008 02:37:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2008/07/13/56001.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/56001.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2008/07/13/56001.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/56001.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/56001.html</trackback:ping><description><![CDATA[<p>&nbsp; 来自：梦在天涯C++博客(<a href="http://www.cppblog.com/mzty/">http://www.cppblog.com/mzty/</a>)</p>
<p><span>一</span><span> </span><span>引言</span></p>
<p><span>作为一名</span><span>windows</span><span>系统上图形软件开发者已经有</span><span>3</span><span>个多年头了，在此过程中有不少的经历和经验，非常高兴与大家分享，今天主要是《</span><span>windows via C++</span><span>》一书的阅读心得，所以主要谈到的是</span><span>windows</span><span>上</span><span>C++</span><span>的开发。</span></p>
<p>&nbsp;</p>
<p><span>二</span><span> C++</span><span>语言</span></p>
<p><span>我们知道</span><span>C++</span><span>是一门</span><span>ISO</span><span>的面向对象的语言，下面我介绍他的三个方面，也正是这三个主要方面决定了他被广泛的使用。第一，</span><span>C++</span><span>是一个功能强大的语言。比如</span><span>C++</span><span>语言本身提供的基于</span><span>C</span><span>语言的内嵌类型，数组，结构体和指针等，</span><span>C++</span><span>比</span><span>C</span><span>新加入的面向对象的</span><span>Class</span><span>，继承，多态和模板等，还有</span><span>C++</span><span>标准模板库（</span><span>STL</span><span>）提供的实际开发当中常用的数据结构和算法的实现；第二，大量的开源和第三方库，如果在</span><span>windows</span><span>上使用</span><span>C++</span><span>开发，我们还可以借助</span><span>microsoft</span><span>对</span><span>C++</span><span>提供的强有力的支持，首先的</span><span>VS</span><span>编译器，还有</span><span>UI</span><span>库</span><span>MFC</span><span>，还有</span><span>ATL</span><span>等；除此之外我们还可以看到其他的许多非</span><span>microsoft</span><span>的开源的和第三方的支持，比如说</span><span>Boost</span><span>很大程度的扩充了</span><span>STL</span><span>，提供了更多更高级的功能，还有</span><span>Loki</span><span>把</span><span>C++</span><span>与设计模式结合起来，还有很多的第三方的</span><span>UI</span><span>库，比如</span><span>QT</span><span>，</span><span>WxWindows</span><span>，</span><span>WTL</span><span>，</span><span>GTK</span><span>等，第三方的网络通信库，比如</span><span>ACE</span><span>，</span><span>StreamModule</span><span>等，第三那的</span><span>XML</span><span>库，比如</span><span>Xerces</span><span>，</span><span>CMarkup</span><span>，</span><span>tinyxml</span><span>等，第三方的科学计算库，比如</span><span>Blitz++</span><span>，</span><span>MTL</span><span>等，第三方的游戏开发库，比如</span><span>OGRE</span><span>，</span><span>KlayGE</span><span>等，第三方的线程库，比如</span><span>C++ Threads</span><span>，</span><span>ZThreads</span><span>等，还有其他的很多。第三，</span><span>C++</span><span>的高性能。这个也是毋庸质疑的，我们知道的大部分的操作系统，嵌入式开发，游戏，图像软件离不开</span><span>C++</span><span>，这都是跟</span><span>C++</span><span>的高性能有很大的关系。但从这一点来看，这就是很多现代的其他的高级语言没有的，所以</span><span>C++</span><span>以后仍然有很长的路要走。</span></p>
<p>&nbsp;</p>
<p><span>三</span><span> </span><span>《</span><span>Windows via c++</span><span>》之经典</span></p>
<p><span>上面说了</span><span>C++</span><span>语言本身，这里具体到</span><span>windows</span><span>系统上</span><span>C++</span><span>的开发，我们要基于</span><span>windows</span><span>系统开发软件，就难免的要和</span><span>windows</span><span>系统打交道，比如系统本身对字符编码的支持，系统的异常处理机制，线程的创建管理，进程的创建管理，内存和虚拟内存的使用，堆栈的操作，</span><span>DLL</span><span>的使用等。上面提到的这些都不是</span><span>C++</span><span>语言本身的职责，是需要操作系统提供的支持，而所有这些内容正是《</span><span>windows via C++</span><span>》所覆盖的内容，也正是本书很好的把</span><span>C++</span><span>和</span><span>Windows</span><span>连接起来，引领</span><span>C++</span><span>程序员走向</span><span>windows</span><span>的底层，这也正是本书的经典之处</span><span>!</span><span>再次感谢作者</span><span>Jeffrey Richter</span><span>的伟大贡献！</span></p>
<p>&nbsp;</p>
<p><span>1</span><span>）字符编码：字符编码作为字符串的基础，自然而然就成了我们软件开发必不可缺少的基石，那么什么是字符编码那？字符编码就是字符在计算机内部的表示形式，我们都知道在计算机内部，所有的信息最终都表示为一个二进制的字符串。每一个二进制位（</span><span>bit</span><span>）有</span><span>0</span><span>和</span><span>1</span><span>两种状态，因此八个二进制位就可以组合出</span><span>256</span><span>种状态，这被称为一个字节（</span><span>byte</span><span>）。上个世纪</span><span>60</span><span>年代，美国制定了一套字符编码，对英语字符与二进制位之间的关系，做了统一规定。这被称为</span><span>ASCII</span><span>码，一直沿用至今。</span><span>ASCII</span><span>码一共规定了</span><span>128</span><span>个字符的编码，因为他只占用了一个字节的后面</span><span>7</span><span>位，最前面的</span><span>1</span><span>位统一规定为</span><span>0</span><span>。英语用</span><span>128</span><span>个符号编码就够了，但是用来表示其他语言，</span><span>128</span><span>个符号是不够的。所以后来就各国有了各国的编码，比如日文中的汉字远远大于</span><span>256</span><span>个，所以日文使用如果第一个字符在</span><span>0 x 8 1 </span><span>与</span><span>0 x 9 F </span><span>之间，或者在</span><span>0 x E 0 </span><span>与</span><span>0 x F C </span><span>之间，那么就必须观察下一个字节，才能确定字符串中的这个完整的字符。这样他就使用一个或两个字节来表示一个字符，这种编码被称为双字节字符集（</span><span>D B C S </span><span>）。由于世界上存在着多种编码方式，这使得同一个二进制数字可以被解释成不同的符号。因此，要想打开一个文本文件，就必须知道它的编码方式，否则用错误的编码方式解读，就会出现乱码。这个时候</span><span>Unicode</span><span>就出现了他将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码，那么乱码问题就会消失。但是</span><span>unicode</span><span>也有不同的实现，主要的有三种：</span><span>UTF-16</span><span>：其本身就是标准的</span><span>Unicode</span><span>编码方案，又称为</span><span>UCS-2</span><span>，它固定使用</span><span>16 bits(</span><span>两个字节</span><span>)</span><span>整数来表示一个字符。</span><span>UTF-32</span><span>：又称为</span><span>UCS-4</span><span>，它固定使用</span><span>32 bits(</span><span>四个字节</span><span>)</span><span>整数来表示一个字符。</span><span>UTF -8</span><span>：最广泛的使用的</span><span>UTF</span><span>方案，</span><span>UTF-8</span><span>使用可变长度字节来储存</span><span>Unicode</span><span>字符，例如</span><span>ASCII</span><span>字母继续使用</span><span>1</span><span>字节储存，重音文字、希腊字母或西里尔字母等使用</span><span>2</span><span>字节来储存，而常用的汉字就要使用</span><span>3</span><span>字节。辅助平面字符则使用</span><span>4</span><span>字节。</span><span>UTF-8</span><span>更便于在使用</span><span>Unicode</span><span>的系统与现存的单字节的系统进行数据传输和交换。与前两个方案不同：</span><span>UTF-8</span><span>以字节为编码单元，没有字节序的问题。但是不管是哪种</span><span>unicode</span><span>的实现都可以包含世界所有的字符，解决软件本地化的难题。</span></p>
<p>&nbsp;</p>
<p><span>Windows</span><span>在</span><span>2000</span><span>以前使用</span><span>ASCII</span><span>，</span><span>2000</span><span>及以后的系统都使用</span><span>unicode</span><span>来编码，但是需要注意的是</span><span>Windows2000</span><span>既支持</span><span>Unicode</span><span>，也支持</span><span>ANSI</span><span>，因此可以为任意一种开发应用程序</span><span>.</span><span>如果调用任何一个</span><span>Windows</span><span>函数并给它传递一个</span><span>ANSI</span><span>字符串，那么系统首先要将字符串转换成</span><span>Unicode</span><span>，然后将</span><span>Unicode</span><span>字符串传递给操作系统。如果希望函数返回</span><span>ANSI</span><span>字符串，系统就会首先将</span><span>Unicode</span><span>字符串转换成</span><span>ANSI</span><span>字符串，然后将结果返回给你的应用程序。所有这些转换操作都是在你看不见的情况下发生的。当然，进行这些字符串的转换需要占用系统的时间和内存。比如同一个函数</span><span>CreateWindowEx()</span><span>，在内部其实是当</span><span>ASCII</span><span>是调用</span><span>CreateWindowExA()</span><span>，而当</span><span>unicode</span><span>时调用</span><span>CreateWindowExW()</span><span>。同时</span><span>windows</span><span>系统还给我们提供了</span><span>ASCII</span><span>和</span><span>unicode</span><span>间的转化函数</span><span>MultiByteToWideChar(</span><span>）和</span><span>WideCharToMultiByte()</span><span>。</span></p>
<p>&nbsp;</p>
<p><span>2</span><span>）进程和线程：进程通常被定义为一个正在运行的程序的实例，它由两个部分组成，第一，</span><span> </span><span>一个是操作系统用来管理进程的内核对象，内核对象也是系统用来存放关于进程的统计信息的地方；第二，是地址空间，它包含所有可执行模块或</span><span> D L L </span><span>模块的代码和数据，它还包含动态内存分配的空间，如线程堆栈和堆分配空间。线程是应用程序执行时的最小单位，同样线程也是由两个部分组成的：第一，</span><span> </span><span>一个是线程的内核对象，操作系统用它来对线程实施管理，内核对象也是系统用来存放线程统计信息的地方；第二，线程堆栈，它用于维护线程在执行代码时需要的所有函数参数和局部变量。</span></p>
<p>&nbsp;</p>
<p><span>进程是不活泼的，从来不执行任何东西，它只是线程的容器，若要使进程完成某项操作，它必须拥有一个在它的环境中运行的线程，该线程负责执行包含在进程的地址空间中的代码，当创建一个进程时，系统会自动创建它的第一个线程，称为主线程，然后，该线程可以创建其他的线程，而这些线程又能创建更多的线程。如果在单进程环境中，你有两个或多个线程正在运行，那么这两个线程将共享单个地址空间。这些线程能够执行相同的代码，对相同的数据进行操作。这些线程还能共享内核对象句柄，因为句柄表依赖于每个进程而不是每个线程存在。</span></p>
<p><span>windows</span><span>提供和很多函数来创建和管理线程和进程，比如</span><span>CreateThread</span><span>（），</span><span>ExitThread</span><span>（），</span><span>TerminateThread</span><span>（），</span><span>GetCurrentThread()</span><span>，</span><span>CreateProcess</span><span>（），</span><span>ExitProcess</span><span>（），</span><span>TerminateProcess </span><span>（），</span><span>GetCurrentProcess</span><span>（）等。</span></p>
<p>&nbsp;</p>
<p><span>3</span><span>）线程同步和线程局部存储：由于同一进程的所有线程共享进程的虚拟地址空间，并且线程的中断是汇编语言级的，所以可能会发生两个线程同时访问同一个对象（包括全局变量、共享资源、</span><span>API</span><span>函数和</span><span>MFC</span><span>对象等）的情况，这有可能导致程序错误。属于不同进程的线程在同时访问同一内存区域或共享资源时，也会存在同样的问题。因此，在多线程应用程序中，常常需要采取一些措施来同步线程的执行。</span></p>
<p>&nbsp;</p>
<p><span>windows</span><span>提供了</span><span>3</span><span>中同步机制，分别是信号量</span><span>Semaphore</span><span>，互斥量</span><span>Mutex</span><span>，关键代码段</span><span>CriticalSection</span><span>。其中信号量</span><span>Semaphore</span><span>，是一个可以限制对指定的临界段进行访问的线程的数目的数据结构。互斥量</span><span>Mutex</span><span>和关键代码段</span><span>CriticalSection</span><span>，他们的作用是相同的，都是用来保证某时刻只有一个线程能够访问全局或静态的资源。区别是：</span><span>Mutex</span><span>是内核对象，可以设置等待超时时间，可以在不同的进程的线程中使用，但是所消耗的时间也比较多。</span><span>CriticalSection</span><span>与</span><span>Mutex</span><span>相反。</span></p>
<p>&nbsp;</p>
<p><span>线程局部存储（</span><span>TLS</span><span>），可以为全局或静态变量对不同的线程有不同的拷贝。</span></p>
<p>&nbsp;</p>
<p><span>4</span><span>）线程池：可以实现在程序中根据需要动态的创建线程，比如在</span><span>server</span><span>端，根据访问的用户的多少来创建线程的多少。在</span><span>windows2000</span><span>以后增加了创建线程池的</span><span>API</span><span>，比如</span><span> QueueUserWorkItem</span><span>（）。</span></p>
<p>&nbsp;</p>
<p><span>5)&nbsp;</span><span>纤程：用户级的线程机制，比线程小的单位，开发人员负责管理纤程的调度，同时负责确定纤程何时在线程时间片上下文中运行，一般不会带来性能的提高，主要的目的是为开发人员调度多个不需要并行执行的任务提供一个便捷的机制。单线程可以包含一个或多个纤程。就内核而言，线程是抢占调度的，是正在执行的代码。然而，线程每次执行一个纤程的代码，你决定究竟执行哪个纤程，你可以调用</span><span>ConvertThreadToFiber</span><span>（）</span><span>将已有的线程转化位纤程，当对纤程的执行环境进行分配和初始化后，就可以将执行环境的地址与线程关联起来，该线程被转换成一个纤程，而纤程则在该线程上运行。现在，如果你的纤程（线程）返回或调用</span><span>ExitThread</span><span>函数，那么纤程和线程都会终止运行。除非打算创建更多的纤程以便在同一个线程上运行，否则没有理由将线程转换成纤程。若要创建另一个纤程，该线程（当前正在运行纤程的线程）可以调用</span><span>CreateFiber</span><span>函数。但是调用</span><span>CreateFilber</span><span>创建的纤程并不执行，直到调用</span><span>SwitchToFiber</span><span>函数。若要撤消纤程，可以调用</span><span>DeleteFiber</span><span>函数。</span></p>
<p>&nbsp;</p>
<p><span>6)&nbsp;</span><span>作业：作业可以看作是一组进程的容器</span><span>,</span><span>把这些进程当作一个整体</span><span>,</span><span>对这个整体整个加入更多的限制</span><span>. </span><span>因为</span><span>Windows</span><span>并不维护进程之间的父</span><span>/</span><span>子关系。即使父进程已经终止运行，子进程仍然会继续运行。</span><span>Microsoft Windoss 2000</span><span>提供了一个新的作业内核对象，使你能够将进程组合在一起，并且创建一个&#8220;沙框&#8221;，以便限制进程能够进行的操作。最好将作业对象视为一个进程的容器。但是，创建包含单个进程的作业是有用的，因为这样一来，就可以对该进程加上通常情况下不能加的限制。创建一个新作业内核对象可以调用</span><span>CreateJobObject</span><span>（），另一个进程要访问作业，可以通过</span><span>OpenJobObject</span><span>（），应该知道，关闭作业对象并不会迫使作业中的所有进程终止运行。该作业对象实际上做上了删除标记，只有当作业中的所有进程全部终止运行之后，该作业对象才被自动撤消。注意，关闭作业的句柄后，尽管该作业仍然存在，但是该作业将无法被所有进程访问。通过调用</span><span>SetInformationJobObject()</span><span>可以给作业加上各种限制</span><span>.</span><span>查询限制</span><span>QueryInformationJobObject</span><span>（），将进程放入作业</span><span>AssignProcessToJobObject</span><span>（），若要撤销作业中的进程调用</span><span>TerminateJobObject</span><span>（）。</span></p>
<p>&nbsp;</p>
<p><span>7)&nbsp;</span><span>虚拟内存，内存映射文件和堆栈：每个进程都被赋予它自己的虚拟地址空间。对于</span><span>3 2</span><span>位进程来说，这个地址空间是</span><span>4 G B,</span><span>其中默认有</span><span>2G</span><span>是用户可以使用的。由于每个进程可以接收它自己的私有的地址空间，因此当进程中的一个线程正在运行时，该线程可以访问只属于它的进程的内存。属于所有其他进程的内存则隐藏着，并且不能被正在运行的线程访问。注意在</span><span>Windows 2000</span><span>中，属于操作系统本身的内存也是隐藏的，正在运行的线程无法访问。这意味着线程常常不能访问操作系统的数据。</span></p>
<p>&nbsp;</p>
<p><span>Windows</span><span>提供了</span><span>3</span><span>种进行内存管理的方法，它们是第一，</span><span> </span><span>虚拟内存，最适合用来管理大型对象或结构数组。</span><span> </span><span>第二，内存映射文件，最适合用来管理大型数据流（通常来自文件）以及在单个计算机上运行的多个进程之间共享数据。第三，</span><span> </span><span>内存堆栈，最适合用来管理大量的小对象。</span></p>
<p>&nbsp;</p>
<p><span>在较老的操作系统中，物理存储器被视为计算机拥有的</span><span>R A M</span><span>的容量。换句话说，如果计算机拥有</span><span>1 6 M B</span><span>的</span><span>R A M</span><span>，那么加载和运行的应用程序最多可以使用</span><span>1 6 M B</span><span>的</span><span>R A M</span><span>。今天的操作系统能够使得磁盘空间看上去就像内存一样。磁盘上的文件通常称为页文件，它包含了可供所有进程使用的虚拟内存。</span></p>
<p>&nbsp;</p>
<p><span>内存映射文件与虚拟内存一样，内存映射文件可以用来保留一个地址空间的区域，并将物理存储器提交给该区域。它们之间的差别是，物理存储器来自一个已经位于磁盘上的文件，而不是系统的页文件。一旦该文件被映射，就可以访问它，就像整个文件已经加载内存一样。</span></p>
<p>&nbsp;</p>
<p><span>堆栈可以用来分配许多较小的数据块。例如，若要对链接表和链接树进行管理，最好的方法是使用堆栈，堆栈的优点是，可以不考虑分配粒度和页面边界之类的问题，集中精力处理手头的任务。堆栈的缺点是，分配和释放内存块的速度比其他机制要慢，并且无法直接控制物理存储器的提交和回收。进程和线程都有自己的堆栈，而且大小可以更改。</span></p>
<p>&nbsp;</p>
<p><span>8)&nbsp;DLL</span><span>使用：</span><span>windows</span><span>中广泛的使用</span><span>dll</span><span>来实现模块化，</span><span>dll</span><span>的使用一般有静态和动态加载，静态加载一般通过编译器的设置来实现，动态加载通过使用</span><span>loadlibrary</span><span>（）和</span><span>freelibrary</span><span>（）来实现。</span></p>
<p>&nbsp;</p>
<p><span>9</span><span>）结构化异常处理（</span><span>SEH</span><span>）：</span><span>SEH </span><span>是</span><span> Windows </span><span>系统提供的异常处理功能，跟开发工具无关。</span><span>windows</span><span>上其他程序中的异常处理一般底层都是转化为</span><span>SEH</span><span>来实现。实际上，当你写一条</span><span>C++ throw</span><span>语句时，编译器就生成一个对</span><span>Windows</span><span>的</span><span>RaiseException</span><span>函数的调用。用于</span><span>throw</span><span>语句的变量传递给</span><span>RaiseException</span><span>作为附加的参数。</span></p>
<p>&nbsp;</p>
<p><span>四</span><span> </span><span>《</span><span>Windows via c++</span><span>》之新增</span></p>
<p>&nbsp;</p>
<p><span>1</span><span>）</span><span>64</span><span>位支持：最新的系统有</span><span>64</span><span>的版本，这样的话进程就不再有最大</span><span>4G</span><span>的内存限制，但是由于</span><span>64</span><span>位系统与以前的</span><span>32</span><span>位系统其实是一个</span><span>codebase</span><span>，所以基本有所的接口都与以前</span><span>32</span><span>位保持椅子，这样的话我们以前的所有的</span><span>32</span><span>位的程序只需要从新编译就可以运行在</span><span>64</span><span>系统上，需要特别注意的是指针和句柄的从</span><span>32</span><span>位到</span><span>64</span><span>位的转变。</span></p>
<p>&nbsp;</p>
<p><span>2</span><span>）</span><span>windows vista/2008</span><span>特有：提供了更加安全的</span><span>stirng</span><span>函数，一些内核对象的改变等。</span></p>
<p>&nbsp;</p>
<p><span>3</span><span>）可重复使用的代码：大量可在我们日常开发中重复使用的代码和让我们更好的理解进程的源代码</span><span>processInfo</span><span>，</span><span>LockCop</span><span>等。</span></p>
<p>&nbsp;</p>
<p><span>五</span><span> </span><span>总结</span></p>
<p><span>总之，通过阅读《</span><span>Windows via C++</span><span>》使我们更好的了解</span><span>windows</span><span>系统，更好的在</span><span>windows</span><span>进行</span><span>C++</span><span>开发！推荐</span><span>windows</span><span>上</span><span>C++</span><span>开发人员可以一读！</span></p><img src ="http://www.cppblog.com/mzty/aggbug/56001.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2008-07-13 10:37 <a href="http://www.cppblog.com/mzty/archive/2008/07/13/56001.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows开发经典图书推荐</title><link>http://www.cppblog.com/mzty/archive/2008/07/10/55775.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Thu, 10 Jul 2008 01:19:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2008/07/10/55775.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/55775.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2008/07/10/55775.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/55775.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/55775.html</trackback:ping><description><![CDATA[不能不说是经典啊！我觉的是非常的经典啊！感谢图灵！借首页一用哦！<br><br><img height=534 alt="" src="http://www.cppblog.com/images/cppblog_com/mzty/7317/o_yitiantulong.JPG" width=993 border=0><br><br>参考：<a href="http://www.cnblogs.com/turingbooks/archive/2008/07/04/1235964.html">http://www.cnblogs.com/turingbooks/archive/2008/07/04/1235964.html</a><br>更多图灵图书可以看：<a href="http://www.cnblogs.com/turingbooks/">http://www.cnblogs.com/turingbooks/</a> <br><br>购买：<a href="http://www.china-pub.com/static/zt_mb/zt_huodong_0808.asp?filename=jsj_tlms_080702">http://www.china-pub.com/static/zt_mb/zt_huodong_0808.asp?filename=jsj_tlms_080702</a><img src ="http://www.cppblog.com/mzty/aggbug/55775.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2008-07-10 09:19 <a href="http://www.cppblog.com/mzty/archive/2008/07/10/55775.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>3D CAD软件及核心</title><link>http://www.cppblog.com/mzty/archive/2008/06/19/54040.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Thu, 19 Jun 2008 10:15:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2008/06/19/54040.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/54040.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2008/06/19/54040.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/54040.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/54040.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<p>3D CAD软件及核心</p>
<p>一 3D CAD软件</p>
<p>1）CATIA （达索Dassault Aviation）（高端）（）</p>
<p>CATIA是英文 Computer Aided Tri-Dimensional Interface Application 的缩写。是世界上一种主流的CAD/CAE/CAM一体化软件。在70年代Dassault Aviation 成为了第一个用户，CATIA 也应运而生。从1982年到1988年，CATIA 相继发布了1版本、2版本、3版本，并于1993年发布了功能强大的4版本，现在的CATIA 软件分为V4版本和 V5版本两个系列。V4版本应用于UNIX 平台，V5版本应用于UNIX和Windows 两种平台。V5版本的开发开始于1994年。为了使软件能够易学易用，Dassault System 于94年开始重新开发全新的CATIA V5版本，新的V5版本界面更加友好，功能也日趋强大，并且开创了CAD/CAE/CAM 软件的一种全新风格。<br>&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; 法国 Dassault Aviation 是世界著名的航空航天企业。其产品以幻影2000和阵风战斗机最为著名。CATIA的产品开发商Dassault System 成立于1981年。而如今其在CAD/CAE/CAM 以及PDM 领域内的领导地位，已得到世界范围内的承认。其销售利润从最开始的一百万美圆增长到现在的近二十亿美圆。雇员人数由20人发展到2，000多人。<br>&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; CATIA是法国Dassault System公司的CAD/CAE/CAM一体化软件，居世界CAD/CAE/CAM领域的领导地位，广泛应用于航空航天、汽车制造、造船、机械制造、电子\电器、消费品行业，它的集成解决方案覆盖所有的产品设计与制造领域，其特有的DMU电子样机模块功能及混合建模技术更是推动着企业竞争力和生产力的提高。CATIA 提供方便的解决方案，迎合所有工业领域的大、中、小型企业需要。包括:从大型的波音747飞机、火箭发动机到化妆品的包装盒，几乎涵盖了所有的制造业产品。在世界上有超过13,000的用户选择了CATIA。CATIA 源于航空航天业，但其强大的功能以得到各行业的认可，在欧洲汽车业，已成为事实上的标准。CATIA 的著名用户包括波音、克莱斯勒、宝马、奔驰等一大批知名企业。其用户群体在世界制造业中具有举足轻重的地位。波音飞机公司使用CATIA完成了整个波音 777的电子装配，创造了业界的一个奇迹，从而也确定了CATIA 在CAD/CAE/CAM 行业内的领先地位。</p>
<p><br>2）UG （UGS现被西门子收购）（高端）（Parasolid几何造型核心为基础，采用基于约束的特征建模技术和传统的几何建模为一体的复合建模技术）</p>
<p>Unigraphics Solutions公司(简称UGS)是全球著名的MCAD供应商,主要为汽车与交通、航空航天、日用消费品、通用机械以及电子工业等领域通过其虚拟产品开发(VPD)的理念提供多级化的、集成的、企业级的包括软件产品与服务在内的完整的 MCAD解决方案。其主要的CAD产品是UG。<br>UG公司的产品主要有为机械制造企业提供包括从设计、分析到制造应用的Unigraphics软件、基于Windows的设计与制图产品Solid Edge、集团级产品数据管理系统iMAN、产品可视化技术ProductVision以及被业界广泛使用的高精度边界表示的实体建模核心 Parasolid在内的全线产品。<br>UG在航空航天、汽车、通用机械、工业设备、医疗器械以及其它高科技应用领域的机械设计和模具加工自动化的市场上得到了广泛的应用。多年来，UGS一直在支持美国通用汽车公司实施目前全球最大的虚拟产品开发项目，同时Unigraphics也是日本著名汽车零部件制造商DENSO公司的计算机应用标准，并在全球汽车行业得到了很大的应用，如Navistar、底特律柴油机厂、Winnebago和Robert Bosch AG 等。<br>另外，UGS公司在航空领域也有很好的的表现：在美国的航空业，安装了超过10,000套UG软件；在俄罗斯航空业，UG软件具有90%以上的市场；在北美汽轮机市场，UG软件占80%。UGS在喷气发动机行业也占有领先地位，拥有如Pratt &amp; Whitney和GE 喷气发动机公司这样的知名客户。航空业的其它客户还有：B/E航空公司、波音公司、 以色列飞机公司、英国航空公司、Northrop Grumman、伊尔飞机和Antonov。<br>UGS公司的产品同时还遍布通用机械、医疗器械、电子、高技术以及日用消费品等行业，如：3M、Will-Pemco、Biomet、Zimmer、飞利浦公司、吉列公司、Timex、 Eureka 和Arctic Cat等。</p>
<p><br>3）Pro/ENGINEER（PTC）（中端）(PROE是参数化造型的开创者，以其参数化、基于特征、全相关等概念闻名于CAD界)</p>
<p>1985年，PTC公司成立于美国波士顿，开始参数化建模软件的研究。1988年，V1.0的Pro/ENGINEER诞生了。经过10余年的发展，Pro/ENGINEER已经成为三维建模软件的领头羊。目前已经发布了Pro/ENGINEER2000i2。PTC的系列软件包括了在工业设计和机械设计等方面的多项功能，还包括对大型装配体的管理、功能仿真、制造、产品数据管理等等。Pro/ENGINEER还提供了目前所能达到的最全面、集成最紧密的产品开发环境。PRO/E的最新版本为PRO/E2000i，它可运行于Windows/NT和UNIX平台上，共有六大主模块，下面我把它们逐一介绍给大家。</p>
<p>PRO/E概述<br>PRO/ENGINEER软件包的产品开发环境在支持并行工作，它通过一系列完全相关的模块表述产品的外形、装配及其他功能。PRO/E能够让多个部门同时致力于单一的产品模型。包括对大型项目的装配体管理、功能仿真、制造、数据管理等。其中PRO/E V2000I更增加了行为建模技术使其成为把梦想变为现实的杰出工具。</p>
<p>4）solidworks（SolidWorks被达索收购）（低端）（Parasolid几何造型核心为基础，采用基于约束的特征建模技术和传统的几何建模为一体的复合建模技术）</p>
<p>SolidWorks公司成立于1993年，由PTC公司的技术副总裁与CV公司的副总裁发起，总部位于马萨诸塞州的康克尔郡（Concord,Massachusetts）内，当初所赋予的任务是希望在每一个工程师的桌面上提供一套具有生产力的实体模型设计系统。从1995年推出第一套SolidWorks三维机械设计软件至今，它已经拥有位于全球的办事处，并经由300家经销商在全球140个国家进行销售与分销该产品。　SolidWorks软件是世界上第一个基于Windows开发的三维CAD系统，由于技术创新符合CAD技术的发展潮流和趋势，SolidWorks 公司于两年间成为CAD/CAM产业中获利最高的公司。良好的财务状况和用户支持使得SolidWorks每年都有数十乃至数百项的技术创新，公司也获得了很多荣誉。该系统在1995-1999年获得全球微机平台CAD系统评比第一名；从1995年至今，已经累计获得十七项国际大奖，其中仅从1999年起，美国权威的CAD专业杂志CADENCE连续4年授予SolidWorks最佳编辑奖，以表彰SolidWorks的创新、活力和简明。至此，SolidWorks所遵循的易用、稳定和创新三大原则得到了全面的落实和证明，使用它，设计师大大缩短了设计时间，产品快速、高效地投向了市场。<br>&nbsp;&nbsp;&nbsp; 由于SolidWorks出色的技术和市场表现，不仅成为CAD行业的一颗耀眼的明星，也成为华尔街青睐的对象。终于在1997年由法国达索公司以三亿一千万美元的高额市值将SolidWorks全资并购。公司原来的风险投资商和股东，以一千三百万美元的风险投资，获得了高额的回报，创造了CAD行业的世界纪录。并购后的SolidWorks以原来的品牌和管理技术队伍继续独立运作，成为CAD行业一家高素质的专业化公司，SolidWorks三维机械设计软件也成为达索企业中最具竞争力的CAD产品。</p>
<p>5) autodesk inventor(autodesk)(低端)（）<br>Autodesk Inventor 2008产品线提供了一套全面、集成的设计工具，可用于三维设计和建档、创建布线系统和验证设计。 Inventor产品线中的所有产品包均包括强大的数据管理软件和面向二维制图和详细设计的 AutoCAD Mechanical软件。</p>
<p>6)solidege(UGS现被西门子收购)(低端)</p>
<p>二 3D CAD软件核心</p>
<p>1）ACIS是用C＋＋语言编写的，由于没有基于ACIS的高中端CAD软件开发出来，ACIS的维护和提供实时的技术支持看起来要比Parasolid差点。总言之，ACIS的稳定性较差，但容易上手，适用于学校里的研究工作或做个DEMO版演示软件；</p>
<p>2）OpenCasCade是个免费包，适用于市场份额不大的软件开发。比如CMM测量软件，CMM软件一年销售几千套已经是非常好的业绩了。OpenCasCade用于学习研究还是不错的，算法都看得到，不过这是需要良好的数学（比如：高等几何）功底的。</p>
<p>3）Parasolid包里的复杂的曲面造型功能看起来UGS公司有所保留，不过，UGS最近被西门子收购，纯粹的软件行业看起来比较脆弱，前几年的网络泡沫，现在看起来软件泡沫也不远了。</p>
<p>4）ACIS和Parasolid价格差不多，如果是商业开发的话，还是选择Parasolid稳妥点。</p>
<p>三 3D CAD软件选择</p>
<p>几种三维软件的特点结合我的经验对比：<br>1）Solidworks：用法简单，对于非复杂曲面实体建模能力还可以；<br>2）UG：功能强大，操作一般，作模具较好；<br>3）CATIA：功能强大，是当今一流的三维软件，但是操作复杂，一般公司不用，像波音等大公司使用，在中国汽车行业常用；<br>4) PRO/E：功能强大，操作简单，曲面能力强，适用于产品外观模型的建立与结构的设计，制作模具能力较差。<br>至于3DMAX之流，根本不是三维CAD软件，不值一提。 </p><img src ="http://www.cppblog.com/mzty/aggbug/54040.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2008-06-19 18:15 <a href="http://www.cppblog.com/mzty/archive/2008/06/19/54040.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>盖茨53年人生大事记</title><link>http://www.cppblog.com/mzty/archive/2008/06/18/53911.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Wed, 18 Jun 2008 09:35:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2008/06/18/53911.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/53911.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2008/06/18/53911.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/53911.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/53911.html</trackback:ping><description><![CDATA[<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;《连线》杂志近日撰文称，微软创始人兼董事会主席比尔&#183;盖茨(Bill Gates)将于7月正式退出微软的日常运营，全身心投入慈善事业。盖茨的离去将令很多人依依不舍，不仅因为他白手起家的传奇经历激励着人们矢志前进，而且，在盖茨的财富背后，还隐藏着一种更为根本的东西，值得我们去探究。在盖茨与我们告别之际，让我们来回顾一下他走过的50多年的难忘瞬间。
<p>　　<strong>20世纪50年代</strong></p>
<p>　　1955年10月28日 </p>
<p>　　威廉-亨利&#183;盖茨三世出生于西雅图。祖母奥黛丽给他起了一个外号——&#8220;特利&#8221;(Trey)，Trey在英语中的意思是三点的牌、骰子或骨牌。盖茨后来也确实成了一名扑克牌高手。</p>
<p><strong>　　20世纪60年代</strong></p>
<p>　　1967年</p>
<p>　　盖茨上六年级，学习成绩不佳，他充满困惑地问妈妈，&#8220;您曾尝试思考吗？&#8221;</p>
<p>　　1967年秋 </p>
<p>　　盖茨的父母把他送进了湖边学校(Lakeside School)，这是西雅图一所男子学校。他是班里最矮的学生。</p>
<p>　　1968年</p>
<p>　　盖茨和湖边学校同班同学保罗&#183;艾伦(Paul Allen)从手册中学会了Basic语言。几周后，这两个小家伙便将学校用于支付PDP-10电脑使用时间的3000美元年度预算花得一干二净。他们俩不久即与电脑中心公司签了一份合约，向其报告PDP-10电脑中存在的软件缺陷，而报酬是免费使用电脑。</p>
<p><strong>　　20世纪70年代</strong></p>
<p>　　1971年</p>
<p>　　盖茨为湖边学校编写程序，包括一个设计班级课程表的程序。</p>
<p>　　1973年9月</p>
<p>　　盖茨考入哈佛大学。他的学习成绩很不稳定。他有很多坏习惯，经常旷课去编程、玩牌，不爱洗澡，喜欢比萨饼和碳酸饮料。他与住在同一个宿舍的史蒂夫&#183;鲍尔默(Steve Ballmer)结为好友。</p>
<p>　　1975年1月</p>
<p>　　艾伦无意中看到了《大众电子》的封面，上面是Altair 8800电脑的照片和&#8220;全球第一台对抗商业模式的微型电脑装置&#8221;的大字标题。艾伦买了一本，并冲进盖茨的房间。几天后，盖茨给Altair电脑制造商 MITS打去电话，告诉该公司他和艾伦能为8800电脑开发出Basic语言。</p>
<p>　　1975年2月1日</p>
<p>　　盖茨和艾伦完成Basic开发，将其以3000美元外加最高达18万美元的版税卖给MITS公司。</p>
<p>　　1976年11月26日</p>
<p>　　盖茨和艾伦注册了微软(Microsoft)商标。他们一度考虑以艾伦与盖茨(Allen &amp; Gates)作为公司名称，后提出Micro-Soft，但他们决定将中间的连字符去掉，于是微软就此诞生。当时艾伦23岁，盖茨21岁。</p>
<p>　　1977年1月</p>
<p>　　盖茨从哈佛大学休学，在新墨西哥州阿尔伯克基创建了微软，MITS总部也设在此地。</p>
<p>　　1977年</p>
<p>　　盖茨的秘书多次在微软办公大楼内发现盖茨躺在地板上呼呼大睡。他仍喜欢吃比萨饼，同时对属下要求严格，经常与同事争辩。盖茨经常说的一句话是：&#8220;这是我有史以来听说的最愚蠢的事情。&#8221;</p>
<p>　　1977年底</p>
<p>　　盖茨多次因驾驶保时捷911超速而被警方逮捕，还有一次则是无照驾驶。这可害苦了艾伦，他保释盖茨的经历至少有一次。</p>
<p>　　1978年12月</p>
<p>　　微软年终销售额超过100万美元。</p>
<p>　　1979年1月1日</p>
<p>　　微软将公司总部迁至华盛顿州贝尔维尤市。</p>
<p><strong>　　20世纪80年代</strong></p>
<p>　　1980年8月28日</p>
<p>　　盖茨与IBM签署合同，同意为这家PC制造商开发软件。后来，他以5万美元买了一套名为QDOS的操作系统，稍加改进并更名为DOS，便授权IBM使用。</p>
<p>　　1981年8月12日</p>
<p>　　IBM开始销售具有MS-DOS 1.0的PC。</p>
<p>　　1982年</p>
<p>　　在上市销售的第一年，MS-DOS被授权于50个硬件制造商使用。</p>
<p>　　1983年2月18日</p>
<p>　　艾伦因身患霍奇金氏病被迫辞去微软副总裁一职。他买了一个<a class=akey href="http://sports.sina.com.cn/basketball/" target=_blank><span style="COLOR: #0066cc">篮球</span></a>队，创建了一个音乐博物馆，拥有世界上第三大游艇。</p>
<p>　　1983年11月10日</p>
<p>　　Windows揭开神秘面纱。Windows是MS-DOS的延伸，可提供图形用户界面。</p>
<p>　　1984年1月24日</p>
<p>　　盖茨出席了Macintosh的上市宣传活动——微软是第一批为苹果电脑开发软件的公司之一。</p>
<p>　　1985年</p>
<p>　　有报道称盖茨粗暴辱骂一位女高管，后者要求调离岗位。</p>
<p>　　1985年8月12日</p>
<p>　　经过10年的奋斗，微软产品的销售额达到1.4亿美元。</p>
<p>　　1986年3月13日</p>
<p>　　微软以每股21美元公开发售股票。当天微软股价报收于28美元，为公司筹集到6100万美元。</p>
<p>　　1987年</p>
<p>　　盖茨在曼哈顿召开的微软新闻发布会上邂逅梅琳达&#183;弗朗奇(Melinda French)。</p>
<p>　　1989年8月1日</p>
<p>　　微软推出Office办公软件。</p>
<p><strong>　　20世纪90年代</strong></p>
<p>　　1990年5月13日</p>
<p>　　盖茨在母亲节这一天提出微软公司高层退休时间表。</p>
<p>　　1990年6月</p>
<p>　　美国联邦贸易委员会对微软和IBM在PC软件市场可能存在的勾结行为展开调查。</p>
<p>　　1993年4月11日</p>
<p>　　在从佛罗里达州飞往西雅图的包机上，盖茨向梅琳达求婚。盖茨还安排飞机在奥马哈降落，带着梅琳达同好友沃伦&#183;巴菲特(Warren Buffett)一同出去购物。</p>
<p>　　1993年8月20日</p>
<p>　　美国司法部从联邦贸易委员会接管对微软的调查。</p>
<p>　　1994年1月1日</p>
<p>　　盖茨和梅琳达在夏威夷拉奈小岛上举行了小型婚礼。为给新婚妻子一个惊喜，盖茨特意安排梅琳达最喜欢的歌手威利&#183;尼尔森(Willie Nelson)在婚礼上表演。</p>
<p>　　1994年4月</p>
<p>　　好消息：盖茨首次登上了《连线》杂志封面。坏消息：美国政府对微软展开了反垄断调查。</p>
<p>　　1994年7月</p>
<p>　　微软同意接受美国政府签署的法令，承诺放弃极端的反竞争商业行为(例如，要求硬件制造商为其所生产的配置特定微处理器的所有电脑支付MS-DOS授权费，即使该电脑没有安装这一操作系统)。</p>
<p>　　1994年11月11日</p>
<p>　　盖茨以3080万美元购得达&#183;芬奇的《哈默手稿》(Codex Hammer)——达&#183;芬奇亲笔写下的72页科学手稿。他同意将《哈默手稿》公开展示。</p>
<p>　　1995年</p>
<p>　　盖茨出现在可口可乐(据报道他喜欢喝健怡可乐)的商业广告中：这位亿万富翁搜遍全身口袋，寻找购买饮料的零钱。</p>
<p>　　1995年7月17日</p>
<p>　　39岁的盖茨以129亿美元的个人财富成为世界首富。微软在1995年的收入达到59亿美元，拥有17,801名员工。</p>
<p>　　1995年8月24日</p>
<p>　　微软推出网络浏览器Internet Explorer。</p>
<p>　　1996年6月</p>
<p>　　盖茨第二次登上《连线》杂志封面，这次是用Photoshop软件处理过的他裹着浴袍的照片。</p>
<p>　　1996年12月</p>
<p>　　微软股价创下新高——同比上涨88%。从理论上讲，那一年，盖茨每天的收入高达3000万美元。</p>
<p>　　1997年10月20日</p>
<p>　　因违反1994年签署的协议，美国法院对微软处以每天100万美元的罚款。美国司法部称，微软要求硬件制造商申请Windows 95授权时，必须在其硬件产品中绑定Internet Explorer，由此违反了这一协议。</p>
<p>　　1998年2月4日</p>
<p>　　盖茨在比利时布鲁塞尔会见比利时政府官员和企业家时，遭到奶油蛋糕的袭击。事后，盖茨开玩笑说，&#8220;这块蛋糕可不怎么好吃&#8221;。</p>
<p>　　1998年5月18日</p>
<p>　　美国司法部和20个州的总检察官认为微软将网络浏览器绑定到其操作系统，违反了相关规定，由此对微软提出起诉。</p>
<p>　　1998年11月9日</p>
<p>　　在一段作证录像中，当盖茨表示自己从未蓄意将竞争对手赶出软件市场时，他的身子微微颤抖。医生据此认为盖茨可能患有亚斯伯格症候群(Asperger's syndrome)。</p>
<p>　　1999年</p>
<p>　　盖茨和妻子将威廉&#183;盖茨基金会更名为比尔与梅琳达&#183;盖茨基金会，并提出了减少世界上不公平现象的目标。</p>
<p><strong>　　21世纪初</strong></p>
<p>　　2000年1月13日</p>
<p>　　盖茨辞去微软CEO一职，成为公司首席软件工程师，将大权交给鲍尔默。</p>
<p>　　2000年6月7日</p>
<p>　　美国联邦地区法院法官托马斯&#183;潘菲尔德&#183;杰克逊(Thomas Penfield Jackson)裁定微软应一分为二。</p>
<p>　　2000年11月</p>
<p>　　盖茨第三次登上《连线》杂志封面，这次是为了揭开微软反垄断案后鲜为人知的故事。</p>
<p>　　2001年6月28日</p>
<p>　　美国哥伦比亚地区上诉法院推翻杰克逊法官的裁决。</p>
<p>　　2002年 </p>
<p>　　据针对中国内地和香港年轻人的调查显示，盖茨取代了毛泽东在他们心中的偶像地位。</p>
<p>　　2005年3月2日</p>
<p>　　盖茨在白金汉宫接受英国女王授予的骑士勋章，此前，鲁迪&#183;朱利安尼和斯蒂文&#183;斯皮尔伯格都曾获得这一殊荣。盖茨此后有资格在名字后面加上字母&#8220;KBE&#8221;(英帝国爵级勋章)。</p>
<p>　　2005年12月</p>
<p>　　盖茨夫妇和爱尔兰U2乐队主唱波诺当选为美国《时代》周刊2005年度人物。</p>
<p>　　2006年6月15日</p>
<p>　　盖茨宣布，他将在两年内逐步退出公司的日常事务管理。</p>
<p>　　2006年6月26日</p>
<p>　　在得到巴菲特300多亿美元捐款后，比尔与梅琳达&#183;盖茨基金会规模壮大一倍，成为世界最大的慈善基金会。</p>
<p>　　2008年3月</p>
<p>　　《福布斯》发布08年全球富豪排行榜，蝉联13年首富桂冠的盖茨以580亿美元的资产总值下滑至第三的位置。而盖茨的牌友、&#8220;股神&#8221;巴菲特则取代他问鼎冠军宝座。(杨琳)</p><img src ="http://www.cppblog.com/mzty/aggbug/53911.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2008-06-18 17:35 <a href="http://www.cppblog.com/mzty/archive/2008/06/18/53911.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C#入门代码 </title><link>http://www.cppblog.com/mzty/archive/2008/06/18/53835.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Wed, 18 Jun 2008 04:08:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2008/06/18/53835.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/53835.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2008/06/18/53835.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/53835.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/53835.html</trackback:ping><description><![CDATA[<div class=postbody>
<p>转自：<a href="http://www.cnblogs.com/lyj/archive/2007/01/09/616053.html">http://www.cnblogs.com/lyj/archive/2007/01/09/616053.html</a><br><strong><br>一、从控制台读取东西代码片断：</strong><br>using System;</p>
<p>class TestReadConsole<br>{<br>&nbsp;&nbsp;&nbsp; public static void Main()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Write(Enter your name:);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string strName = Console.ReadLine();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine( Hi + strName);<br>&nbsp;&nbsp;&nbsp; }<br>}<br><strong>二、读文件代码片断：</strong><br>using System; <br>using System.IO; </p>
<p>public class TestReadFile <br>{ <br>&nbsp;&nbsp;&nbsp; public static void Main(String[] args) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Read text file C:\temp\test.txt <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileStream fs = new FileStream(@c:\temp\test.txt , FileMode.Open, FileAccess.Read); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StreamReader sr = new StreamReader(fs);&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String line=sr.ReadLine();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (line!=null)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(line);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; line=sr.ReadLine();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sr.Close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fs.Close();<br>&nbsp;&nbsp;&nbsp; } <br>} <br><strong>三、写文件代码：<br></strong>using System; <br>using System.IO; </p>
<p>public class TestWriteFile <br>{ <br>&nbsp;&nbsp;&nbsp; public static void Main(String[] args) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Create a text file C:\temp\test.txt <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileStream fs = new FileStream(@c:\temp\test.txt , FileMode.OpenOrCreate, FileAccess.Write); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StreamWriter sw = new StreamWriter(fs); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Write to the file using StreamWriter class <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.BaseStream.Seek(0, SeekOrigin.End); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.WriteLine( First Line ); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.WriteLine( Second Line); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.Flush(); <br>&nbsp;&nbsp;&nbsp; } <br>} <br><strong>四、拷贝文件：</strong><br>using System;<br>using System.IO;</p>
<p>class TestCopyFile<br>{<br>&nbsp;&nbsp;&nbsp; public static void Main()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File.Copy(c:\\temp\\source.txt, C:\\temp\\dest.txt );&nbsp; <br>&nbsp;&nbsp;&nbsp; }<br>}<br><strong>五、移动文件：<br></strong>using System;<br>using System.IO;</p>
<p>class TestMoveFile<br>{<br>&nbsp;&nbsp;&nbsp; public static void Main()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File.Move(c:\\temp\\abc.txt, C:\\temp\\def.txt );&nbsp; <br>&nbsp;&nbsp;&nbsp; }<br>}<br><strong>六、使用计时器：</strong><br>using System;<br>using System.Timers;</p>
<p>class TestTimer<br>{<br>&nbsp;&nbsp;&nbsp; public static void Main()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Timer timer = new Timer();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.Elapsed += new ElapsedEventHandler( DisplayTimeEvent );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.Interval = 1000;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.Start();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.Enabled = true;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( Console.Read() != 'q' )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //-------------<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public static void DisplayTimeEvent( object source, ElapsedEventArgs e )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Write(\r{0}, DateTime.Now);<br>&nbsp;&nbsp;&nbsp; }<br>}<br><strong>七、调用外部程序：</strong><br>class Test <br>{ <br>&nbsp;&nbsp;&nbsp; static void Main(string[] args) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Diagnostics.Process.Start(notepad.exe); <br>&nbsp;&nbsp;&nbsp; } <br>}</p>
<p><span style="COLOR: red">ADO.NET方面的：</span><br><strong>八、连接Access数据库：</strong><br>using System;<br>using System.Data;<br>using System.Data.OleDb;</p>
<p>class TestADO<br>{<br>&nbsp;&nbsp;&nbsp; static void Main(string[] args)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string strDSN = Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\\test.mdb;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string strSQL = SELECT * FROM employees ;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OleDbConnection conn = new OleDbConnection(strDSN);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OleDbCommand cmd = new OleDbCommand( strSQL, conn );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OleDbDataReader reader = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Open();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reader = cmd.ExecuteReader();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (reader.Read() )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(First Name:{0}, Last Name:{1}, reader[FirstName], reader[LastName]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (Exception e)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(e.Message);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>} <br><strong>九、连接SQL Server数据库：</strong><br>using System;<br>using System.Data.SqlClient;</p>
<p>public class TestADO<br>{<br>&nbsp;&nbsp;&nbsp; public static void Main()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlConnection conn = new SqlConnection(Data Source=localhost; Integrated Security=SSPI; Initial Catalog=pubs);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlCommand&nbsp; cmd = new SqlCommand(SELECT * FROM employees, conn);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Open();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlDataReader reader = cmd.ExecuteReader();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (reader.Read())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(First Name: {0}, Last Name: {1}, reader.GetString(0), reader.GetString(1));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reader.Close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(Exception Occured --&gt;&gt; {0},e);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; }<br>}<br><strong>十、从SQL内读数据到XML：<br></strong>using System;<br>using System.Data;<br>using System.Xml;<br>using System.Data.SqlClient; <br>using System.IO; </p>
<p>public class TestWriteXML<br>{ <br>&nbsp;&nbsp;&nbsp; public static void Main()<br>&nbsp;&nbsp;&nbsp; { </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String strFileName=c:/temp/output.xml;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlConnection conn = new SqlConnection(server=localhost;uid=sa;pwd=;database=db);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String strSql = SELECT FirstName, LastName FROM employees; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlDataAdapter adapter = new SqlDataAdapter(); </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adapter.SelectCommand = new SqlCommand(strSql,conn);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Build the DataSet<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataSet ds = new DataSet();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adapter.Fill(ds, employees);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Get a FileStream object<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileStream fs = new FileStream(strFileName,FileMode.OpenOrCreate,FileAccess.Write);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Apply the WriteXml method to write an XML document<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ds.WriteXml(fs);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fs.C