﻿<?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/zjj2816/category/2063.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 23 Nov 2008 18:31:47 GMT</lastBuildDate><pubDate>Sun, 23 Nov 2008 18:31:47 GMT</pubDate><ttl>60</ttl><item><title>如何在运行时确定对象类型（RTTI） 转</title><link>http://www.cppblog.com/zjj2816/archive/2008/11/19/67286.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Wed, 19 Nov 2008 06:59:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2008/11/19/67286.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/67286.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2008/11/19/67286.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/67286.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/67286.html</trackback:ping><description><![CDATA[RTTI 是&#8220;Runtime Type
Information&#8221;的缩写，意思是：运行时类型信息。它提供了运行时确定对象类型的方法。本文将简略介绍 RTTI 的一些背景知识、描述
RTTI 的概念，并通过具体例子和代码介绍什么时候使用以及如何使用 RTTI；本文还将详细描述两个重要的 RTTI 运算符的使用方法，它们是
typeid 和 dynamic_cast。<br>
&nbsp;&nbsp;&nbsp; 其实，RTTI
在C++中并不是什么新的东西，它早在十多年以前就已经出现了。但是大多数开发人员，包括许多高层次的C++程序员对它并不怎么熟悉，更不用说使用 RTTI
来设计和编写应用程序了。<br>
&nbsp;&nbsp;&nbsp; 一些面向对象专家在传播自己的设计理念时，大多都主张在设计和开发中明智地使用虚拟成员函数，而不用 RTTI
机制。但是，在很多情况下，虚拟函数无法克服本身的局限。每每涉及到处理异类容器和根基类层次（如 MFC）时，不可避免要对对象类型进行动态判断，也就是动态类型的侦测。如何确定对象的动态类型呢？答案是使用内建的
RTTI 中的运算符：typeid 和 dynamic_cast。<br>
&nbsp;&nbsp;&nbsp; 首先让我们来设计一个类层次，假设我们创建了某个处理文件的抽象基类。它声明下列纯虚拟函数：open()、close()、read()和
write()：
<pre>class File<br>{<br>public:<br> virtual int open(const string &amp; filename)=0;<br> virtual int close(const string &amp; filename)=0;<br> //<br> virtual ~File()=0; // 记住添加纯虚拟析构函数（dtor）<br>};</pre>
现在从 File 类派生的类要实现基类的纯虚拟函数，同时还要提供一些其他的操作。假设派生类为 DiskFile，除了实现基类的纯虚拟函数外，还要实现自己的flush()和defragment()操作：
<pre>class DiskFile: public File<br>{<br>public:<br> int open(const string &amp; filename);<br><br> // 实现其他的纯虚拟函数<br>    ......<br><br> // 自己的专有操作<br> virtual int flush();<br> virtual int defragment();<br>};    </pre>
接着，又从 DiskFile 类派生两个类，假设为 TextFile 和 MediaFile。前者针对文本文件，后者针对音频和视频文件：
<pre>class TextFile: public DiskFile<br>{<br>  // ......<br>  int  sort_by_words();<br>};<br><br>class MediaFile: public DiskFile<br>{<br>  //......<br>};        </pre>
我们之所以要创建这样的类层次，是因为这样做以后可以创建多态对象，如：
<pre>File *pfile; // *pfile的静态类型是 File<br>if(some_condition)<br>  pfile = new TextFile; // 动态类型是 TextFile<br>else<br>  pfile = new DiskFile; // 动态类型是 DiskFile       </pre>
&nbsp;&nbsp;&nbsp;
假设你正在开发一个基于图形用户界面（GUI）的文件管理器，每个文件都可以以图标方式显示。当鼠标移到图标上并单击右键时，文件管理器打开一个菜单，每
个文件除了共同的菜单项，不同的文件类型还有不同的菜单项。如：共同的菜单项有&#8220;打开&#8221;&#8220;拷贝&#8221;、和&#8220;粘贴&#8221;，此外，还有一些针对特殊文件的专门操作。比
如，文本文件会有&#8220;编辑&#8221;操作，而多媒体文件则会有&#8220;播放&#8221;菜单。为了使用 RTTI 来动态定制菜单，文件管理器必须侦测每个文件的动态类型。利用
运算符 typeid 可以获取与某个对象关联的运行时类型信息。typeid 有一个参数，传递对象或类型名。因此，为了确定 x
的动态类型是不是Y，可以用表达式：typeid(x) == typeid(Y)实现：
<pre>#include &lt;typeinfo&gt; // typeid 需要的头文件<br>void menu::build(const File * pfile)<br>{<br> if (typeid(*pfile)==typeid(TextFile))<br> {<br>  add_option("edit"); <br> }<br> else if (typeid(*pfile)==typeid(MediaFile))<br> {<br> add_option("play"); <br> }<br>}      </pre>
&nbsp;&nbsp;&nbsp;
使用 typeid 要注意一个问题，那就是某些编译器（如 Visual C++）默认状态是禁用 RTTI
的，目的是消除性能上的开销。如果你的程序确实使用了 RTTI，一定要记住在编译前启用 RTTI。使用 typeid 可能产生一些将来的维护问题。假设你决定扩展上述的类层次，从MediaFile
派生另一个叫 LocalizeMedia 的类，用这个类表示带有不同语言说明文字的媒体文件。但 LocalizeMedia 本质上还是个
MediaFile 类型的文件。因此，当用户在该类文件图标上单击右键时，文件管理器必须提供一个&#8220;播放&#8221;菜单。可惜
build()成员函数会调用失败，原因是你没有检查这种特定的文件类型。为了解决这个问题，你必须象下面这样对 build() 打补丁：
<pre>void menu::build(const File * pfile)<br>{<br><br> //......<br><br>  else if (typeid(*pfile)==typeid(LocalizedMedia))<br> {<br>  add_option("play"); <br>  }<br>}     </pre>
&nbsp;&nbsp;&nbsp;
唉，这种做法真是显得太业余了，以后每次添加新的类，毫无疑问都必须打类似的补丁。显然，这不是一个理想的解决方案。这个时候我们就要用到
dynamic_cast，这个运算符用于多态编程中保证在运行时发生正确的转换（即编译器无法验证是否发生正确的转换）。用它来确定某个对象是
MediaFile 对象还是它的派生类对象。dynamic_cast
常用于从多态编程基类指针向派生类指针的向下类型转换。它有两个参数：一个是类型名；另一个是多态对象的指针或引用。其功能是在运行时将对象强制转换为目标类型并返回布尔型结果。也就是说，如果该函数成功地并且是动态的将
*pfile 强制转换为 MediaFile，那么 pfile的动态类型是 MediaFile 或者是它的派生类。否则，pfile 则为其它的类型：
<pre>void menu::build(const File * pfile)<br>{<br> if (dynamic_cast &lt;MediaFile *&gt; (pfile))<br> {<br>  // pfile 是 MediaFile 或者是MediaFile的派生类 LocalizedMedia<br>  add_option("play"); <br> }<br> else if (dynamic_cast &lt;TextFile*&gt; (pfile))<br> {<br>  // pfile 是 TextFile 是TextFile的派生类<br>  add_option("edit"); <br> }<br>}    </pre>
&nbsp;&nbsp;&nbsp; 细细想一下，虽然使用 dynamic_cast 确实很好地解决了我们的问题，但也需要我们付出代价，那就是与 typeid
相比，dynamic_cast 不是一个常量时间的操作。为了确定是否能完成强制类型转换，dynamic_cast`必须在运行时进行一些转换细节操作。因此在使用 dynamic_cast
操作时，应该权衡对性能的影响。<img src ="http://www.cppblog.com/zjj2816/aggbug/67286.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2008-11-19 14:59 <a href="http://www.cppblog.com/zjj2816/archive/2008/11/19/67286.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)进程通信机制</title><link>http://www.cppblog.com/zjj2816/archive/2007/12/13/38433.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Thu, 13 Dec 2007 07:50:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2007/12/13/38433.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/38433.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2007/12/13/38433.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/38433.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/38433.html</trackback:ping><description><![CDATA[		Windows&nbsp;95进程间数据通讯的实现技术<br>1、引言<br>在Windows程序中，各个进程之间常常需要交换数据，进行数据通讯。WIN32&nbsp;API提供了<br>许多函数使我们能够方便高效的进行进程间的通讯，通过这些函数我们可以控制不同进<br>程间的数据交换，就如同在WIN16中对本地进程进行读写操作一样。<br>典型的WIN16两进程可以通过共享内存来进行数据交换：（1）进程A将GlobalAlloc（GM<br>EM_SHARE...）API分配一定长度的内存；（2）进程A将GlobalAlloc函数返回的句柄传递<br>给进程B（通过一个登录消息）；（3）进程B对这个句柄调用GlobalLock函数，并利用G<br>lobalLock函数返回的指针访问数据。这种方法在WIN32中可能失败，这是因为GlobalLo<br>ck函数返回指向的是进程A的内存，由于进程使用的是虚拟地址而非实际物理地址，因此<br>这一指针仅与A进程有关，而于B进程无关。<br>本文探讨了几种WIN32下进程之间通讯的几种实现方法，读者可以使用不同的方法以达到<br>程序运行高效可靠的目的。<br>2、Windows95中进程的内存空间管理<br>WIN32进程间通讯与Windows95的内存管理有密切关系，理解Windows95的内存管理对我们<br>如下的程序设计将会有很大的帮助，下面我们讨论以下Windows95中进程的内存空间管理<br>。<br>在WIN16下，所有Windows应用程序共享单一地址，任何进程都能够对这一空间中属于共<br>享单一的地址空间，任何进程都能够对这一空间中属于其他进程的内存进行读写操作，<br>甚至可以存取操作系统本身的数据，这样就可能破坏其他程序的数据段代码。<br>在WIN32下，每个进程都有自己的地址空间，一个WIN32进程不能存取另一个地址的私有<br>数据，两个进程可以用具有相同值的指针寻址，但所读写的只是它们各自的数据，这样<br>就减少了进程之间的相互干扰。另一方面，每个WIN32进程拥有4GB的地址空间，但并不<br>代表它真正拥有4GB的实际物理内存，而只是操作系统利用CPU的内存分配功能提供的虚<br>拟地址空间。在一般情况下，绝大多数虚拟地址并没有物理内存于它对应，在真正可以<br>使用这些地址空间之前，还要由操作系统提供实际的物理内存（这个过程叫&#8220;提交&#8221;co<br>mmit）。在不同的情况下，系统提交的物理内存是不同的，可能是RAM，也可能是硬盘模<br>拟的虚拟内存。<br>3、WIN32中进程间的通讯<br>在Windows&nbsp;95中，为实现进程间平等的数据交换，用户可以有如下几种选择：<br>*&nbsp;使用内存映射文件<br>*&nbsp;通过共享内存DLL共享内存<br>*&nbsp;向另一进程发送WM_COPYDATA消息<br>*&nbsp;调用ReadProcessMemory以及WriteProcessMemory函数，用户可以发送由GlobalLock(<br>GMEM_SHARE,...)函数调用提取的句柄、GlobalLock函数返回的指针以及VirtualAlloc函<br>数返回的指针。<br>3.1、利用内存映射文件实现WIN32进程间的通讯<br>Windows95中的内存映射文件的机制为我们高效地操作文件提供了一种途径，它允许我们<br>在WIN32进程中保留一段内存区域，把目标文件映射到这段虚拟内存中。在程序实现中必<br>须考虑各进程之间的同步。具体实现步骤如下：<br>首先我们在发送数据的进程中需要通过调用内存映射API函数CreateFileMapping创建一<br>个有名的共享内存：<br>HANDLE&nbsp;CreateFileMapping(<br>HANDLE&nbsp;hFile,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;映射文件的句柄，<br>//设为0xFFFFFFFF以创建一个进程间共享的对象<br>LPSECURITY_ATTRIBUTES&nbsp;lpFileMappingAttributes,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;安全属性<br>DWORD&nbsp;flProtect,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;保护方式<br>DWORD&nbsp;dwMaximumSizeHigh,&nbsp;&nbsp;&nbsp;&nbsp;//对象的大小<br>DWORD&nbsp;dwMaximumSizeLow,<br>LPCTSTR&nbsp;lpName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;必须为映射文件命名<br>);<br>与虚拟内存类似，保护方式可以是PAGE_READONLY或是PAGE_READWRITE。如果多进程都对<br>同一共享内存进行写访问，则必须保持相互间同步。映射文件还可以指定PAGE_WRITECO<br>PY标志，可以保证其原始数据不会遭到破坏，同时允许其他进程在必要时自由的操作数<br>据的拷贝。<br>在创建文件映射对象后使用可以调用MapViewOfFile函数映射到本进程的地址空间内。<br>下面说明创建一个名为MySharedMem的长度为4096字节的有名映射文件：<br>HANDLE&nbsp;hMySharedMapFile=CreateFileMapping((HANDLE)0xFFFFFFFF)，<br>NULL，PAGE_READWRITE，0，0x1000，"MySharedMem")；<br>并映射缓存区视图：<br>LPSTR&nbsp;pszMySharedMapView=(LPSTR)MapViewOfFile(hMySharedMapFile，<br>FILE_MAP_READ|FILE_MAP_WRITE，0，0，0);<br>其他进程访问共享对象，需要获得对象名并调用OpenFileMapping函数。<br>HANDLE&nbsp;hMySharedMapFile=OpenFileMapping(FILE_MAP_WRITE，<br>FALSE，"MySharedMem");<br>一旦其他进程获得映射对象的句柄，可以象创建进程那样调用MapViewOfFile函数来映射<br>对象视图。用户可以使用该对象视图来进行数据读写操作，以达到数据通讯的目的。<br>当用户进程结束使用共享内存后，调用UnmapViewOfFile函数以取消其地址空间内的视图<br>：<br>if&nbsp;(!UnmapViewOfFile(pszMySharedMapView))<br>{&nbsp;AfxMessageBox("could&nbsp;not&nbsp;unmap&nbsp;view&nbsp;of&nbsp;file");&nbsp;}<br>3.2、利用共享内存DLL<br>共享数据DLL允许进程以类似于Windows&nbsp;3.1&nbsp;DLL共享数据的方式访问读写数据，多个进<br>程都可以对该共享数据DLL进行数据操作，达到共享数据的目的。在WIN32中为建立共享<br>内存，必须执行以下步骤：<br>首先创建一个有名的数据区。这在Visual&nbsp;C++中是使用data_seg&nbsp;pragma宏。使用data_<br>seg&nbsp;pragma宏必须注意数据的初始化：<br>#pragma&nbsp;data_seg("MYSEC")<br>char&nbsp;MySharedData[4096]={0};<br>#pragma&nbsp;data_seg()<br>然后在用户的DEF文件中为有名的数据区设定共享属性。<br>LIBRARY&nbsp;TEST<br>DATA&nbsp;READ&nbsp;WRITE<br>SECTIONS<br>&nbsp;&nbsp;&nbsp;&nbsp;.MYSEC&nbsp;READ&nbsp;WRITE&nbsp;SHARED<br>这样每个附属于DLL的进程都将接受到属于自己的数据拷贝，一个进程的数据变化并不会<br>反映到其他进程的数据中。<br>在DEF文件中适当地输出数据。以下的DEF文件项说明了如何以常数变量的形式输出MySh<br>aredData。<br>EXPORTS<br>&nbsp;&nbsp;&nbsp;&nbsp;MySharedData&nbsp;CONSTANT<br>最后在应用程序（进程）按外部变量引用共享数据。<br>extern&nbsp;_export"C"{char&nbsp;*&nbsp;MySharedData[];}<br>进程中使用该变量应注意间接引用。<br>m_pStatic=(CEdit*)GetDlgItem(IDC_SHARED);<br>m_pStatic-&gt;GetLine(0,*MySharedData,80);<br>3.3、用于传输只读数据的WM_COPYDATA<br>传输只读数据可以使用Win32中的WM_COPYDATA消息。该消息的主要目的是允许在进程间<br>传递只读数据。Windows95在通过WM_COPYDATA消息传递期间，不提供继承同步方式。SD<br>K文档推荐用户使用SendMessage函数，接受方在数据拷贝完成前不返回，这样发送方就<br>不可能删除和修改数据：<br>SendMessage(hwnd,WM_COPYDATA,wParam,lParam);<br>其中wParam设置为包含数据的窗口的句柄。lParam指向一个COPYDATASTRUCT的结构：<br>typedef&nbsp;struct&nbsp;tagCOPYDATASTRUCT{<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwData;//用户定义数据<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;cbData;//数据大小<br>&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;lpData;//指向数据的指针<br>}COPYDATASTRUCT;<br>该结构用来定义用户数据。<br>3.4、直接调用ReadProcessMemory和WriteProcessMemory函数实现进程间通讯<br>通过调用ReadProcessMemory以及WriteProcessMemory函数用户可以按类似与Windows3.<br>1的方法实现进程间通讯，在发送进程中分配一块内存存放数据，可以调用GlobalAlloc<br>或者VirtualAlloc函数实现：<br>pApp-&gt;m_hGlobalHandle=GlobalAlloc(GMEM_SHARE,1024);<br>可以得到指针地址：<br>pApp-&gt;mpszGlobalHandlePtr=(LPSTR)GlobalLock<br>(pApp-&gt;m_hGlobalHandle);<br>在接收进程中要用到用户希望影响的进程的打开句柄。为了读写另一进程，应按如下方<br>式调用OpenProcess函数：<br>HANDLE&nbsp;hTargetProcess=OpenProcess(<br>STANDARD_RIGHTS_REQUIRED|<br>PROCESS_VM_REDA|<br>PROCESS_VM_WRITE|<br>PROCESS_VM_OPERATION,//访问权限<br>FALSE,//继承关系<br>dwProcessID);//进程ID<br>为保证OpenProcess函数调用成功，用户所影响的进程必须由上述标志创建。<br>一旦用户获得一个进程的有效句柄，就可以调用ReadProcessMemory函数读取该进程的内<br>存：<br>BOOL&nbsp;ReadProcessMemory(<br>HANDLE&nbsp;hProcess,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;进程指针<br>LPCVOID&nbsp;lpBaseAddress,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;数据块的首地址<br>LPVOID&nbsp;lpBuffer,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;读取数据所需缓冲区<br>DWORD&nbsp;cbRead,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;要读取的字节数<br>LPDWORD&nbsp;lpNumberOfBytesRead<br>);<br>使用同样的句柄也可以写入该进程的内存：<br>BOOL&nbsp;WriteProcessMemory(<br>HANDLE&nbsp;hProcess,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;进程指针<br>LPVOID&nbsp;lpBaseAddress,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;要写入的首地址<br>LPVOID&nbsp;lpBuffer,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;缓冲区地址<br>DWORD&nbsp;cbWrite,&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;要写的字节数<br>LPDWORD&nbsp;lpNumberOfBytesWritten<br>);<br>如下所示是读写另一进程的共享内存中的数据：<br>ReadProcessMemory((HANDLE)hTargetProcess,<br>(LPSTR)lpsz,m_strGlobal.GetBuffer(_MAX_FIELD),<br>_MAX_FIELD,&amp;cb);<br>WriteProcessMemory((HANDLE)hTargetProcess,<br>(LPSTR)lpsz,(LPSTR)STARS,<br>m_strGlobal.GetLength(),&amp;cb);<br>4、进程之间的消息发送与接收<br>在实际应用中进程之间需要发送和接收Windows消息来通知进程间相互通讯，发送方发送<br>通讯的消息以通知接收方，接收方在收到发送方的消息后就可以对内存进行读写操作。<br><br>我们在程序设计中采用Windows注册消息进行消息传递，首先在发送进程初始化过程中进<br>行消息注册：<br>m_nMsgMapped=::RegisterWindowsMessage("Mapped");<br>m_nMsgHandle=::RegisterWindowsMessage("Handle");<br>m_nMsgShared=::RegisterWindowsMessage("Shared");<br>在程序运行中向接收进程发送消息：<br>CWnd*&nbsp;pWndRecv=FindWindow(lpClassName,"Receive");<br>pWndRecv-&gt;SendMessage(m_MsgMapped,0,0);<br>pWndRecv-&gt;SendMessage(m_nMsgHandle,<br>(UINT)GetCurrentProcessID(),(LONG)pApp-&gt;m_hGlobalHandle);<br>pWndRecv-&gt;SendMessage(m_nMsgShared,0,0);<br>可以按如下方式发送WM_COPYDATA消息：<br>static&nbsp;COPYDATASTRUCT&nbsp;cds;//用户存放数据<br>pWnd-&gt;SendMessage(WM_COPYDATA,NULL,(LONG)&amp;cds);<br>接收方进程初始化也必须进行消息注册：<br>UNIT&nbsp;CRecvApp::&nbsp;m_nMsgMapped=::RegisterWindowsMessage("Mapped");<br>UNIT&nbsp;CRecvApp::m_nMsgHandle=::RegisterWindowsMessage("Handle");<br>UNIT&nbsp;CRecvApp::m_nMsgShared=::RegisterWindowsMessage("Shared");<br>同时映射消息函数如下：<br>ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgMapped,OnRegMsgMapped)<br>ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgHandle,OnRegMsgHandle)<br>ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgShared,OnRegMsgShared)<br>在这些消息函数我们就可以采用上述技术实现接收进程中数据的读写操作了。<br>5、结束语<br>从以上分析中我们可以看出Windows95的内存管理与Windows&nbsp;3.x相比有很多的不同，对<br>进程之间的通讯有较为严格的限制。这就确保了任何故障程序无法意外地写入用户的地<br>址空间，而用户则可根据实际情况灵活地进行进程间的数据通讯，从这一点上来讲Wind<br>ows95增强应用程序的强壮性。<br>参考文献：<br>1、&nbsp;David&nbsp;J.Kruglinski,&nbsp;Visual&nbsp;C++技术内幕,&nbsp;北京：清华大学出版社，1995.<br>2、&nbsp;Microsoft&nbsp;Co.&nbsp;Visual&nbsp;C++&nbsp;5.0&nbsp;On&nbsp;Line&nbsp;Help. <br><img src ="http://www.cppblog.com/zjj2816/aggbug/38433.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2007-12-13 15:50 <a href="http://www.cppblog.com/zjj2816/archive/2007/12/13/38433.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows mobile 关闭gprs连接</title><link>http://www.cppblog.com/zjj2816/archive/2007/11/22/37127.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Thu, 22 Nov 2007 04:59:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2007/11/22/37127.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/37127.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2007/11/22/37127.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/37127.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/37127.html</trackback:ping><description><![CDATA[unsigned int CloseRasGPRSConnections()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp; int index; // An integer index<br>&nbsp;&nbsp;&nbsp;&nbsp; DWORD dwError, dwRasConnSize, dwNumConnections; // Number of connections found<br>&nbsp;&nbsp;&nbsp;&nbsp; RASCONN RasConn[20]; // Buffer for connection state data,Assume the maximum number of entries is 20.<br>&nbsp;&nbsp;&nbsp; BOOL RETURN_VALUE=0;<br>&nbsp;&nbsp;&nbsp; WCHAR *MySelectNetName;<br><br>&nbsp;&nbsp;&nbsp;&nbsp; // Assume no more than 20 connections.<br>&nbsp;&nbsp;&nbsp;&nbsp; RasConn[0].dwSize = sizeof (RASCONN);<br>&nbsp;&nbsp;&nbsp;&nbsp; dwRasConnSize = 20 * sizeof (RASCONN);<br><br>&nbsp;&nbsp;&nbsp;&nbsp; // Find all connections.<br>&nbsp;&nbsp;&nbsp; &nbsp;if (dwError = RasEnumConnections (RasConn, &amp;dwRasConnSize,&amp;dwNumConnections))<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return -1;<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp; // If there are no connections, return zero.<br>&nbsp;&nbsp;&nbsp;&nbsp; if (!dwNumConnections)<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return 0;<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp; // Terminate all of the remote access connections.<br>&nbsp;&nbsp;&nbsp;&nbsp; GetConnectionStatus();<br>&nbsp;&nbsp;&nbsp; //here add to get selected network<br>&nbsp;&nbsp;&nbsp; MySelectNetName=GetMMSSelectNet();<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; GPRSServerName* P_CMWAPtemp=pCMWAP_backup;<br>&nbsp;&nbsp;&nbsp;&nbsp; for (index = 0; index &lt; (int)dwNumConnections; ++index)<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while( P_CMWAPtemp )<br>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(!wcscmp(RasConn[index].szEntryName,P_CMWAPtemp-&gt;ServerName)||<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; !wcscmp(RasConn[index].szEntryName, MySelectNetName))<br>&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; if (dwError = RasHangUp (RasConn[index].hrasconn))<br>&nbsp;&nbsp;&nbsp; &nbsp;&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;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; RETURN_VALUE=-1;<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //successfully disconnect cmwap; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; RETURN_VALUE=0;<br>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; P_CMWAPtemp = P_CMWAPtemp-&gt;pnext ;<br>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; //free mem<br>&nbsp;&nbsp;&nbsp;&nbsp; freelink(pCMWAP_backup);<br>&nbsp;&nbsp;&nbsp;&nbsp; return RETURN_VALUE;<br>}<br><br><br><img src ="http://www.cppblog.com/zjj2816/aggbug/37127.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2007-11-22 12:59 <a href="http://www.cppblog.com/zjj2816/archive/2007/11/22/37127.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++ 和 jscript</title><link>http://www.cppblog.com/zjj2816/archive/2007/11/20/36988.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Tue, 20 Nov 2007 01:19:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2007/11/20/36988.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/36988.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2007/11/20/36988.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/36988.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/36988.html</trackback:ping><description><![CDATA[#pragma once<br><br>#include &lt;afxdisp.h&gt;<br>#include &lt;activscp.h&gt;<br><br>class CCodeObject;<br>class CScriptSite;<br><br>class CScriptingSupportHelper<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; CScriptingSupportHelper();<br>&nbsp;&nbsp;&nbsp; ~CScriptingSupportHelper();<br><br>&nbsp;&nbsp;&nbsp; BOOL Create(CWnd* pWnd);<br>&nbsp;&nbsp;&nbsp; BOOL RunScript(CString str);<br><br>&nbsp;&nbsp;&nbsp; CCodeObject* GetCodeObject() const { return m_pCodeObject; }<br>&nbsp;&nbsp;&nbsp; CScriptSite* GetScriptSite() const { return m_pScriptSite; }<br>&nbsp;&nbsp;&nbsp; IActiveScript* GetActiveScript() const { return m_pActiveScript; }<br><br>private:<br>&nbsp;&nbsp;&nbsp; CCodeObject* m_pCodeObject;<br>&nbsp;&nbsp;&nbsp; CScriptSite* m_pScriptSite;<br><br>&nbsp;&nbsp;&nbsp; IActiveScript* m_pActiveScript;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; IActiveScriptParse* m_pActiveScriptParse;<br>};<br><br>class CCodeObject : public CCmdTarget<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; CCodeObject(CScriptingSupportHelper* pScripting, CWnd* pWnd);<br>&nbsp;&nbsp;&nbsp; virtual ~CCodeObject();<br><br>&nbsp;&nbsp;&nbsp; void Line(long, long, long, long);<br>&nbsp;&nbsp;&nbsp; void Ellipse(long, long, long, long);<br>&nbsp;&nbsp;&nbsp; void DrawText(LPCTSTR msg, long x, long y, long w, long h);<br><br>&nbsp;&nbsp;&nbsp; void OnPaint();<br>&nbsp;&nbsp;&nbsp; void OnMouseClick(long x, long y);<br><br>private:<br>&nbsp;&nbsp;&nbsp; CWnd* m_pWnd;<br>&nbsp;&nbsp;&nbsp; CScriptingSupportHelper* m_pScripting;<br>&nbsp;&nbsp;&nbsp; BOOL GetDispatch(OLECHAR* name, COleDispatchDriver&amp; disp, DISPID&amp; dispid);<br><br>&nbsp;&nbsp;&nbsp; enum <br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; idLine = 1,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; idEllipse,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; idDrawText,<br>&nbsp;&nbsp;&nbsp; };<br><br>&nbsp;&nbsp;&nbsp; DECLARE_DISPATCH_MAP()<br>};<br><br>class CScriptSite : public IActiveScriptSite<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; CScriptSite(CScriptingSupportHelper* pScripting)&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m_pScripting = pScripting;<br>&nbsp;&nbsp;&nbsp; };<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; ~CScriptSite()&nbsp; <br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; };<br><br>&nbsp;&nbsp;&nbsp; virtual ULONG STDMETHODCALLTYPE AddRef() <br>&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return InterlockedIncrement(&amp;m_nRefCount); <br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; virtual ULONG STDMETHODCALLTYPE Release() <br>&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return InterlockedDecrement(&amp;m_nRefCount);<br>&nbsp;&nbsp;&nbsp; };<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppObj)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *ppObj = NULL;<br><br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if ((iid == IID_IUnknown) || (iid == IID_IActiveScriptSite))<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *ppObj= (IActiveScriptSite*)this;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; AddRef();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return S_OK;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } <br><br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return E_NOINTERFACE;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; virtual HRESULT STDMETHODCALLTYPE GetLCID(LCID __RPC_FAR *) <br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return E_NOTIMPL;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; virtual HRESULT STDMETHODCALLTYPE GetItemInfo(LPCOLESTR, DWORD, IUnknown __RPC_FAR *__RPC_FAR * pObj, ITypeInfo __RPC_FAR *__RPC_FAR *)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ASSERT(m_pScripting);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ASSERT(m_pScripting-&gt;GetCodeObject());<br><br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *pObj = m_pScripting-&gt;GetCodeObject()-&gt;GetIDispatch(TRUE);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return S_OK;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; virtual HRESULT STDMETHODCALLTYPE GetDocVersionString(BSTR __RPC_FAR *)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return E_NOTIMPL;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; virtual HRESULT STDMETHODCALLTYPE OnScriptTerminate(const VARIANT __RPC_FAR * ,const EXCEPINFO __RPC_FAR *) <br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return E_NOTIMPL;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; virtual HRESULT STDMETHODCALLTYPE OnStateChange(SCRIPTSTATE)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return E_NOTIMPL;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; virtual HRESULT STDMETHODCALLTYPE OnScriptError(IActiveScriptError __RPC_FAR * pScriptError)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return E_NOTIMPL;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; virtual HRESULT STDMETHODCALLTYPE OnEnterScript()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return E_NOTIMPL;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; virtual HRESULT STDMETHODCALLTYPE OnLeaveScript()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return E_NOTIMPL;<br>&nbsp;&nbsp;&nbsp; }<br><br>private:<br>&nbsp;&nbsp;&nbsp; long m_nRefCount;<br>&nbsp;&nbsp;&nbsp; CScriptingSupportHelper* m_pScripting;<br>};<br><br>#include "StdAfx.h"<br>#include "ScriptingSupport.h"<br><br>CCodeObject::CCodeObject(CScriptingSupportHelper* pScripting, CWnd* pWnd) <br>&nbsp;&nbsp;&nbsp; : m_pWnd(pWnd),<br>&nbsp;&nbsp;&nbsp; &nbsp; m_pScripting(pScripting)<br><br>{<br>&nbsp;&nbsp;&nbsp; EnableAutomation();<br>}<br><br>CCodeObject::~CCodeObject() <br>{<br>}<br><br>BEGIN_DISPATCH_MAP(CCodeObject, CCmdTarget)<br>DISP_FUNCTION_ID(CCodeObject, "Line", idLine, Line, VT_EMPTY, VTS_I4 VTS_I4 VTS_I4 VTS_I4)<br>DISP_FUNCTION_ID(CCodeObject, "Ellipse", idEllipse, Ellipse, VT_EMPTY, VTS_I4 VTS_I4 VTS_I4 VTS_I4)<br>DISP_FUNCTION_ID(CCodeObject, "DrawText", idDrawText, DrawText, VT_EMPTY, VTS_BSTR VTS_I4 VTS_I4 VTS_I4 VTS_I4)<br>END_DISPATCH_MAP()<br><br>void CCodeObject::Line(long x1, long y1, long x2, long y2)<br>{<br>&nbsp;&nbsp;&nbsp; CWindowDC dc(m_pWnd);<br><br>&nbsp;&nbsp;&nbsp; dc.MoveTo(x1, y1);<br>&nbsp;&nbsp;&nbsp; dc.LineTo(x2, y2);<br>}<br><br>void CCodeObject::Ellipse(long x1, long y1, long x2, long y2)<br>{<br>&nbsp;&nbsp;&nbsp; CWindowDC dc(m_pWnd);<br>&nbsp;&nbsp;&nbsp; dc.Ellipse(x1, y1, x2, y2);<br>}<br><br>void CCodeObject::DrawText(LPCTSTR msg, long x, long y, long w, long h)<br>{<br>&nbsp;&nbsp;&nbsp; CWindowDC dc(m_pWnd);<br>&nbsp;&nbsp;&nbsp; CRect rect(x, y, x+w, y+h);<br><br>&nbsp;&nbsp;&nbsp; dc.DrawText(msg, rect, 0);<br>}<br><br>void CCodeObject::OnPaint()<br>{<br>&nbsp;&nbsp;&nbsp; COleDispatchDriver disp;<br>&nbsp;&nbsp;&nbsp; DISPID dispid;<br>&nbsp;&nbsp;&nbsp; if (GetDispatch(L"OnPaint", disp, dispid)) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; disp.InvokeHelper(dispid, DISPATCH_METHOD, VT_EMPTY, 0, 0);<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br>BOOL CCodeObject::GetDispatch(OLECHAR* name, COleDispatchDriver&amp; disp, DISPID&amp; dispid) <br>{<br>&nbsp;&nbsp;&nbsp; IDispatch* pScriptDispatch = 0;<br>&nbsp;&nbsp;&nbsp; m_pScripting-&gt;GetActiveScript()-&gt;GetScriptDispatch(0, &amp;pScriptDispatch);<br>&nbsp;&nbsp;&nbsp; disp.AttachDispatch(pScriptDispatch);<br>&nbsp;&nbsp;&nbsp; HRESULT hr = pScriptDispatch-&gt;GetIDsOfNames(IID_NULL, &amp;name, 1, LOCALE_SYSTEM_DEFAULT, &amp;dispid);<br>&nbsp;&nbsp;&nbsp; return SUCCEEDED(hr);<br>}<br><br>void CCodeObject::OnMouseClick(long x, long y)<br>{<br>&nbsp;&nbsp;&nbsp; COleDispatchDriver disp;<br>&nbsp;&nbsp;&nbsp; DISPID dispid;<br>&nbsp;&nbsp;&nbsp; if (GetDispatch(L"OnMouseClick", disp, dispid)) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; disp.InvokeHelper(dispid, DISPATCH_METHOD, VT_EMPTY, 0, (const BYTE*)(VTS_I4 VTS_I4), x, y);<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br>CScriptingSupportHelper::CScriptingSupportHelper()<br>&nbsp;&nbsp;&nbsp; : m_pCodeObject(0),<br>&nbsp;&nbsp;&nbsp; &nbsp; m_pScriptSite(0),<br>&nbsp;&nbsp;&nbsp; &nbsp; m_pActiveScript(0),<br>&nbsp;&nbsp;&nbsp; &nbsp; m_pActiveScriptParse(0)<br>{<br>}<br><br>CScriptingSupportHelper::~CScriptingSupportHelper()<br>{<br>&nbsp;&nbsp;&nbsp; if (m_pActiveScript) <br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m_pActiveScript-&gt;Close();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m_pActiveScriptParse-&gt;Release();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m_pActiveScript-&gt;Release();<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; delete m_pCodeObject; m_pCodeObject=0;<br>&nbsp;&nbsp;&nbsp; delete m_pScriptSite; m_pScriptSite=0;<br>}<br><br>BOOL CScriptingSupportHelper::RunScript(CString strText)<br>{<br>&nbsp;&nbsp;&nbsp; EXCEPINFO ei = {0};<br>&nbsp;&nbsp;&nbsp; BSTR bstrText = strText.AllocSysString();<br>&nbsp;&nbsp;&nbsp; m_pActiveScriptParse-&gt;ParseScriptText(bstrText, NULL, NULL, NULL, 0, 0, 0, NULL, &amp;ei);<br>&nbsp;&nbsp;&nbsp; SysFreeString(bstrText);<br><br>&nbsp;&nbsp;&nbsp; m_pActiveScript-&gt;SetScriptState(SCRIPTSTATE_CONNECTED);<br><br>&nbsp;&nbsp;&nbsp; return TRUE;<br>}<br><br>BOOL CScriptingSupportHelper::Create(CWnd* pWnd)<br>{<br>&nbsp;&nbsp;&nbsp; m_pCodeObject = new CCodeObject(this, pWnd);<br>&nbsp;&nbsp;&nbsp; m_pScriptSite = new CScriptSite(this);<br><br>&nbsp;&nbsp;&nbsp; CLSID clsidJScript;<br>&nbsp;&nbsp;&nbsp; CLSIDFromProgID(L"JScript", &amp;clsidJScript);<br>&nbsp;&nbsp;&nbsp; CoCreateInstance(clsidJScript, NULL, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void **)&amp;m_pActiveScript);<br>&nbsp;&nbsp;&nbsp; m_pActiveScript-&gt;QueryInterface(IID_IActiveScriptParse, (void**)&amp;m_pActiveScriptParse);<br>&nbsp;&nbsp;&nbsp; m_pActiveScript-&gt;SetScriptSite(m_pScriptSite);<br>&nbsp;&nbsp;&nbsp; m_pActiveScript-&gt;AddNamedItem(L"Code", SCRIPTITEM_ISVISIBLE | SCRIPTITEM_ISSOURCE | SCRIPTITEM_GLOBALMEMBERS);<br>&nbsp;&nbsp;&nbsp; m_pActiveScriptParse-&gt;InitNew();<br><br><br>&nbsp;&nbsp;&nbsp; return TRUE;<br>}<br><br><br><br><br><img src ="http://www.cppblog.com/zjj2816/aggbug/36988.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2007-11-20 09:19 <a href="http://www.cppblog.com/zjj2816/archive/2007/11/20/36988.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(msdn)Using MFC to Automate SAPI (SAPI 5.3)http://msdn2.microsoft.com/en-us/library/ms717069.aspx</title><link>http://www.cppblog.com/zjj2816/archive/2007/11/20/36985.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Tue, 20 Nov 2007 01:06:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2007/11/20/36985.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/36985.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2007/11/20/36985.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/36985.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/36985.html</trackback:ping><description><![CDATA[<div class="title">Microsoft Speech API 5.3&nbsp;&nbsp; 用oleview 可以产生 idl 文件 再用 midl工具 可以产生 tlb,h,c 存根文件 等.<br></div>
<!--content type: HTML. Transform: psdk2mtps.xslt.-->
<h1>Using MFC to Automate SAPI</h1>
<h2>Introduction</h2>
<p>The
Microsoft Foundation Classes (MFC) provides an easy and convenient way
to automate calls to SAPI using its Class Wizard to generate wrappers
for the SAPI layer from the SAPI Type Library.</p>
<p>In order to accomplish this, perform the following steps:</p>
<ol>
    <li>Create a new MFCAppWizard(exe) project in Visual C++. </li>
    <li>Based
    on the type of application you are creating, follow the wizard prompts.
    In Step 3 of the wizard prompts, (or Step 2 if you are creating a
    Dialog Based application) make sure that the Automation check box is
    selected under the heading, What other support would you like to
    include?</li>
</ol>
<p>Once the new project is ready, access Class Wizard. </p>
<ol>
    <li>Click the <span style="color: red;">Automation</span> tab, and then click <span style="color: red;">Add Class and select From a type library</span> in the drop-down list.
    </li>
    <li>Browse for the sapi.dll file and open it. </li>
    <li>Select the
    classes you would like Class Wizard to generate a wrapper for. The
    resulting default header and implementation files are sapi.h and
    sapi.cpp respectively. The rest of this document assumes that you have
    chosen to use these default file names. Click OK.</li>
    <li>You should now be back in the Class Wizard window. Click OK.</li>
</ol>
After you are done with the above steps, Visual C++ will automatically
add the Class Wizard generated files sapi.cpp and sapi.h to your
project.
<p>Upon viewing the sapi.h file, you should notice that it is nothing
more than an automation wrapper that has been generated for all the
classes you selected. Notice that all the classes inherit from
COleDispatchDriver, hence the dispatch interface needs to be set up.
This only requires a few lines of simple code, after which the wrapper
class can be used just like any other C++ class.</p>
<h2>Example</h2>
<p>This
example assumes that you chose to generate a wrapper for the
ISpeechVoice class from among any other classes you may have selected.
Using the project created above, include the sapi.h file within a
source file in the project that will make automation calls to SAPI
using the wrapper. In that source file, type the following code.</p>
<pre><code>CLSID CLSID_SpVoice;    // class ID for the SAPI SpVoice object<br>LPDISPATCH pDisp;       // dispatch interface for the class<br>ISpeechVoice voice;     // use the MFC Class Wizard generated wrapper<br><br>CLSIDFromProgID(L"SAPI.SpVoice", &amp;CLSID;_SpVoice);<br>voice.CreateDispatch(CLSID_SpVoice);<br>pDisp = voice.m_lpDispatch;<br><br>HRESULT hr = pDisp-&gt;QueryInterface(CLSID_SpVoice, (void**)&amp;voice;.m_lpDispatch);<br><br>if (hr == S_OK) {<br>    pDisp-&gt;Release();<br>}<br>else {<br>    voice.AttachDispatch(pDisp, TRUE);<br>}<br><br>voice.Speak("hello world", 1);   // asynchronous call to Speak method of ISpeechVoice interface<br></code></pre>
<p>If you have been following the steps outlined above
properly, you should hear your computer say "hello world!" That's all
there is to using MFC to make automation calls to SAPI. Currently
however, not all the wrapper classes generated by MFC's Class Wizard
work properly. For instance, the ISpeechLexicon interface does not
work. The work around for this is to implement your own automation
wrapper classes using C++. The steps to do that are beyond the scope of
this document. Of course, you can always use the COM interfaces in C++
and Automation in Visual Basic to ensure that every interface in SAPI
works easily and flawlessly.</p><img src ="http://www.cppblog.com/zjj2816/aggbug/36985.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2007-11-20 09:06 <a href="http://www.cppblog.com/zjj2816/archive/2007/11/20/36985.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>客户端调用com</title><link>http://www.cppblog.com/zjj2816/archive/2007/11/20/36983.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Tue, 20 Nov 2007 00:49:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2007/11/20/36983.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/36983.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2007/11/20/36983.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/36983.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/36983.html</trackback:ping><description><![CDATA[void opercom()<br>{<br>&nbsp;&nbsp;&nbsp; ::CoInitializeEx(NULL, COINIT_MULTITHREADED); <br>&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;&nbsp; {2D8EBDEE-437C-47c9-ABCC-F169E5E781D0}speeddial<br>&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;&nbsp; {85140985-7A18-4009-B5FB-43268FD154F8}ISpRecognizerLite<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CLSID CLSID_SpVoice;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::CLSIDFromProgID(L"SpeedDial", &amp;CLSID_SpVoice);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPCLASSFACTORY pClsF;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPUNKNOWN punk; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::CoGetClassObject(CLSID_SpVoice,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(void**)&amp;pClsF);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pClsF-&gt;CreateInstance(NULL,IID_IUnknown,(void**)&amp;punk);<br>&nbsp;&nbsp;&nbsp; punk-&gt;QueryInterface(IID_ISpRecognizerLite,(void**)&amp;非抽象类);<br>&nbsp;&nbsp;&nbsp; ::CoUninitialize();<br>}<br><img src ="http://www.cppblog.com/zjj2816/aggbug/36983.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2007-11-20 08:49 <a href="http://www.cppblog.com/zjj2816/archive/2007/11/20/36983.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)手工注册com</title><link>http://www.cppblog.com/zjj2816/archive/2007/11/20/36982.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Tue, 20 Nov 2007 00:48:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2007/11/20/36982.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/36982.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2007/11/20/36982.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/36982.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/36982.html</trackback:ping><description><![CDATA[BOOL regcom(LPCWSTR strLib)<br>{<br>&nbsp;&nbsp;&nbsp; //for registration<br>&nbsp;&nbsp;&nbsp; HMODULE hLib = ::LoadLibrary(strLib);<br>&nbsp;&nbsp;&nbsp; if(hLib == 0) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; HRESULT (STDAPICALLTYPE *pDllRegisterServer)();<br>&nbsp;&nbsp;&nbsp; (FARPROC&amp;)pDllRegisterServer = ::GetProcAddress(hLib, _T("DllRegisterServer"));<br>&nbsp;&nbsp;&nbsp; if(pDllRegisterServer == NULL) {&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ::FreeLibrary(hLib);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; if(FAILED(pDllRegisterServer ())) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ::FreeLibrary(hLib);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ::FreeLibrary(hLib);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return TRUE;<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br>BOOL unregcom(LPCWSTR strLib)<br>{<br>&nbsp;&nbsp;&nbsp; HMODULE hLib = ::LoadLibrary(strLib);<br>&nbsp;&nbsp;&nbsp; if(hLib == 0) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; HRESULT (STDAPICALLTYPE *pDllUnregisterServer)();<br>&nbsp;&nbsp;&nbsp; (FARPROC&amp;)pDllUnregisterServer = ::GetProcAddress(hLib, _T("DllUnregisterServer"));<br>&nbsp;&nbsp;&nbsp; if(pDllUnregisterServer == NULL) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ::FreeLibrary(hLib);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; if(FAILED(pDllUnregisterServer())) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ::FreeLibrary(hLib);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ::FreeLibrary(hLib);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return TRUE;<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br><br><img src ="http://www.cppblog.com/zjj2816/aggbug/36982.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2007-11-20 08:48 <a href="http://www.cppblog.com/zjj2816/archive/2007/11/20/36982.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Rapi 使用</title><link>http://www.cppblog.com/zjj2816/archive/2007/11/20/36981.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Tue, 20 Nov 2007 00:46:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2007/11/20/36981.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/36981.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2007/11/20/36981.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/36981.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/36981.html</trackback:ping><description><![CDATA[void CopyFilePCtoWinCE(CString strFileNamePC, CString strFileNamePPC)<br>{<br>&nbsp;&nbsp;&nbsp; CFile oldFile; <br>&nbsp;&nbsp;&nbsp; oldFile.Open(strFileNamePC, CFile::modeRead |CFile::typeBinary); <br>&nbsp;&nbsp;&nbsp; int iLen = oldFile.GetLength(); <br>&nbsp;&nbsp;&nbsp; iLen = iLen / BUFFER_SIZE; <br>&nbsp;&nbsp;&nbsp; BSTR bstr = strFileNamePPC.AllocSysString(); <br>&nbsp;&nbsp;&nbsp; SysFreeString(bstr); <br>&nbsp;&nbsp;&nbsp; CeRapiInit(); <br>&nbsp;&nbsp;&nbsp; HANDLE h = CeCreateFile(bstr, GENERIC_READ | GENERIC_WRITE, 0, NULL, <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); <br>&nbsp;&nbsp;&nbsp; char cTemp[BUFFER_SIZE]; <br>&nbsp;&nbsp;&nbsp; DWORD nbytes; <br>&nbsp;&nbsp;&nbsp; int iTotBytes = 0; <br>&nbsp;&nbsp;&nbsp; int iReaded=0; <br>&nbsp;&nbsp;&nbsp; while((iReaded=oldFile.Read(&amp;cTemp, BUFFER_SIZE)) &gt;= 1) <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; CeWriteFile(h, &amp;cTemp, (DWORD)iReaded, &amp;nbytes, NULL); <br>&nbsp;&nbsp;&nbsp; CeCloseHandle(h); <br>&nbsp;&nbsp;&nbsp; oldFile.Close(); <br>&nbsp;&nbsp;&nbsp; CeRapiUninit(); <br>}<br><br>void CopyFileWinCEtoPC(CString strFileNamePPC, CString strFileNamePC)<br>{<br>&nbsp;&nbsp;&nbsp; BSTR bstr = strFileNamePPC.AllocSysString(); <br>&nbsp;&nbsp;&nbsp; SysFreeString(bstr); <br>&nbsp;&nbsp;&nbsp; CeRapiInit(); <br><br>&nbsp;&nbsp;&nbsp; HANDLE h; <br>&nbsp;&nbsp;&nbsp; h = CeCreateFile(bstr, GENERIC_READ, FILE_SHARE_READ, NULL, <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); <br><br>&nbsp;&nbsp;&nbsp; CFile oldFile; <br>&nbsp;&nbsp;&nbsp; oldFile.Open(strFileNamePC, CFile::modeCreate | CFile::modeWrite); <br><br>&nbsp;&nbsp;&nbsp; char cTemp[BUFFER_SIZE]; <br>&nbsp;&nbsp;&nbsp; DWORD nbytes; <br>&nbsp;&nbsp;&nbsp; CString s; <br><br>&nbsp;&nbsp;&nbsp; while(CeReadFile(h, &amp;cTemp, (DWORD)BUFFER_SIZE, &amp;nbytes, NULL) == TRUE) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; oldFile.Write(&amp;cTemp, nbytes); <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(nbytes &lt; BUFFER_SIZE) <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break; <br>&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp; CeCloseHandle(h); <br>&nbsp;&nbsp;&nbsp; oldFile.Close(); <br>&nbsp;&nbsp;&nbsp; CeRapiUninit();&nbsp; <br>}<br><br>BOOL DeleteFileFromCE(CString strFileNamePPC)<br>{<br>&nbsp;&nbsp;&nbsp; BSTR bstr = strFileNamePPC.AllocSysString(); <br>&nbsp;&nbsp;&nbsp; SysFreeString(bstr); <br>&nbsp;&nbsp;&nbsp; CeRapiInit();<br>&nbsp;&nbsp;&nbsp; BOOL bRet = CeDeleteFile(bstr);<br>&nbsp;&nbsp;&nbsp; CeRapiUninit();<br>&nbsp;&nbsp;&nbsp; return bRet;<br>}<br><br><br><img src ="http://www.cppblog.com/zjj2816/aggbug/36981.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2007-11-20 08:46 <a href="http://www.cppblog.com/zjj2816/archive/2007/11/20/36981.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数对比</title><link>http://www.cppblog.com/zjj2816/archive/2007/11/19/36923.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Mon, 19 Nov 2007 02:25:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2007/11/19/36923.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/36923.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2007/11/19/36923.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/36923.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/36923.html</trackback:ping><description><![CDATA[<span style="color: #000000;"><br><span style="color: red;">用_t</span></span><span style="color: #000000;"><span style="color: red;">替换字符'w',比如 wcsncpy&nbsp; to _tcsncpy(自适应函数).<br></span></span><br>
<p><strong>_tcsncpy_l </strong><span style="color: #000000;"><span style="color: red;">后缀&nbsp; _l 不推荐使用的函数<br></span></span></p>
<p><strong>_tcsncpy_s </strong><span style="color: #000000;"><span style="color: red;">后缀&nbsp; _s </span></span><span id="nsrTitle">Security Enhancements in the CRT</span> </p>
<p><strong>_tcsncpy_s_l </strong><span style="color: #000000;"><span style="color: red;">后缀&nbsp; _s_l 同 _s</span></span></p>
<p>security enhancements</p>
<span style="color: #000000;"><span style="color: red;"></span><br></span><span style="color: #000000;">宽字符处理函数函数与普通函数对照表&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">字符分类：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;宽字符函数普通C函数描述&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswalnum（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isalnum（）&nbsp;测试字符是否为数字或字母&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswalpha（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isalpha（）&nbsp;测试字符是否是字母&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswcntrl（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iscntrl（）&nbsp;测试字符是否是控制符&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswdigit（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isdigit（）&nbsp;测试字符是否为数字&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswgraph（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isgraph（）&nbsp;测试字符是否是可见字符&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswlower（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;islower（）&nbsp;测试字符是否是小写字符&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswprint（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isprint（）&nbsp;测试字符是否是可打印字符&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswpunct（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ispunct（）&nbsp;测试字符是否是标点符号&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswspace（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isspace（）&nbsp;测试字符是否是空白符号&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswupper（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isupper（）&nbsp;测试字符是否是大写字符&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">iswxdigit（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isxdigit（）测试字符是否是十六进制的数字&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">大小写转换：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">宽字符函数&nbsp;&nbsp;&nbsp;&nbsp;普通C函数描述&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">towlower（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tolower（）&nbsp;把字符转换为小写&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">towupper（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;toupper（）&nbsp;把字符转换为大写&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">字符比较：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;宽字符函数普通C函数描述&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcscoll（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcoll（）&nbsp;比较字符串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">日期和时间转换：&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">宽字符函数描述&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">strftime（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据指定的字符串格式和locale设置格式化日期和时间&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcsftime（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据指定的字符串格式和locale设置格式化日期和时间，&nbsp;并返回宽字符串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">strptime（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据指定格式把字符串转换为时间值，&nbsp;是strftime的反过程&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">打印和扫描字符串：&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">宽字符函数描述&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">fprintf（）</span><span style="color: #000000;">/</span><span style="color: #000000;">fwprintf（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用vararg参量的格式化输出&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">fscanf（）</span><span style="color: #000000;">/</span><span style="color: #000000;">fwscanf（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;格式化读入&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">printf（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用vararg参量的格式化输出到标准输出&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">scanf（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从标准输入的格式化读入&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">sprintf（）</span><span style="color: #000000;">/</span><span style="color: #000000;">swprintf（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据vararg参量表格式化成字符串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">sscanf（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以字符串作格式化读入&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">vfprintf（）</span><span style="color: #000000;">/</span><span style="color: #000000;">vfwprintf（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用stdarg参量表格式化输出到文件&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">vprintf（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用stdarg参量表格式化输出到标准输出&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">vsprintf（）</span><span style="color: #000000;">/</span><span style="color: #000000;">vswprintf（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;格式化stdarg参量表并写到字符串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">数字转换：&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">宽字符函数&nbsp;&nbsp;&nbsp;&nbsp;普通C函数描述&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcstod（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strtod（）&nbsp;&nbsp;把宽字符的初始部分转换为双精度浮点数&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcstol（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strtol（）&nbsp;&nbsp;把宽字符的初始部分转换为长整数&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcstoul（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strtoul（）&nbsp;把宽字符的初始部分转换为无符号长整数&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">多字节字符和宽字符转换及操作：&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">宽字符函数描述&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">mblen（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据locale的设置确定字符的字节数&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">mbstowcs（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;把多字节字符串转换为宽字符串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">mbtowc（）</span><span style="color: #000000;">/</span><span style="color: #000000;">btowc（）&nbsp;&nbsp;&nbsp;&nbsp;把多字节字符转换为宽字符&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcstombs（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;把宽字符串转换为多字节字符串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wctomb（）</span><span style="color: #000000;">/</span><span style="color: #000000;">wctob（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;把宽字符转换为多字节字符&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">输入和输出：&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">宽字符函数&nbsp;&nbsp;&nbsp;&nbsp;普通C函数描述&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">fgetwc（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fgetc（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从流中读入一个字符并转换为宽字符&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">fgetws（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fgets（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从流中读入一个字符串并转换为宽字符串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">fputwc（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fputc（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;把宽字符转换为多字节字符并且输出到标准输出&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">fputws（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fputs（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;把宽字符串转换为多字节字符并且输出到标准输出串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">getwc（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getc（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从标准输入中读取字符，&nbsp;并且转换为宽字符&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">getwchar（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getchar（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从标准输入中读取字符，&nbsp;并且转换为宽字符&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">None&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gets（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用fgetws（）&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">putwc（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;putc（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;把宽字符转换成多字节字符并且写到标准输出&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">putwchar（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;putchar（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;把宽字符转换成多字节字符并且写到标准输出&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">None&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用fputws（）&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">ungetwc（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ungetc（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;把一个宽字符放回到输入流中&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">字符串操作：&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">宽字符函数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;普通C函数描述&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcscat（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcat（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;把一个字符串接到另一个字符串的尾部&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcsncat（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strncat（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;类似于wcscat（），&nbsp;而且指定粘接字符串的粘接长度.&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcschr（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strchr（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;查找子字符串的第一个位置&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcsrchr（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strrchr（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从尾部开始查找子字符串出现的第一个位置&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcspbrk（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strpbrk（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从一字符字符串中查找另一字符串中任何一个字符第一次出现的位置&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcswcs（）</span><span style="color: #000000;">/</span><span style="color: #000000;">wcsstr（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strchr（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在一字符串中查找另一字符串第一次出现的位置&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcscspn（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcspn（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回不包含第二个字符串的的初始数目&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcsspn（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strspn（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回包含第二个字符串的初始数目&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcscpy（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;拷贝字符串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcsncpy（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strncpy（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;类似于wcscpy（），&nbsp;同时指定拷贝的数目&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcscmp（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcmp（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;比较两个宽字符串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcsncmp（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strncmp（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;类似于wcscmp（），&nbsp;还要指定比较字符字符串的数目&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcslen（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strlen（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;获得宽字符串的数目&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcstok（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strtok（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据标示符把宽字符串分解成一系列字符串&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcswidth（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;None&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;获得宽字符串的宽度&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">wcwidth（）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;None&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;获得宽字符的宽度&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">另外还有对应于memory操作的&nbsp;wmemcpy（），&nbsp;wmemchr（），&nbsp;wmemcmp（），&nbsp;wmemmove（），&nbsp;wmemset（）．</span> <img src ="http://www.cppblog.com/zjj2816/aggbug/36923.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2007-11-19 10:25 <a href="http://www.cppblog.com/zjj2816/archive/2007/11/19/36923.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IBasicVideo::GetCurrentImage 抓图</title><link>http://www.cppblog.com/zjj2816/archive/2007/11/19/36918.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Mon, 19 Nov 2007 00:40:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2007/11/19/36918.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/36918.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2007/11/19/36918.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/36918.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/36918.html</trackback:ping><description><![CDATA[<a href="http://www.geekpage.jp/en/programming/directshow/getcurrentimage.php">http://www.geekpage.jp/en/programming/directshow/getcurrentimage.php</a><br><br>
<pre><code>#include &lt;stdio.h&gt;
#include &lt;dshow.h&gt;
// change here
#define	FILENAME L"C:\\DXSDK\\Samples\\Media\\butterfly.mpg"
// note that this sample fails on some environment
int
main()
{
IGraphBuilder *pGraphBuilder;
IMediaControl *pMediaControl;<strong>
IBasicVideo *pBasicVideo;</strong>
CoInitialize(NULL);
CoCreateInstance(CLSID_FilterGraph,
NULL,
CLSCTX_INPROC,
IID_IGraphBuilder,
(LPVOID *)&amp;pGraphBuilder);
pGraphBuilder-&gt;QueryInterface(IID_IMediaControl,
(LPVOID *)&amp;pMediaControl);
pMediaControl-&gt;RenderFile(FILENAME);
<strong>
pGraphBuilder-&gt;QueryInterface(IID_IBasicVideo,
(LPVOID *)&amp;pBasicVideo);
</strong>
pMediaControl-&gt;Run();
// The image will be saved when OK is clicked
MessageBox(NULL,
"Grab Image",
"Grab",
MB_OK);
<strong>
// Must Pause before using GetCurrentImage
pMediaControl-&gt;Pause();
// get width and height
long height, width;
pBasicVideo-&gt;get_VideoHeight(&amp;height);
pBasicVideo-&gt;get_VideoWidth(&amp;width);
long bufSize;
long *imgData;
HRESULT hr;
/*
The second value is NULL to resolve required buffer size.
The required buffer size will be returned in variable "bufSize".
*/
hr = pBasicVideo-&gt;GetCurrentImage(&amp;bufSize, NULL);
if (FAILED(hr)) {
printf("GetCurrentImage failed\n");
return 1;
}
if (bufSize &lt; 1) {
printf("failed to get data size\n");
return 1;
}
imgData = (long *)malloc(bufSize);
// The data will be in DIB format
pBasicVideo-&gt;GetCurrentImage(&amp;bufSize, imgData);
</strong>
// save DIB file as Bitmap.
// This sample saves image as bitmap to help
// understanding the sample.
HANDLE fh;
BITMAPFILEHEADER bmphdr;
BITMAPINFOHEADER bmpinfo;
DWORD nWritten;
memset(&amp;bmphdr, 0, sizeof(bmphdr));
memset(&amp;bmpinfo, 0, sizeof(bmpinfo));
bmphdr.bfType = ('M' &lt;&lt; 8) | 'B';
bmphdr.bfSize = sizeof(bmphdr) + sizeof(bmpinfo) + bufSize;
bmphdr.bfOffBits = sizeof(bmphdr) + sizeof(bmpinfo);
bmpinfo.biSize = sizeof(bmpinfo);
bmpinfo.biWidth = width;
bmpinfo.biHeight = height;
bmpinfo.biPlanes = 1;
bmpinfo.biBitCount = 32;
fh = CreateFile("result.bmp",
GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(fh, &amp;bmphdr, sizeof(bmphdr), &amp;nWritten, NULL);
WriteFile(fh, &amp;bmpinfo, sizeof(bmpinfo), &amp;nWritten, NULL);
WriteFile(fh, imgData, bufSize, &amp;nWritten, NULL);
CloseHandle(fh);
<strong>
free(imgData);
// Release resource
pBasicVideo-&gt;Release();
</strong>
pMediaControl-&gt;Release();
pGraphBuilder-&gt;Release();
CoUninitialize();
return 0;
}</code></pre>
<img src ="http://www.cppblog.com/zjj2816/aggbug/36918.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2007-11-19 08:40 <a href="http://www.cppblog.com/zjj2816/archive/2007/11/19/36918.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++类对象的拷贝构造函数分析</title><link>http://www.cppblog.com/zjj2816/archive/2006/12/01/15831.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Fri, 01 Dec 2006 00:52:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2006/12/01/15831.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/15831.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2006/12/01/15831.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/15831.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/15831.html</trackback:ping><description><![CDATA[对于普通类型的对象来说，它们之间的复制是很简单的，例如： <br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e7e9e9" border="1"><tbody><tr><td>int a=100;<br />int b=a;</td></tr></tbody></table><br />　　而类对象与普通对象不同，类对象内部结构一般较为复杂，存在各种成员变量。下面看一个类对象拷贝的简单例子。 <br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e7e9e9" border="1"><tbody><tr><td>#include &lt;iostream&gt;<br />using namespace std;<br />class CA<br />{<br />　public:<br />　　CA(int b)<br />　　{<br />　　　a=b;<br />　　}<br />　　void Show ()<br />　　{<br />　　　cout&lt;&lt;a&lt;&lt;endl;<br />　　}<br />　private:<br />　　int a;<br />};<br /><br />int main()<br />{<br />　CA A(100);<br />　CA B=A;<br />　B.Show ();<br />　return 0;<br />}</td></tr></tbody></table><br />　　运行<a class="bluekey" href="http://dev.yesky.com/" target="_blank">程序</a>，屏幕输出100。从以上代码的运行结果可以看出，系统为对象B分配了内存并完成了与对象A的复制过程。就类对象而言，相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。下面我们举例说明拷贝构造函数的工作过程。<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e7e9e9" border="1"><tbody><tr><td>#include &lt;iostream&gt;<br />using namespace std;<br />class CA<br />{<br />　public:<br />　　CA(int b)<br />　　{<br />　　　a=b;<br />　　}<br />　　CA(const CA&amp; C)<br />　　{<br />　　　a=C.a;<br />　　}<br />　　void Show()<br />　　{<br />　　　cout&lt;&lt;a&lt;&lt;endl;<br />　　}<br />　private:<br />　　int a;<br />};<br /><br />int main()<br />{<br />　CA A(100);<br />　CA B=A;<br />　B.Show ();<br />　return 0;<br />}</td></tr></tbody></table><br />　　CA(const CA&amp; C)就是我们自定义的拷贝构造函数。可见，拷贝构造函数是一种特殊的构造函数，函数的名称必须和类名称一致，它的唯一的一个参数是本类型的一个引用变量，该参数是const类型，不可变的。例如：类X的拷贝构造函数的形式为X(X&amp; x)。<br /><br />　　当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候，拷贝构造函数就会被自动调用。也就是说，当类的对象需要拷贝时，拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数：<br /><br />　　一个对象以值传递的方式传入函数体 <br /><br />　　一个对象以值传递的方式从函数返回 <br /><br />　　一个对象需要通过另外一个对象进行初始化。 <br /><br />　　如果在类中没有显式地声明一个拷贝构造函数，那么，编译器将会自动生成一个默认的拷贝构造函数，该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝，后面将进行说明。 <br /><br />　　自定义拷贝构造函数是一种良好的编程风格，它可以阻止编译器形成默认的拷贝构造函数，提高源码效率。<br /><br />　　<b>浅拷贝和深拷贝</b><br /><br />　　在某些状况下，类内成员变量需要动态开辟堆内存，如果实行位拷贝，也就是把对象里的值完全复制给另一个对象，如A=B。这时，如果B中有一个成员变量指针已经申请了内存，那A中的那个成员变量也指向同一块内存。这就出现了问题：当B把内存释放了（如：析构），这时A内的指针就是野指针了，出现运行错误。<br /><br />　　深拷贝和浅拷贝可以简单理解为：如果一个类拥有资源，当这个类的对象发生复制过程的时候，资源重新分配，这个过程就是深拷贝，反之，没有重新分配资源，就是浅拷贝。下面举个深拷贝的例子。 <br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e7e9e9" border="1"><tbody><tr><td>#include &lt;iostream&gt;<br />using namespace std;<br />class CA<br />{<br />　public:<br />　　CA(int b,char* cstr)<br />　　{<br />　　　a=b;<br />　　　str=new char[b];<br />　　　strcpy(str,cstr);<br />　　}<br />　　CA(const CA&amp; C)<br />　　{<br />　　　a=C.a;<br />　　　str=new char[a]; //深拷贝<br />　　　if(str!=0)<br />　　　　strcpy(str,C.str);<br />　　}<br />　　void Show()<br />　　{<br />　　　cout&lt;&lt;str&lt;&lt;endl;<br />　　}<br />　　~CA()<br />　　{<br />　　　delete str;<br />　　}<br />　private:<br />　　int a;<br />　　char *str;<br />};<br /><br />int main()<br />{<br />　CA A(10,"Hello!");<br />　CA B=A;<br />　B.Show();<br />　return 0;<br />}</td></tr></tbody></table><br />　　好吧，就说这些，希望本文能对您有所帮助。<img src ="http://www.cppblog.com/zjj2816/aggbug/15831.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2006-12-01 08:52 <a href="http://www.cppblog.com/zjj2816/archive/2006/12/01/15831.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>体验C++中接口与实现分离的技术</title><link>http://www.cppblog.com/zjj2816/archive/2006/07/05/9419.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Wed, 05 Jul 2006 01:59:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2006/07/05/9419.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/9419.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2006/07/05/9419.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/9419.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/9419.html</trackback:ping><description><![CDATA[在用C++写要导出类的库时，我们经常只想暴露接口，而隐藏类的实现细节。也就是说我们提供的头文件里只提供要暴露的公共成员函数的声明，类的其他所有信息都不会在这个头文件里面显示出来。这个时候就要用到接口与实现分离的技术。<br /><br />　　下面用一个最简单的例子来说明。<br /><br />　　类ClxExp是我们要导出的类，其中有一个私有成员变量是ClxTest类的对象，各个文件内容如下： <br /><br />　　lxTest.h文件内容：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>class ClxTest <br />{<br />　public:<br />　　ClxTest();<br />　　virtual ~ClxTest();<br />　　void DoSomething();<br />};</td></tr></tbody></table><br />　　lxTest.cpp文件内容：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>#include "lxTest.h"<br /><br />#include &lt;iostream&gt;<br />using namespace std;<br /><br />ClxTest::ClxTest()<br />{}<br /><br />ClxTest::~ClxTest()<br />{}<br /><br />void ClxTest::DoSomething()<br />{<br />　cout &lt;&lt; "Do something in class ClxTest!" &lt;&lt; endl;<br />}<br /><br />////////////////////////////////////////////////////////////////////////////</td></tr></tbody></table><br />　　lxExp.h文件内容：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>#include "lxTest.h"<br /><br />class ClxExp <br />{<br />　public:<br />　　ClxExp();<br />　　virtual ~ClxExp();<br />　　void DoSomething();<br />　private:<br />　　ClxTest m_lxTest;<br />　　void lxTest();<br />};</td></tr></tbody></table><br />　　lxExp.cpp文件内容：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>#include "lxExp.h"<br /><br />ClxExp::ClxExp()<br />{}<br /><br />ClxExp::~ClxExp()<br />{}<br /><br />// 其实该方法在这里并没有必要，我这样只是为了说明调用关系<br />void ClxExp::lxTest()<br />{<br />　m_lxTest.DoSomething(); <br />}<br /><br />void ClxExp::DoSomething()<br />{<br />　lxTest();<br />}</td></tr></tbody></table><br />　　为了让用户能使用我们的类ClxExp，我们必须提供lxExp.h文件，这样类ClxExp的私有成员也暴露给用户了。而且，仅仅提供lxExp.h文件是不够的，因为lxExp.h文件include了lxTest.h文件，在这种情况下，我们还要提供lxTest.h文件。那样ClxExp类的实现细节就全暴露给用户了。另外，当我们对类ClxTest做了修改（如添加或删除一些成员变量或方法）时，我们还要给用户更新lxTest.h文件，而这个文件是跟接口无关的。如果类ClxExp里面有很多像m_lxTest那样的对象的话，我们就要给用户提供N个像lxTest.h那样的头文件，而且其中任何一个类有改动，我们都要给用户更新头文件。还有一点就是用户在这种情况下必须进行重新编译！<br /><br />　　上面是非常小的一个例子，重新编译的时间可以忽略不计。但是，如果类ClxExp被用户大量使用的话，那么在一个大项目中，重新编译的时候我们就有时间可以去喝杯咖啡什么的了。当然上面的种种情况不是我们想看到的！你也可以想像一下用户在自己程序不用改动的情况下要不停的更新头文件和编译时，他们心里会骂些什么。其实对用户来说，他们只关心类ClxExp的接口DoSomething()方法。那我们怎么才能只暴露类ClxExp的DoSomething()方法而不又产生上面所说的那些问题呢？答案就是－－接口与实现的分离。我可以让类ClxExp定义接口，而把实现放在另外一个类里面。下面是具体的方法：<br /><br />　　首先，添加一个实现类ClxImplement来实现ClxExp的所有功能。注意：类ClxImplement有着跟类ClxExp一样的公有成员函数，因为他们的接口要完全一致。<br /><br />　　lxImplement.h文件内容：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>#include "lxTest.h"<br /><br />class ClxImplement <br />{<br />　public:<br />　　ClxImplement();<br />　　virtual ~ClxImplement();<br /><br />　　void DoSomething();<br />　<br />　private:<br />　　ClxTest m_lxTest;<br />　　void lxTest();<br />};</td></tr></tbody></table><br />　　lxImplement.cpp文件内容：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>#include "lxImplement.h"<br /><br />ClxImplement::ClxImplement()<br />{}<br /><br />ClxImplement::~ClxImplement()<br />{}<br /><br />void ClxImplement::lxTest()<br />{<br />　m_lxTest.DoSomething();<br />}<br /><br />void ClxImplement::DoSomething()<br />{<br />　lxTest();<br />}</td></tr></tbody></table><br />　　然后，修改类ClxExp。<br /><br />　　修改后的lxExp.h文件内容：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>// 前置声明<br />class ClxImplement;<br /><br />class ClxExp <br />{<br />　public:<br />　　ClxExp();<br />　　virtual ~ClxExp();<br />　　void DoSomething();<br />　private:<br />　　// 声明一个类ClxImplement的指针，不需要知道类ClxImplement的定义<br />　　ClxImplement *m_pImpl;<br />};</td></tr></tbody></table><br />　　修改后的lxExp.cpp文件内容：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>// 在这里包含类ClxImplement的定义头文件<br />#include "lxImplement.h"<br /><br />ClxExp::ClxExp()<br />{<br />　m_pImpl = new ClxImplement;<br />}<br /><br />ClxExp::~ClxExp()<br />{<br />　delete m_pImpl;<br />}<br /><br />void ClxExp::DoSomething()<br />{<br />　m_pImpl-&gt;DoSomething();<br />}</td></tr></tbody></table><br />　　通过上面的方法就实现了类ClxExp的接口与实现的分离。请注意两个文件中的注释。类ClxExp里面声明的只是接口而已，而真正的实现细节被隐藏到了类ClxImplement里面。为了能在类ClxExp中使用类ClxImplement而不include头文件lxImplement.h，就必须有前置声明class ClxImplement，而且只能使用指向类ClxImplement对象的指针，否则就不能通过编译。<br /><br />　　在发布库文件的时候，我们只需给用户提供一个头文件lxExp.h就行了，不会暴露类ClxExp的任何实现细节。而且我们对类ClxTest的任何改动，都不需要再给用户更新头文件（当然，库文件是要更新的，但是这种情况下用户也不用重新编译！）。这样做还有一个好处就是，可以在分析阶段由系统分析员或者高级程序员来先把类的接口定义好，甚至可以把接口代码写好（例如上面修改后的lxExp.h文件和lxExp.cpp文件），而把类的具体实现交给其他程序员开发。 <img src ="http://www.cppblog.com/zjj2816/aggbug/9419.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2006-07-05 09:59 <a href="http://www.cppblog.com/zjj2816/archive/2006/07/05/9419.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ Primer读书笔记</title><link>http://www.cppblog.com/zjj2816/archive/2006/06/29/9151.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Thu, 29 Jun 2006 07:11:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2006/06/29/9151.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/9151.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2006/06/29/9151.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/9151.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/9151.html</trackback:ping><description><![CDATA[前些日子开始看《C++ Primer》，顺便做一些笔记，既有书上的，也有自己理解的。<br />因为刚学C++不久，笔下难免有谬误之处，行文更是凌乱；<br />所幸不是用来显配的东西，发在linuxsir只是为了方便自己阅读记忆，以防只顾上网忘了正事。<br />书看了不到一半，所以大约才写了一半，慢慢补充。<br />=========================================<br /><br /><font color="brown"><br />==========================================<br />转载务必注明原作者<br />neplusultra 2005.2.3<br />==========================================<br /></font><br /><br /><font color="red">const要注意的问题</font><br />　　1、下面是一个几乎所有人刚开始都会搞错的问题：<br />已知：typedef char *cstring;<br />在以下声明中，cstr的类型是什么？<br />extern const cstring cstr;<br /><br />错误答案：const char *cstr;<br />正确答案：char *const cstr;<br /><br />　　错误在于将typedef当作宏扩展。const 修饰cstr的类型。cstr是一个指针，因此，这个定义声明了cstr是一个指向字符的const指针。<br />　　2、指针是const还是data为const？<br />辨别方法很简单，如下：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 82px"><div dir="ltr" style="TEXT-ALIGN: left">char *p="hello"; //non-const pointer, non-const data;
const char *p="hello"; // non-const pointer, const data;
char * const p="hello"; // const pointer , non-const data;
const char * const p="hello"; // const pointer, const data;</div></pre></div>　　要注意的是，"hello"的类型是const char * ，按C++standard规则，char *p="hello" 是非法的(右式的const char* 不能转换为左式的char *)，违反了常量性。但是这种行为在C中实在太频繁，因此C++standard对于这种初始化动作给予豁免。尽管如此，还是尽量避免这种用法。<br />　　3、const初始化的一些问题<br />const 对象必须被初始化：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 66px"><div dir="ltr" style="TEXT-ALIGN: left">const int *pi=new int; // 错误，没有初始化
const int *pi=new int(100); //正确
const int *pci=new const int[100]; //编译错误，无法初始化用new表达式创建的内置类型数组元素。</div></pre></div><br /><font color="red">什么时候需要copy constructor,copy assignment operator,destructor</font><br />　　注意，若class需要三者之一，那么它往往需要三者。<br />当class的copy constructor内分配有一块指向hcap的内存，需要由destructor释放，那么它也往往需要三者。<br /><br /><font color="red">为什么需要protected 访问级别</font><br />　　有人认为，protected访问级别允许派生类直接访问基类成员，这破坏了封装的概念，因此所有基类的实现细节都应该是private的；另外一些人认为，如果派生类不能直接访问基类的成员，那么派生类的实现将无法有足够的效率供用户使用，如果没有protected，类的设计者将被迫把基类成员设置为public。<br />　　事实上，protected正是在高纯度的封装与效率之间做出的一个良好折衷方案。<br /><br /><font color="red">为什么需要virtual member function又不能滥用virtual</font><br />　　若基类设计者把本应设计成virtual的成员函数设计成非virtual，则继承类将无法实现改写(overridden)，给继承类的实现带来不便；<br />　　另一方面，一旦成员函数被设计成virtual，则该类的对象将额外增加虚拟指针（vptr）和虚拟表格（vtbl），所以倘若出于方便继承类overridden的目的而使所有成员函数都为virtual，可能会影响效率，因为每个virtual成员函数都需付出动态分派的成本。而且virtual成员函数不能内联（inline），我们知道，内联发生在编译时刻，而虚拟函数在运行时刻才处理。对于那些小巧而被频繁调用、与类型无关的函数，显然不应该被设置成virtual。<br /><br /><font color="red">关于引用的一些注意点</font><br />　　1、把函数参数声明为数组的引用：当函数参数是一个数组类型的引用时，数组长度成为参数和实参类型的一部分，编译器检查数组实参的长度和与在函数参数类型中指定的长度是否匹配。<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 386px"><div dir="ltr" style="TEXT-ALIGN: left">//参数为10个int数组
void showarr(int (&amp;arr)[10]);
void func()
{
  int i,j[2],k[10];
  showarr(i); //错误！实参必须是10个int的数组
  showarr(j); //错误！实参必须是10个int的数组
  showarr(k); //正确！
}

//更灵活的实现，借助函数模板。下面是一个显示数组内容的函数。
template &lt;typename Type , int size&gt;
void printarr(const Type (&amp; r_array)[size])
{
	for(int i=0;i&lt;size;i++) std::cout&lt;&lt; r_array[i] &lt;&lt;' ';
	std::cout &lt;&lt; std::endl;
}

void caller()
{
   int ar[5]={1,2,5,3,4}; //数组可以任意大小。
   printarr(ar); //正确！自动正确调用printarr()
}</div></pre></div>　　2、<br />　　3、<br /><br /><font color="red">goto语句的一些要注意的地方</font><br />　　1、label语句只能用作goto的目标，且label语句只能用冒号结束，且label语句后面不能紧接右花括号'}'，如<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 34px"><div dir="ltr" style="TEXT-ALIGN: left">label8: }</div></pre></div>　　办法是在冒号后面加一个空语句（一个';'即可），如<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 34px"><div dir="ltr" style="TEXT-ALIGN: left">label7: ;} </div></pre></div>　　 2、goto语句不能向前跳过如下声明语句：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 98px"><div dir="ltr" style="TEXT-ALIGN: left">goto label6;
int x=1; //错误，不能跳过该声明！
cout&lt;&lt;x&lt;&lt;endl; //使用x
label6:
//其他语句</div></pre></div>但是，把int x=1; 改为int x; 则正确了。另外一种方法是：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 130px"><div dir="ltr" style="TEXT-ALIGN: left">goto label6;
{
  int x=1; //正确，使用了语句快
  cout&lt;&lt;x&lt;&lt;endl;
}
label6:
//其他语句</div></pre></div>　　3、goto语句可以向后（向程序开头的方向）跳过声明定义语句。<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 82px"><div dir="ltr" style="TEXT-ALIGN: left">begin:
int i=22;
cout&lt;&lt; i &lt;&lt;endl;
goto begin; //非常蹩脚，但它是正确的</div></pre></div><br /><font color="red">变量作用域</font><br />　　1、花括号可以用来指明局部作用域。<br />　　2、在for、if、switch、while语句的条件/循环条件中可以声明变量，该变量仅在相应语句块内有效。<br />　　3、extern为声明但不定义一个对象提供了一种方法；它类似于函数声明，指明该对象会在其他地方被定义：或者在此文本的其他地方，或者在程序的其他文本文件中。例如extern int i; 表示在其他地方存在声明 int i; <br />　　extern 声明不会引起内存分配，他可以在同一个文件或同一个程序中出现多次。因此在全局作用域中，以下语句是正确的：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 66px"><div dir="ltr" style="TEXT-ALIGN: left">extern int c;
int c=1;  //没错
extern int c; //没错</div></pre></div>　　但是，extern声明若指定了一个显式初始值的全局对象，将被视为对该对象的定义，编译器将为其分配存储区；对该对象的后续定义将出错。如下：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 50px"><div dir="ltr" style="TEXT-ALIGN: left">extern int i=1;
int i=2; //出错！重复定义</div></pre></div><br /><font color="red">auto_ptr若干注意点</font><br />　　1、auto_ptr的主要目的是支持普通指针类型相同的语法，并为auto_ptr所指对象的释放提供自动管理，而且auto_ptr的安全性几乎不会带来额外的代价（因为其操作支持都是内联的）。定义形式有三种：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 66px"><div dir="ltr" style="TEXT-ALIGN: left">auto_ptr&lt;type_pointed_to&gt;identifier(ptr_allocated_by_new);
auto_ptr&lt;type_pointed_to&gt;identifier(auto_ptr_of_same_type);
auto_ptr&lt;type_pointed_to&gt;identifier;</div></pre></div>　　2、所有权概念。auto_ptr_p1=auto_ptr_p2的后果是，auto_ptr_p2丧失了其原指向对象的所有权，并且auto_ptr_p2.get()==0。不要让两个auto_ptr对象拥有空闲存储区内同一对象的所有权。注意以下两种种初始化方式的区别：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 66px"><div dir="ltr" style="TEXT-ALIGN: left">auto_ptr&lt;string&gt;auto_ptr_str1(auto_ptr_str2.get()); //注意！用str2指针初始化str1, 两者同时拥有所有权，后果未定义。
auto_ptr&lt;string&gt;auto_ptr_str1(auto_ptr_str2.release());//OK！str2释放了所有权。
</div></pre></div><br />　　3、不能用一个指向“内存不是通过应用new表达式分配的”指针来初始化或者赋值auto_ptr。如果这样做了，delete表达式会被应用在不是动态分配的指针上，这将导致未定义的程序行为。<br /><font color="red"><br />C风格字符串结尾空字符问题</font><br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 50px"><div dir="ltr" style="TEXT-ALIGN: left">char *str="hello world!"; //str末尾自动加上一个结尾空字符，但strlen不计该空字符。
char *str2=new char[strlen(str)<font color="blue">+1</font>] // +1用来存放结尾空字符。</div></pre></div><br /><br /><font color="red">定位new表达式</font><br />　　头文件：&lt;new&gt;<br />　　形式：new (place_address) type-specifier<br />　　该语句可以允许程序员将对象创建在已经分配好的内存中，允许程序员预分配大量的内存供以后通过这种形式的new表达式创建对象。其中place_address必须是一个指针。例如：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 82px"><div dir="ltr" style="TEXT-ALIGN: left">char *buf=new char[sizeof(myclass-type)*16];
myclass-type *pb=new (buf) myclass-type; //使用预分配空间来创建对象
// ... 
delete [] buf;  // 无须 delete pb。</div></pre></div><br /><font color="red"><br />名字空间namespace<br /></font><br />　　1、namespace的定义可以是不连续的（即namespace的定义是可以积累的），即，同一个namespace可以在不同的文件中定义，分散在不同文件中的同一个namespace中的内容彼此可见。这对生成一个库很有帮助，可以使我们更容易将库的源代码组织成接口和实现部分。如：在头文件（.h文件）的名字空间部分定义库接口；在实现文件（如.c或.cpp文件）的名字空间部分定义库实现。名字空间定义可积累的特性是“向用户隐藏实现细节”必需的，它允许把不同的实现文件（如.c或.cpp文件）编译链接到一个程序中，而不会有编译错误和链接错误。<br />　　2、全局名字空间成员，可以用“::member_name”的方式引用。当全局名字空间的成员被嵌套的局部域中声明的名字隐藏时，就可以采用这种方法引用全局名字空间成员。<br />　　3、名字空间成员可以被定义在名字空间之外。但是，只有包围该成员声明的名字空间（也就是该成员声明所在的名字空间及其<font color="blue">外围名字空间</font>）才可以包含它的定义。<br />　　尤其要注意的是#include语句的次序。假定名字空间成员mynamespace::member_i的声明在文件dec.h中，且#include "dec.h"语句置于<font color="blue">全局</font>名字空间，那么在include语句之后定义的其他名字空间内，mynamespace::member_i的声明均可见。即，mynamespace::member_i可以在#include "dec.h"之后的任何地方任何名字空间内定义。<br />　　4、未命名的名字空间。我们可以用未命名的名字空间声明一个局部于某一文件的实体。未命名的名字空间可以namespace开头，其后不需名字，而用一对花括号包含名字空间声明块。如：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 274px"><div dir="ltr" style="TEXT-ALIGN: left">//　其他代码略
namespace
{
	void mesg()
	{
		cout&lt;&lt;"**********\n";
	}
}
int main()
{
	mesg();　//正确
	
　　　　//...

	return 0;
}</div></pre></div>　　由于未命名名字空间的成员是程序实体，所以mesg()可以在程序整个执行期间被调用。但是，未命名名字空间成员只在特定的文件中可见，在构成程序的其他文件中是不可以见的。未命名名字空间的成员与被声明为static的全局实体具有类似的特性。在Ｃ中，被声明为static的全局实体在声明它的文件之外是不可见的。<br /><br /><font color="red">using关键字</font><br />　　1、using声明与using指示符：前者是声明某名字空间内的一个成员，后者是使用整个名字空间。例如：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 50px"><div dir="ltr" style="TEXT-ALIGN: left">using cpp_primer::matrix; // ok,using声明
using <font color="blue">namespace</font> cpp_primer; //ok,using指示符</div></pre></div>　　2、 该using指示符语句可以加在程序文件的几乎任何地方，包括文件开头（#include语句之前）、函数内部。不过用using指定的名字空间作用域（生命周期）受using语句所在位置的生命周期约束。如，函数内部使用“using namespace myspacename;”则 myspacename仅在该函数内部可见。<br />　　3、可以用using语句指定多个名字空间，使得多个名字空间同时可见。但这增加了名字污染的可能性，而且只有在<font color="blue">使用</font>各名字空间相同成员时由多个using指示符引起的二义性错误才能被检测到，这将给程序的检测、扩展、移植带来很大的隐患。因此，因该尽量使用using声明而不是滥用using指示符。<br /><br /><font color="red">重载函数</font><br />　　1、如果两个函数的参数表中参数的个数或者类型不同，则认为这两个函数是重载的。<br />　　如果两个函数的返回类型和参数表精确匹配，则第二个声明被视为第一个的重复声明，与参数名无关。如 void print(string&amp; str)与void print(string&amp;)是一样的。<br />　　如果两个函数的参数表相同，但是返回类型不同，则第二个声明被视为第一个的错误重复声明，会标记为编译错误。<br />　　如果在两个函数的参数表中，只有缺省实参不同，则第二个声明被视为第一个的重复声明。如int max(int *ia,int sz)与int max(int *, int=10)。<br />　　参数名类型如果是由typedef提供的，并不算作新类型，而应该当作typedef的原类型。<br />　　当参数类型是const或者volatile时，分两种情况：对于实参按值传递时，const、volatile修饰符可以忽略；对于把const、volatile应用在指针或者引用参数指向的类型时，const、volatile修饰符对于重载函数的声明是有作用的。例如：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 258px"><div dir="ltr" style="TEXT-ALIGN: left">//OK,以下两个声明其实一样
void func(int i);
void func(const int i);

//Error,无法通过编译，因为func函数被定义了两次。
void func(int i){}
void func(const int i){}

//OK,声明了不同的函数
void func2(int *);
void func2(const int *);

//OK,声明了不同的函数
void func3(int&amp;);
void func3(const int&amp;);</div></pre></div>　　2、链接指示符extern "C"只能指定重载函数集中的一个函数。原因与内部名编码有关，在大多数编译器内部，每个函数明及其相关参数表都被作为一个惟一的内部名编码，一般的做法是把参数的个数和类型都进行编码，然后将其附在函数名后面。但是这种编码不使用于用链接指示符extern "C"声明的函数，这就是为什么在重载函数集合中只有一个函数可以被声明为extern "C"的原因，具有不同的参数表的两个extern "C"的函数会被链接编辑器视为同一函数。例如，包含以下两个声明的程序是非法的。<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 66px"><div dir="ltr" style="TEXT-ALIGN: left">//error:一个重载函数集中有两个extern "C"函数
extern "C" void print(const char*);
extern "C" void print(int);</div></pre></div><br /><font color="red">函数模板</font><br />　　1、定义函数模板：<br /><div style="MARGIN: 5px 20px 20px 0px"><div class="smallfont" style="MARGIN-BOTTOM: 2px">代码:</div><pre class="alt2" style="BORDER-RIGHT: #c6c6c6 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: #c6c6c6 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: #c6c6c6 1px solid; WIDTH: 640px; PADDING-TOP: 4px; BORDER-BOTTOM: #c6c6c6 1px solid; HEIGHT: 114px"><div dir="ltr" style="TEXT-ALIGN: left">template &lt;typename/class identifier, ...&gt; 
[inline/extern] 
ReturnType FunctionName(FuncParameters...)
{
　　//definition of a funciton template...
}</div></pre></div><img src ="http://www.cppblog.com/zjj2816/aggbug/9151.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2006-06-29 15:11 <a href="http://www.cppblog.com/zjj2816/archive/2006/06/29/9151.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>划分全局名字空间</title><link>http://www.cppblog.com/zjj2816/archive/2006/06/29/9150.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Thu, 29 Jun 2006 07:09:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2006/06/29/9150.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/9150.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2006/06/29/9150.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/9150.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/9150.html</trackback:ping><description><![CDATA[
		<script language="JavaScript">
				<!--

function fullSize(sURL){
	window.open(sURL,'scrshot','width=500,height=375,top=20,left=20,directories=no , Toolbar = no, resizable = yes, menubar = no, ScrollBars = yes ');
}

function LibraryHeaderNav(sBackward, sForward, sImgLeftOff, sImgLeftOn, sImgRightOff, sImgRightOn, iH, iW, sImgLeftStyle, sImgRightStyle, sImgRuleStyle, sRuleColor, sRuleSize){
	var tableStr;
	//validate questionable args for defs
	tableStr = "<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 border=0 width=100%>";
	tableStr += "<TR VALIGN=top ALIGN=right>";

	tableStr += "<TD align=right class=" + sImgRuleStyle + ">&nbsp;</TD>";	
	
	tableStr += "<TD width=34 align=right class=" + sImgLeftStyle + ">";
	tableStr += "<A href='" + sBackward + "'>";
	tableStr += "<IMG HEIGHT=" + iH + " WIDTH=" + iW + " BORDER=0";
	tableStr += ' OnMouseOver=\"this.src=\'' + sImgLeftOn + '\'\"';
	tableStr += ' OnMouseOut=\"this.src=\'' + sImgLeftOff + '\'\"';
	tableStr += " SRC='" + sImgLeftOff + "' vspace=0 hspace=0></a></TD>";
	
	tableStr += "<TD width=34 align=left class=" + sImgRightStyle + ">";
	tableStr += "<A href='" + sForward + "'>";
	tableStr += "<IMG HEIGHT=" + iH + " WIDTH=" + iW + " BORDER=0";
	tableStr += ' OnMouseOver=\"this.src=\'' + sImgRightOn + '\'\"';
	tableStr += ' OnMouseOut=\"this.src=\'' + sImgRightOff + '\'\"';
	tableStr += " SRC='" + sImgRightOff + "' vspace=0 hspace=0></a></TD></TR>";

	tableStr += "<TR VALIGN=top>";
	tableStr += "<TD height=3 align=center colspan=3 class=" + sImgRuleStyle + ">";
	tableStr += "<HR color=" + sRuleColor + " size=" + sRuleSize + "></TD></TR></TABLE>";
	//alert(tableStr);
	document.write(tableStr);
}

 																						     //purple is: #aa22aa   orange is: #ff9900
LibraryHeaderNav("ch07b.htm", "ch08a.htm", "images/unit_o_a1.gif", "images/unit_o_a2.gif", "images/unit_o_b1.gif", "images/unit_o_b2.gif", 18, 34, "unit01", "unit02", "headerrule", "#ff9900", "2");
//-->
		</script>
 
<table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr valign="top" align="right"><td class="headerrule" align="right"> </td><td class="unit01" align="right" width="34"><a href="http://www.leftworld.net/online/effectivec/file/ch07b.htm"><img onmouseover="this.src='images/unit_o_a2.gif'" onmouseout="this.src='images/unit_o_a1.gif'" height="18" hspace="0" src="http://www.leftworld.net/online/effectivec/file/images/unit_o_a1.gif" width="34" border="0" /></a></td><td class="unit02" align="left" width="34"><a href="http://www.leftworld.net/online/effectivec/file/ch08a.htm"><img onmouseover="this.src='images/unit_o_b2.gif'" onmouseout="this.src='images/unit_o_b1.gif'" height="18" hspace="0" src="http://www.leftworld.net/online/effectivec/file/images/unit_o_b1.gif" width="34" border="0" /></a></td></tr><tr valign="top"><td class="headerrule" align="middle" colspan="3" height="3"><hr color="#ff9900" size="2" /></td></tr></tbody></table><p></p><h2>条款28: 划分全局名字空间</h2><p></p><p>全局空间最大的问题在于它本身仅有一个。在大的软件项目中，经常会有不少人把他们定义的名字都放在这个单一的空间中，从而不可避免地导致名字冲突。例如，假设library1.h定义了一些常量，其中包括：</p><p>const double lib_version = 1.204;</p><p>类似的，library2.h也定义了：</p><p>const int lib_version = 3;</p><p>很显然，如果某个程序想同时包含library1.h和library2.h就会有问题。对于这类问题，你除了嘴里骂几句，或给作者发报复性邮件，或自己编辑头文件来消除名字冲突外，也没其它什么办法。</p><p>但是，作为程序员，你可以尽力使自己写的程序库不给别人带来这些问题。例如，可以预先想一些不大可能造成冲突的某种前缀，加在每个全局符号前。当然得承认，这样组合起来的标识符看起来不是那么令人舒服。</p><p>另一个比较好的方法是使用c++ namespace。namespace本质上和使用前缀的方法一样，只不过避免了别人总是看到前缀而已。所以，不要这么做：</p><p>const double sdmbook_version = 2.0;      // 在这个程序库中,<br />                                         // 每个符号以"sdm"开头<br />class sdmhandle { ... };                 </p><p>sdmhandle&amp; sdmgethandle();             // 为什么函数要这样声明？<br />                                       // 参见条款47</p><p>而要这么做：</p><p>namespace sdm {<br />  const double book_version = 2.0;<br />  class handle { ... };<br />  handle&amp; gethandle();<br />}</p><p>用户于是可以通过三种方法来访问这一名字空间里的符号：将名字空间中的所有符号全部引入到某一用户空间；将部分符号引入到某一用户空间；或通过修饰符显式地一次性使用某个符号：</p><p>void f1()<br />{<br />  using namespace sdm;           // 使得sdm中的所有符号不用加<br />                                 // 修饰符就可以使用</p><p>  cout &lt;&lt; book_version;          // 解释为sdm::book_version<br />  ...</p><p>  handle h = gethandle();        // handle解释为sdm::handle,<br />                                 // gethandle解释为sdm::gethandle<br />  ...                            </p><p>}</p><p>void f2()<br />{<br />  using sdm::book_version;        // 使得仅book_version不用加<br />                                 // 修饰符就可以使用</p><p>  cout &lt;&lt; book_version;           // 解释为<br />                                  // sdm::book_version<br />  ...</p><p>  handle h = gethandle();         // 错误! handle和gethandle<br />                                  // 都没有引入到本空间<br />  ...                             </p><p>}</p><p>void f3()<br />{<br />  cout &lt;&lt; sdm::book_version;      // 使得book_version<br />                                  // 在本语句有效<br />  ...                             </p><p>  double d = book_version;        // 错误! book_version<br />                                  // 不在本空间</p><p>  handle h = gethandle();         // 错误! handle和gethandle<br />                                  // 都没有引入到本空间<br />  ...                            </p><p>}</p><p>（有些名字空间没有名字。这种没命名的名字空间一般用于限制名字空间内部元素的可见性。详见条款m31。）</p><p>名字空间带来的最大的好处之一在于：潜在的二义不会造成错误（参见条款26）。所以，从多个不同的名字空间引入同一个符号名不会造成冲突（假如确实真的从不使用这个符号的话）。例如，除了名字空间sdm外，假如还要用到下面这个名字空间：</p><p>namespace acmewindowsystem {</p><p>  ...</p><p>  typedef int handle;</p><p>  ...</p><p>}</p><p>只要不引用符号handle，使用sdm和acmewindowsystem时就不会有冲突。假如真的要引用，可以明确地指明是哪个名字空间的handle：</p><p>void f()<br />{<br />  using namespace sdm;                 // 引入sdm里的所有符号<br />  using namespace acmewindowsystem;    // 引入acme里的所有符号</p><p>  ...                                  // 自由地引用sdm<br />                                       // 和acme里除handle之外<br />                                       // 的其它符号</p><p>  handle h;                            // 错误! 哪个handle?</p><p>  sdm::handle h1;                      // 正确, 没有二义</p><p>  acmewindowsystem::handle h2;         // 也没有二义</p><p>  ...</p><p>}</p><p>假如用常规的基于头文件的方法来做，只是简单地包含sdm.h和acme.h，这样的话，由于handle有多个定义，编译将不能通过。</p><p>名字空间的概念加入到c++标准的时间相对较晚，所以有些人会认为它不太重要，可有可无。但这种想法是错误的，因为c++标准库（参见条款49）里几乎所有的东西都存在于名字空间std之中。这可能令你不以为然，但它却以一种直接的方式影响到你：这就是为什么c++提供了那些看起来很有趣的、没有扩展名的头文件，如&lt;iostream&gt;, &lt;string&gt;等。详细介绍参见条款49。</p><p>由于名字空间的概念引入的时间相对较晚，有些编译器可能不支持。就算是这样，那也没理由污染全局名字空间，因为可以用struct来近似实现namespace。可以这样做：先创建一个结构用以保存全局符号名，然后将这些全局符号名作为静态成员放入结构中：</p><p>// 用于模拟名字空间的一个结构的定义<br />struct sdm {<br />  static const double book_version;<br />  class handle { ... };<br />  static handle&amp; gethandle();<br />};</p><p>const double sdm::book_version = 2.0;      // 静态成员的定义</p><p>现在，如果有人想访问这些全局符号名，只用简单地在它们前面加上结构名作为前缀：</p><p>void f()<br />{<br />  cout &lt;&lt; sdm::book_version;</p><p>  ...</p><p>  sdm::handle h = sdm::gethandle();</p><p>  ...<br />}</p><p>但是，如果全局范围内实际上没有名字冲突，用户就会觉得加修饰符麻烦而多余。幸运的是，还是有办法来让用户选择使用它们或忽略它们。</p><p>对于类型名，可以用类型定义（typedef）来显式地去掉空间引用。例如，假设结构s（模拟的名字空间）内有个类型名t，可以这样用typedef来使得t成为s::t的同义词：</p><p>typedef sdm::handle handle;</p><p>对于结构中的每个（静态）对象x，可以提供一个（全局）引用x，并初始化为s::x：</p><p>const double&amp; book_version = sdm::book_version;</p><p>老实说，如果读了条款47，你就会不喜欢定义一个象book_version这样的非局部静态对象。（你就会用条款47中所介绍的函数来取代这样的对象）</p><p>处理函数的方法和处理对象一样，但要注意，即使定义函数的引用是合法的，但代码的维护者会更喜欢你使用函数指针：</p><p>sdm::handle&amp; (* const gethandle)() =      // gethandle是指向sdm::gethandle<br />  sdm::gethandle;                         // 的const 指针 (见条款21)</p><p>注意gethandle是一个常指针。因为你当然不想让你的用户将它指向别的什么东西，而不是sdm::gethandle，对不对？</p><p>（如果真想知道怎么定义一个函数的引用，看看下面：</p><p>sdm::handle&amp; (&amp;gethandle)() =      // gethandle是指向<br />  sdm::gethandle;                  // sdm::gethandle的引用</p><p>我个人认为这样的做法也很好，但你可能以前从没见到过。除了初始化的方式外，函数的引用和函数的常指针在行为上完全相同，只是函数指针更易于理解。）</p><p>有了上面的类型定义和引用，那些不会遭遇全局名字冲突的用户就会使用没有修饰符的类型和对象名；相反，那些有全局名字冲突的用户就会忽略类型和引用的定义，代之以带修饰符的符号名。还要注意的是，不是所有用户都想使用这种简写名，所以要把类型定义和引用放在一个单独的头文件中，不要把它和（模拟namespace的）结构的定义混在一起。</p><p>struct是namespace的很好的近似，但实际上还是相差很远。它在很多方面很欠缺，其中很明显的一点是对运算符的处理。如果运算符被定义为结构的静态成员，它就只能通过函数调用来使用，而不能象常规的运算符所设计的那样，可以通过自然的中缀语法来使用：</p><p>// 定义一个模拟名字空间的结构，结构内部包含widgets的类型<br />// 和函数。widgets对象支持operator+进行加法运算<br />struct widgets {<br />  class widget { ... };</p><p><br />  // 参见条款21：为什么返回const<br />  static const widget operator+(const widget&amp; lhs,<br />                                const widget&amp; rhs);</p><p>  ...</p><p>};</p><p>// 为上面所述的widge和operator+ <br />// 建立全局（无修饰符的）名称</p><p>typedef widgets::widget widget;</p><p><br />const widget (* const operator+)(const widget&amp;,        // 错误!<br />                                 const widget&amp;);       // operator+不能是指针名<br /> </p><p>widget w1, w2, sum;</p><p>sum = w1 + w2;                           // 错误! 本空间没有声明<br />                                         // 参数为widgets 的operator+</p><p>sum = widgets::operator+(w1, w2);        // 合法, 但不是<br />                                         // "自然"的语法</p><p>正因为这些限制，所以一旦编译器支持，就要尽早使用真正的名字空间。</p><img height="0" src="http://www.leftworld.net/shequ/sta.cgi?a=6" width="0" /><script><![CDATA[ar style='null';var url='http://www.leftworld.net/stat';]]&gt;</script><script src="http://www.leftworld.net/stat/stat.js"></script><script language="javascript" src="http://www.leftworld.net/stat/stat.php?user=&amp;style=null&amp;referer=http%3A//www.google.cn/search%3Fhl%3Dzh-CN%26newwindow%3D1%26q%3Dc%252B%252B+namespace%26meta%3Dlr%253Dlang_zh-CN"></script><img src ="http://www.cppblog.com/zjj2816/aggbug/9150.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2006-06-29 15:09 <a href="http://www.cppblog.com/zjj2816/archive/2006/06/29/9150.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>