﻿<?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/colys/category/3604.html</link><description>LIFE AS CODE</description><language>zh-cn</language><lastBuildDate>Tue, 20 May 2008 19:07:25 GMT</lastBuildDate><pubDate>Tue, 20 May 2008 19:07:25 GMT</pubDate><ttl>60</ttl><item><title>插花问题的“动态规划法”算法[转]</title><link>http://www.cppblog.com/colys/articles/33753.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Mon, 08 Oct 2007 05:40:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/33753.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/33753.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/33753.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/33753.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/33753.html</trackback:ping><description><![CDATA[// Layout.cpp : Defines the entry point for the console application.<br>/*<br>&nbsp;作者：成晓旭<br>&nbsp;时间：2001年10月11日(11:35:38-12:35:00)<br>&nbsp;内容：完成插花问题的&#8220;动态规划法&#8221;算法及注解<br>*/<br>#include "stdafx.h"<br>#include "string.h"<br>#define MAX(A,B) ((A) &gt; (B) ? (A):(B))<br>//--------------------鲜花问题--------------------<br>#define F 100<br>#define V 100<br>/*<br>&nbsp;插花问题描述:<br>&nbsp;&nbsp;&nbsp;将f束鲜花插入v个花瓶中,使达到最徍的视觉效果,<br>&nbsp;&nbsp;问题相关约定及插花要求:<br>&nbsp;&nbsp;&nbsp;鲜花被编号为1--f,花瓶被编号为1--v,花瓶按从小到<br>&nbsp;&nbsp;大顺序排列,一只花瓶只能插一支花,鲜花i插入花瓶j中的<br>&nbsp;&nbsp;视觉效果效果值已知,编号小的鲜花所放入的花瓶编号也小&nbsp;<br>&nbsp;问题求解思路:<br>&nbsp;&nbsp;&nbsp;花瓶j(1&lt;=j&lt;=v)中插入鲜花的可能编号为[1..j](编号<br>&nbsp;&nbsp;小的鲜花所放入的花瓶编号也小);<br>&nbsp;&nbsp;&nbsp;设数组p[i][j]表示鲜花i插入花瓶j的好看程度,数组<br>&nbsp;&nbsp;q[i][j]表示[1..i]束鲜花插入[1..j]个花瓶所能得到的最大<br>&nbsp;&nbsp;好看程度,初始化q[0][0] = 0;q[0][j]=0(1&lt;=j&lt;=v),则q[f][v]<br>&nbsp;&nbsp;是问题的解.<br>&nbsp;&nbsp;&nbsp;特别地,j束鲜花插入到前面的j只花瓶中,所得到的好看<br>&nbsp;&nbsp;程度是q[j][j] = p[1][1]+p[2][2]+...+[j][j].现将插花过<br>&nbsp;&nbsp;程按花瓶排列顺序划分成不同阶段,则在第j阶段,第i束鲜花<br>&nbsp;&nbsp;若放入第j号花瓶,最大好看程度是q[i-1][j-1]+p[i][j];第i束鲜<br>&nbsp;&nbsp;花若放入前j-1个花瓶中的某一个,所得的好看程度是q[i][j-1],<br>&nbsp;&nbsp;那么在第j阶段,插入第i束鲜花所能得到的最大好看程度为:<br>&nbsp;&nbsp;q[i][j] = MAX(q[i-1][j-1]+p[i][j],q[i][j-1]),要使q[i][j]<br>&nbsp;&nbsp;最大,应使q[i-1][j-1]和q[i][j-1]也最大<br>*/<br>//初始化函数<br>void Initialize(int *f,int *v,int p[][V])<br>{<br>&nbsp;int i,j;<br>&nbsp;printf("输入鲜花数量及花瓶个数:");<br>&nbsp;scanf("%d%d",f,v);<br>&nbsp;printf("顺序输入各鲜花插入各花瓶的好看程度:\n");<br>&nbsp;for(i=1;i&lt;=*f;i++)<br>&nbsp;&nbsp;for(j=1;j&lt;=*v;j++)<br>&nbsp;&nbsp;&nbsp;p[i][j] = i+j;<br>&nbsp;&nbsp;&nbsp;//scanf("%d",&amp;p[i][j]);<br>}<br>//鲜花问题处理函数<br>int Sove(int p[][V],int f,int v,int *way)<br>{<br>&nbsp;int i,j,newv,q[F][V];<br>&nbsp;q[0][0] = 0;<br>&nbsp;/*设置v个花瓶分别被插入v束鲜花时各号花瓶对应的(初始)最大好看程度*/<br>&nbsp;for(j=1;j&lt;=v;j++)<br>&nbsp;{<br>&nbsp;&nbsp;q[0][j] = 0;<br>&nbsp;&nbsp;/*设置第j束鲜花放入第j号花瓶中的最大好看程度*/<br>&nbsp;&nbsp;q[j][j] = q[j-1][j-1]+p[j][j];<br>&nbsp;}<br>&nbsp;for(j=1;j&lt;=v;j++)<br>&nbsp;&nbsp;for(i=1;i&lt;j;i++)<br>&nbsp;&nbsp;&nbsp;q[i][j] = MAX(q[i-1][j-1]+p[i][j],q[i][j-1]);<br>&nbsp;newv = v;<br>&nbsp;for(i=f;i&gt;0;i--)<br>&nbsp;{<br>&nbsp;&nbsp;while(q[i-1][newv-1]+p[i][newv] &lt; q[i][newv])<br>&nbsp;&nbsp;&nbsp;newv--;<br>&nbsp;&nbsp;//确定鲜花i插在花瓶newv中,并准备考虑前一只花瓶　<br>&nbsp;&nbsp;way[i] = newv--;<br>&nbsp;}<br>&nbsp;return(q[f][v]);<br>}<br>//--------------------鲜花问题--------------------<br>//--------------------最长子串问题--------------------<br>#define N 100<br>char a[N],b[N],str[N];<br>//计算两个序列最长公共子序列的长度<br>int Get_LongSubStr_Len(char *a,char *b,int c[][N])<br>{<br>&nbsp;int m=strlen(a),n=strlen(b),//两个序列的长度<br>&nbsp;&nbsp;i,j;//循环变量<br>&nbsp;for(i=0;i&lt;=m;i++)&nbsp;c[i][0] = 0;<br>&nbsp;for(i=1;i&lt;=n;i++)&nbsp;c[0][i] = 0;<br>&nbsp;for(i=1;i&lt;=m;i++)<br>&nbsp;&nbsp;for(j=1;j&lt;=n;j++)<br>&nbsp;&nbsp;&nbsp;if(a[i-1]==b[j-1])<br>&nbsp;&nbsp;&nbsp;&nbsp;c[i][j] = c[i-1][j-1]+1;<br>&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;c[i][j] = MAX(c[i-1][j],c[i][j-1]);<br>&nbsp;&nbsp;&nbsp;/*<br>&nbsp;&nbsp;&nbsp;&nbsp;if(c[i-1][j]&gt;=c[i][j-1])<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i][j] = c[i-1][j];<br>&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i][j] = c[i][j-1];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br>&nbsp;return(c[m][n]);<br>}<br>//构造最长公共子序列<br>char *Build_LongSubStr(char s[],char *a,char *b)<br>{<br>&nbsp;int i=strlen(a),j=strlen(b),<br>&nbsp;&nbsp;k,c[N][N];<br>&nbsp;k = Get_LongSubStr_Len(a,b,c);<br>&nbsp;s[k] = '\0';<br>&nbsp;while(k&gt;0)<br>&nbsp;{<br>&nbsp;&nbsp;if(c[i][j]==c[i-1][j])<br>&nbsp;&nbsp;&nbsp;i--;<br>&nbsp;&nbsp;else<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;if(c[i][j]==c[i][j-1])<br>&nbsp;&nbsp;&nbsp;&nbsp;j--;<br>&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;s[--k]=a[i-1];<br>&nbsp;&nbsp;&nbsp;&nbsp;i--;<br>&nbsp;&nbsp;&nbsp;&nbsp;j--;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>&nbsp;}<br>&nbsp;return(s);<br>}<br>//--------------------最长子串问题--------------------<br>int main(int argc, char* argv[])<br>{<br>&nbsp;int i,f,v,p[F][V],way[F];<br>&nbsp;//-----------------------------------<br>&nbsp;/*<br>&nbsp;Initialize(&amp;f,&amp;v,p);<br>&nbsp;printf("最大好看程度为%d\n",Sove(p,f,v,way));<br>&nbsp;printf("插有鲜花的花瓶是:\n");<br>&nbsp;for(i=1;i&lt;=f;i++)<br>&nbsp;&nbsp;printf("%4d",way[i]);<br>&nbsp;*/<br>&nbsp;//-----------------------------------<br>&nbsp;printf("输入两个字符串(长度&lt;%d):\n",N);<br>&nbsp;scanf("%s%s",a,b);<br>&nbsp;printf("两个串的最长公共子序列是:%s\n",Build_LongSubStr(str,a,b));<br>&nbsp;//-----------------------------------<br>&nbsp;printf("\n\n应用程序正在运行......\n");<br>&nbsp;return 0;<br>}
<br><img src ="http://www.cppblog.com/colys/aggbug/33753.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-10-08 13:40 <a href="http://www.cppblog.com/colys/articles/33753.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]ini文件纯C++读写代码</title><link>http://www.cppblog.com/colys/articles/28387.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Thu, 19 Jul 2007 14:21:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/28387.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/28387.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/28387.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/28387.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/28387.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: //////////////////////////////////////////////////////////////////&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n...&nbsp;&nbsp;<a href='http://www.cppblog.com/colys/articles/28387.html'>阅读全文</a><img src ="http://www.cppblog.com/colys/aggbug/28387.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-07-19 22:21 <a href="http://www.cppblog.com/colys/articles/28387.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>成员函数指针与高性能的C++委托(下)</title><link>http://www.cppblog.com/colys/articles/25793.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Thu, 07 Jun 2007 16:18:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/25793.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/25793.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/25793.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/25793.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/25793.html</trackback:ping><description><![CDATA[委托（delegate）<br>　　<br>　　和成员函数指针不同，你不难发现委托的用处。最重要的，使用委托可以很容易地实现一个 Subject/Observer设计模式的改进版[GoF, p. 293]。Observer（观察者）模式显然在GUI中有很多的应用，但我发现它对应用程序核心的设计也有很大的作用。委托也可用来实现策略（Strategy）[GoF, p. 315]和状态（State）[GoF, p. 305]模式。<br>　　<br>　　现在，我来说明一个事实，委托和成员函数指针相比并不仅仅是好用，而且比成员函数指针简单得多！既然所有的.NET语言都实现了委托，你可能会猜想如此高层的概念在汇编代码中并不好实现。但事实并不是这样：委托的实现确实是一个底层的概念，而且就像普通的函数调用一样简单（并且很高效）。一个C++委托只需要包含一个this 指针和一个简单的函数指针就够了。当你建立一个委托时，你提供这个委托一个this指针，并向它指明需要调用哪一个函数。编译器可以在建立委托时计算出调整this指针需要的偏移量。这样在使用委托的时候，编译器就什么事情都不用做了。这一点更好的是，编译器可以在编译时就可以完成全部这些工作，这样的话，委托的处理对编译器来说可以说是微不足道的工作了。在x86系统下将委托处理成的汇编代码就应该是这么简单：<br>　　<br>　　mov ecx, [this]<br>　　<br>　　call [pfunc]<br>　　<br>　　但是，在标准C++中却不能生成如此高效的代码。 Borland为了解决委托的问题在它的C++编译器中加入了一个新的关键字（__closure）,用来通过简洁的语法生成优化的代码。GNU编译器也对语言进行了扩展，但和Borland的编译器不兼容。如果你使用了这两种语言扩展中的一种，你就会限制自己只使用一个厂家的编译器。而如果你仍然遵循标准C++的规则，你仍然可以实现委托，但实现的委托就不会是那么高效了。<br>　　<br>　　有趣的是，在C#和其他.NET语言中，执行一个委托的时间要比一个函数调用慢8倍（参见http://msdn.microsoft.com/library/en- us/dndotnet/html/fastmanagedcode.asp）。我猜测这可能是垃圾收集和.NET安全检查的需要。最近，微软将&#8220;统一事件模型（unified event model）&#8221;加入到Visual C++中，随着这个模型的加入，增加了__event、 __raise、__hook、__unhook、event_source和event_receiver等一些关键字。坦白地说，我对加入的这些特性很反感，因为这是完全不符合标准的，这些语法是丑陋的，因为它们使这种C++不像C++，并且会生成一堆执行效率极低的代码。<br>　　<br>　　解决这个问题的推动力：对高效委托（fast delegate）的迫切需求<br>　　<br>　　使用标准C++实现委托有一个过度臃肿的症状。大多数的实现方法使用的是同一种思路。这些方法的基本观点是将成员函数指针看成委托��但这样的指针只能被一个单独的类使用。为了避免这种局限，你需要间接地使用另一种思路：你可以使用模版为每一个类建立一个&#8220;成员函数调用器（member function invoker）&#8221;。委托包含了this指针和一个指向调用器（invoker）的指针，并且需要在堆上为成员函数调用器分配空间。<br>　　<br>　　对于这种方案已经有很多种实现，包括在CodeProject上的实现方案。各种实现在复杂性上、语法（比如，有的和C#的语法很接近）上、一般性上有所不同。最具权威的一个实现是boost::function。最近，它已经被采用作为下一个发布的C++标准版本中的一部分[Sutter1]。希望它能够被广泛地使用。<br>　　<br>　　就像传统的委托实现方法一样，我同样发觉这种方法并不十分另人满意。虽然它提供了大家所期望的功能，但是会混淆一个潜在的问题：人们缺乏对一个语言的底层的构造。 &#8220;成员函数调用器&#8221;的代码对几乎所有的类都是一样的，在所有平台上都出现这种情况是令人沮丧的。毕竟，堆被用上了。但在一些应用场合下，这种新的方法仍然无法被接受。<br>　　<br>　　我做的一个项目是离散事件模拟器，它的核心是一个事件调度程序，用来调用被模拟的对象的成员函数。大多数成员函数非常简单：它们只改变对象的内部状态，有时在事件队列（event queue）中添加将来要发生的事件，在这种情况下最适合使用委托。但是，每一个委托只被调用（invoked）一次。一开始，我使用了boost:: function，但我发现程序运行时，给委托所分配的内存空间占用了整个程序空间的三分之一还要多！&#8220;我要真正的委托！&#8221;我在内心呼喊着，&#8220;真正的委托只需要仅仅两行汇编指令啊！&#8221;<br>　　<br>　　我并不能总是能够得到我想要的，但后来我很幸运。我在这儿展示的代码（代码下载链接见译者注）几乎在所有编译环境中都产生了优化的汇编代码。最重要的是，调用一个含有单个目标的委托（single-target delegate）的速度几乎同调用一个普通函数一样快。实现这样的代码并没有用到什么高深的东西，唯一的遗憾就是，为了实现目标，我的代码和标准C++ 的规则有些偏离。我使用了一些有关成员函数指针的未公开知识才使它能够这样工作。如果你很细心，而且不在意在少数情况下的一些编译器相关（compiler-specific）的代码，那么高性能的委托机制在任何C++编译器下都是可行的。<br>　　<br>　　诀窍：将任何类型的成员函数指针转化为一个标准的形式<br>　　<br>　　我的代码的核心是一个能够将任何类的指针和任何成员函数指针分别转换为一个通用类的指针和一个通用成员函数的指针的类。由于C++没有&#8220;通用成员函数（geneic member function）&#8221;的类型，所以我把所有类型的成员函数都转化为一个在代码中未定义的CGenericClass类的成员函数。<br>　　<br>　　大多数编译器对所有的成员函数指针平等地对待，不管他们属于哪个类。所以对这些编译器来说，可以使用reinterpret_cast将一个特定的成员函数指针转化为一个通用成员函数指针。事实上，假如编译器不可以，那么这个编译器是不符合标准的。对于一些接近标准（almost-compliant）的编译器，比如Digital Mars，成员函数指针的reinterpret_cast转换一般会涉及到一些额外的特殊代码，当进行转化的成员函数的类之间没有任何关联时，编译器会出错。对这些编译器，我们使用一个名为horrible_cast的内联函数（在函数中使用了一个union来避免C++的类型检查）。使用这种方法看来是不可避免的��boost::function也用到了这种方法。<br>　　<br>　　对于其他的一些编译器（如Visual C++, Intel C++和Borland C++），我们必须将多重（multiple-）继承和虚拟（virtual-）继承类的成员函数指针转化为单一（single-）继承类的函数指针。为了实现这个目的，我巧妙地使用了模板并利用了一个奇妙的戏法。注意，这个戏法的使用是因为这些编译器并不是完全符合标准的，但是使用这个戏法得到了回报：它使这些编译器产生了优化的代码。<br>　　<br>　　既然我们知道编译器是怎样在内部存储成员函数指针的，并且我们知道在问题中应该怎样为成员函数指针调整this指针，我们的代码在设置委托时可以自己调整this指针。对单一继承类的函数指针，则不需要进行调整；对多重继承，则只需要一次加法就可完成调整；对虚拟继承...就有些麻烦了。但是这样做是管用的，并且在大多数情况下，所有的工作都在编译时完成！<br>　　<br>　　这是最后一个诀窍。我们怎样区分不同的继承类型？并没有官方的方法来让我们区分一个类是多重继承的还是其他类型的继承。但是有一种巧妙的方法，你可以查看我在前面给出了一个列表（见中篇）——对MSVC，每种继承方式产生的成员函数指针的大小是不同的。所以，我们可以基于成员函数指针的大小使用模版！比如对多重继承类型来说，这只是个简单的计算。而在确定unknown_inheritance（16字节）类型的时候，也会采用类似的计算方法。<br>　　<br>　　对于微软和英特尔的编译器中采用不标准12字节的虚拟继承类型的指针的情况，我引发了一个编译时错误（compile-time error），因为需要一个特定的运行环境（workaround）。如果你在MSVC中使用虚拟继承，要在声明类之前使用 FASTDELEGATEDECLARE宏。而这个类必须使用unknown_inheritance（未知继承类型）指针（这相当于一个假定的 __unknown_inheritance关键字）。例如：<br>　　<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">FASTDELEGATEDECLARE(CDerivedClass)<br>　　<br>　　</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;CDerivedClass&nbsp;:&nbsp;</span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;CBaseClass1,&nbsp;</span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;CBaseClass2&nbsp;{<br>　　<br>　　</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;:&nbsp;(etc)</span><span style="color: #008000;"><br></span><span style="color: #000000;">　　<br>　　};</span></div>
<br>　　<br>　　这个宏和一些常数的声明是在一个隐藏的命名空间中实现的，这样在其他编译器中使用时也是安全的。MSVC（7.0或更新版本）的另一种方法是在工程中使用/vmg编译器选项。而Inter的编译器对/vmg编译器选项不起作用，所以你必须在虚拟继承类中使用宏。我的这个代码是因为编译器的bug才可以正确运行，你可以查看代码来了解更多细节。而在遵从标准的编译器中不需要注意这么多，况且在任何情况下都不会妨碍FASTDELEGATEDECLARE宏的使用。<br>　　<br>　　一旦你将类的对象指针和成员函数指针转化为标准形式，实现单一目标的委托（single-target delegate）就比较容易了（虽然做起来感觉冗长乏味）。你只要为每一种具有不同参数的函数制作相应的模板类就行了。实现其他类型的委托的代码也大都与此相似，只是对参数稍做修改罢了。<br>　　<br>　　这种用非标准方式转换实现的委托还有一个好处，就是委托对象之间可以用等式比较。目前实现的大多数委托无法做到这一点，这使这些委托不能胜任一些特定的任务，比如实现多播委托（multi-cast delegates） [Sutter3]。<br>　　<br>　　静态函数作为委托目标（delegate target）<br>　　<br>　　理论上，一个简单的非成员函数（non-member function），或者一个静态成员函数（static member function）可以被作为委托目标（delegate target）。这可以通过将静态函数转换为一个成员函数来实现。我有两种方法实现这一点，两种方法都是通过使委托指向调用这个静态函数的&#8220;调用器（invoker）&#8221;的成员函数的方法来实现的。<br><img src ="http://www.cppblog.com/colys/aggbug/25793.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-06-08 00:18 <a href="http://www.cppblog.com/colys/articles/25793.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>成员函数指针与高性能的C++委托(上)</title><link>http://www.cppblog.com/colys/articles/25790.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Thu, 07 Jun 2007 16:17:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/25790.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/25790.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/25790.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/25790.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/25790.html</trackback:ping><description><![CDATA[&nbsp;<br><br><span style="font-weight: bold;">引子</span><br><br>标准C++中没有真正的面向对象的函数指针。这一点对C++来说是不幸的，因为面向对象的指针（也叫做&#8220;闭包（closure）&#8221;或&#8220;委托（delegate）&#8221;）在一些语言中已经证明了它宝贵的价值。在Delphi (Object Pascal)中，面向对象的函数指针是Borland可视化组建库（VCL，Visual Component Library）的基础。而在目前，C#使&#8220;委托&#8221;的概念日趋流行，这也正显示出C#这种语言的成功。在很多应用程序中，&#8220;委托&#8221;简化了松耦合对象的设计模式[GoF]。这种特性无疑在标准C++中也会产生很大的作用。<br><br>很遗憾，C++中没有&#8220;委托&#8221;，它只提供了成员函数指针（member function pointers）。很多程序员从没有用过函数指针，这是有特定的原因的。因为函数指针自身有很多奇怪的语法规则（比如&#8220;-&gt;*&#8221;和&#8220;.*&#8221;操作符），而且很难找到它们的准确含义，并且你会找到更好的办法以避免使用函数指针。更具有讽刺意味的是：事实上，编译器的编写者如果实现&#8220;委托&#8221;的话会比他费劲地实现成员函数指针要容易地多！<br><br>在这篇文章中，我要揭开成员函数指针那&#8220;神秘的盖子&#8221;。在扼要地重述成员函数指针的语法和特性之后，我会向读者解释成员函数指针在一些常用的编译器中是怎样实现的，然后我会向大家展示编译器怎样有效地实现&#8220;委托&#8221;。最后我会利用这些精深的知识向你展示在C++编译器上实现优化而可靠的&#8220;委托&#8221;的技术。比如，在Visual C++(6.0, .NET, and .NET 2003)中对单一目标委托（single-target delegate）的调用，编译器仅仅生成两行汇编代码！<br><br>函数指针<br><br>下面我们复习一下函数指针。在C和C++语言中，一个命名为my_func_ptr的函数指针指向一个以一个int和一个char*为参数的函数，这个函数返回一个浮点值，声明如下：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">float</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">*</span><span style="color: #000000;">my_func_ptr)(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">);</span></div>
<br><br>//为了便于理解，我强烈推荐你使用typedef关键字。<br><br>//如果不这样的话，当函数指针作为一个函数的参数传递的时候，<br><br>// 程序会变得晦涩难懂。<br><br>// 这样的话，声明应如下所示：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">typedef&nbsp;</span><span style="color: #0000ff;">float</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">*</span><span style="color: #000000;">MyFuncPtrType)(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">);<br><br>MyFuncPtrType&nbsp;my_func_ptr;</span></div>
<br><br>应注意，对每一个函数的参数组合，函数指针的类型应该是不同的。在Microsoft Visual C++（以下称MSVC）中，对三种不同的调用方式有不同的类型：__cdecl, __stdcall, 和__fastcall。如果你的函数指针指向一个型如float some_func(int, char *)的函数，这样做就可以了：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">my_func_ptr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;some_func;<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">当你想调用它所指向的函数时，你可以这样写：</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>(</span><span style="color: #000000;">*</span><span style="color: #000000;">my_func_ptr)(</span><span style="color: #000000;">7</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Arbitrary&nbsp;String</span><span style="color: #000000;">"</span><span style="color: #000000;">);</span></div>
<br><br>你可以将一种类型的函数指针转换成另一种函数指针类型，但你不可以将一个函数指针指向一个void *型的数据指针。其他的转换操作就不用详叙了。一个函数指针可以被设置为0来表明它是一个空指针。所有的比较运算符（==, !=, &lt;, &gt;, &lt;=, &gt;=）都可以使用，可以使用&#8220;==0&#8221;或通过一个显式的布尔转换来测试指针是否为空（null）。<br><br>在C语言中，函数指针通常用来像qsort一样将函数作为参数，或者作为Windows系统函数的回调函数等等。函数指针还有很多其他的应用。函数指针的实现很简单：它们只是&#8220;代码指针（code pointer）&#8221;，它们体现在汇编语言中是用来保存子程序代码的首地址。而这种函数指针的存在只是为了保证使用了正确的调用规范。<br><br>成员函数指针<br><br>在C++程序中，很多函数是成员函数，即这些函数是某个类中的一部分。你不可以像一个普通的函数指针那样指向一个成员函数，正确的做法应该是，你必须使用一个成员函数指针。一个成员函数的指针指向类中的一个成员函数，并和以前有相同的参数，声明如下：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">float</span><span style="color: #000000;">&nbsp;(SomeClass::</span><span style="color: #000000;">*</span><span style="color: #000000;">my_memfunc_ptr)(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">);<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">对于使用const关键字修饰的成员函数，声明如下：</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">float</span><span style="color: #000000;">&nbsp;(SomeClass::</span><span style="color: #000000;">*</span><span style="color: #000000;">my_const_memfunc_ptr)(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">)&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">;</span></div>
<br><br>注意使用了特殊的运算符（::*），而&#8220;SomeClass&#8221;是声明中的一部分。成员函数指针有一个可怕的限制：它们只能指向一个特定的类中的成员函数。对每一种参数的组合，需要有不同的成员函数指针类型，而且对每种使用const修饰的函数和不同类中的函数，也要有不同的函数指针类型。在MSVC中，对下面这四种调用方式都有一种不同的调用类型：__cdecl, __stdcall, __fastcall, 和 __thiscall。（__thiscall是缺省的方式，有趣的是，在任何官方文档中从没有对__thiscall关键字的详细描述，但是它经常在错误信息中出现。如果你显式地使用它，你会看到&#8220;它被保留作为以后使用（it is reserved for future use）&#8221;的错误提示。）如果你使用了成员函数指针，你最好使用typedef以防止混淆。<br><br>将函数指针指向型如float SomeClass::some_member_func(int, char *)的函数，你可以这样写：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">my_memfunc_ptr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">SomeClass::some_member_func;</span></div>
<br><br>很多编译器（比如MSVC）会让你去掉&#8220;&amp;&#8221;，而其他一些编译器（比如GNU G++）则需要添加&#8220;&amp;&#8221;，所以在手写程序的时候我建议把它添上。若要调用成员函数指针，你需要先建立SomeClass的一个实例，并使用特殊操作符&#8220;-&gt;*&#8221;，这个操作符的优先级较低，你需要将其适当地放入圆括号内。<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">SomeClass&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">x&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;SomeClass;<br><br>(x</span><span style="color: #000000;">-&gt;*</span><span style="color: #000000;">my_memfunc_ptr)(</span><span style="color: #000000;">6</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Another&nbsp;Arbitrary&nbsp;Parameter</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">如果类在栈上，你也可以使用&#8220;.*&#8221;运算符。</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>SomeClass&nbsp;y;<br><br>(y.</span><span style="color: #000000;">*</span><span style="color: #000000;">my_memfunc_ptr)(</span><span style="color: #000000;">15</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Different&nbsp;parameters&nbsp;this&nbsp;time</span><span style="color: #000000;">"</span><span style="color: #000000;">);</span></div>
<br><br>不要怪我使用如此奇怪的语法——看起来C++的设计者对标点符号有着由衷的感情！C++相对于C增加了三种特殊运算符来支持成员指针。&#8220;::*&#8221;用于指针的声明，而&#8220;-&gt;*&#8221;和&#8220;.*&#8221;用来调用指针指向的函数。这样看起来对一个语言模糊而又很少使用的部分的过分关注是多余的。（你当然可以重载&#8220;-&gt;*&#8221;这些运算符，但这不是本文所要涉及的范围。）<br><br>一个成员函数指针可以被设置成0，并可以使用&#8220;==&#8221;和&#8220;!=&#8221;比较运算符，但只能限定在同一个类中的成员函数的指针之间进行这样的比较。任何成员函数指针都可以和0做比较以判断它是否为空。与函数指针不同，不等运算符（&lt;, &gt;, &lt;=, &gt;=）对成员函数指针是不可用的。<br><br>成员函数指针的怪异之处<br><br>成员函数指针有时表现得很奇怪。首先，你不可以用一个成员函数指针指向一个静态成员函数，你必须使用普通的函数指针才行（在这里&#8220;成员函数指针&#8221;会产生误解，它实际上应该是&#8220;非静态成员函数指针&#8221;才对）。其次，当使用类的继承时，会出现一些比较奇怪的情况。比如，下面的代码在MSVC下会编译成功（注意代码注释）：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">＃i&nbsp;nclude&nbsp;&#8220;stdio.h&#8221;<br><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;SomeClass&nbsp;{<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br><br></span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;some_member_func(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;x,&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">p)&nbsp;{<br><br>printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">In&nbsp;SomeClass</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;};<br><br>};<br><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;DerivedClass&nbsp;:&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;SomeClass&nbsp;{<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;如果你把下一行的注释销掉，带有&nbsp;line&nbsp;(*)的那一行会出现错误<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;virtual&nbsp;void&nbsp;some_member_func(int&nbsp;x,&nbsp;char&nbsp;*p)&nbsp;{&nbsp;printf("In&nbsp;DerivedClass");&nbsp;};</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>};<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;main()&nbsp;{<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">声明SomeClass的成员函数指针</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>typedef&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;(SomeClass::</span><span style="color: #000000;">*</span><span style="color: #000000;">SomeClassMFP)(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">);<br><br>SomeClassMFP&nbsp;my_memfunc_ptr;<br><br>my_memfunc_ptr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">DerivedClass::some_member_func;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;----&nbsp;line&nbsp;(*)</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br><br>}</span></div>
<br><br>奇怪的是，&amp;DerivedClass::some_member_func是一个SomeClass类的成员函数指针，而不是DerivedClass类的成员函数指针！（一些编译器稍微有些不同：比如，对于Digital Mars C++，在上面的例子中，&amp;DerivedClass::some_member_func会被认为没有定义。）但是，如果在DerivedClass类中重写（override）了some_member_func函数，代码就无法通过编译，因为现在的&amp;DerivedClass::some_member_func已成为DerivedClass类中的成员函数指针！<br><br>成员函数指针之间的类型转换是一个讨论起来非常模糊的话题。在C++的标准化的过程中，在涉及继承的类的成员函数指针时，对于将成员函数指针转化为基类的成员函数指针还是转化为子类成员函数指针的问题和是否可以将一个类的成员函数指针转化为另一个不相关的类的成员函数指针的问题，人们曾有过很激烈的争论。然而不幸的是，在标准委员会做出决定之前，不同的编译器生产商已经根据自己对这些问题的不同的回答实现了自己的编译器。根据标准（第5.2.10/9节），你可以使用reinterpret_cast在一个成员函数指针中保存一个与本来的类不相关的类的成员函数。有关成员函数指针转换的问题的最终结果也没有确定下来。你现在所能做的还是像以前那样——将成员函数指针转化为本类的成员函数的指针。在文章的后面我会继续讨论这个问题，因为这正是各个编译器对这样一个标准没有达成共识的一个话题。<br><br>在一些编译器中，在基类和子类的成员函数指针之间的转换时常有怪事发生。当涉及到多重继承时，使用reinterpret_cast将子类转换成基类时，对某一特定编译器来说有可能通过编译，而也有可能通不过编译，这取决于在子类的基类列表中的基类的顺序！下面就是一个例子：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Derived:&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Base1,&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Base2&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;情况&nbsp;(a)</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Derived2:&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Base2,&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Base1&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;情况&nbsp;(b)</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>typedef&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;(Derived::</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;Derived_mfp)();<br><br>typedef&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;(Derived2::</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;Derived2_mfp)();<br><br>typedef&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;(Base1::</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;Base1mfp)&nbsp;();<br><br>typedef&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;(Base2::</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;Base2mfp)&nbsp;();<br><br>Derived_mfp&nbsp;x;</span></div>
<br><br>对于情况(a)，static_cast&lt;Base1mfp&gt; (x) 是合法的，而static_cast&lt;Base2mfp&gt; (x) 则是错误的。然而情况(b)却与之相反。你只可以安全地将子类的成员函数指针转化为第一个基类的成员函数指针！如果你要实验一下，MSVC会发出C4407号警告，而Digital Mars C++会出现编译错误。如果用reinterpret_cast代替static_cast，这两个编译器都会发生错误，但是两种编译器对此有着不同的原因。但是一些编译器对此细节置之不理，大家可要小心了！<br><br>标准C++中另一条有趣的规则是：你可以在类定义之前声明它的成员函数指针。这对一些编译器会有一些无法预料的副作用。我待会讨论这个问题，现在你只要知道要尽可能得避免这种情况就是了。<br><br>需要值得注意的是，就像成员函数指针，标准C++中同样提供了成员数据指针（member data pointer）。它们具有相同的操作符，而且有一些实现原则也是相同的。它们用在stl::stable_sort的一些实现方案中，而对此很多其他的应用我就不再提及了。<br><br>成员函数指针的使用<br><br>现在你可能会觉得成员函数指针是有些奇异。但它可以用来做什么呢？对此我在网上做了非常广泛的调查。最后我总结出使用成员函数指针的两点原因：<br><br>&nbsp;&nbsp;&nbsp; * 用来做例子给<br>&nbsp;&nbsp;&nbsp; * C++初学者看，帮助它们学习语法；或者 为了实现&#8220;委托（<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delegate）&#8221;！ <br><br>成员函数指针在STL和Boost库的单行函数适配器（one-line function adaptor）中的使用是微不足道的，而且允许你将成员函数和标准算法混合使用。但是它们最重要的应用是在不同类型的应用程序框架中，比如它们形成了MFC消息系统的核心。<br><br>当你使用MFC的消息映射宏（比如ON_COMMAND）时，你会组装一个包含消息ID和成员函数指针（型如：CCmdTarget::*成员函数指针）的序列。这是MFC类必须继承CCmdTarget才可以处理消息的原因之一。但是，各种不同的消息处理函数具有不同的参数列表（比如OnDraw处理函数的第一个参数的类型为CDC *），所以序列中必须包含各种不同类型的成员函数指针。MFC是怎样做到这一点的呢？MFC利用了一个可怕的编译器漏洞（hack），它将所有可能出现的成员函数指针放到一个庞大的联合（union）中，从而避免了通常需要进行的C++类型匹配检查。（看一下afximpl.h和cmdtarg.cpp中名为MessageMapFunctions的union，你就会发现这一恐怖的事实。）因为MFC有如此重要的一部分代码，所以事实是，所有的编译器都为这个漏洞开了绿灯。（但是，在后面我们会看到，如果一些类用到了多重继承，这个漏洞在MSVC中就不会起作用，这正是在使用MFC时只能必须使用单一继承的原因。）<br><br>在boost::function中有类似的漏洞（但不是太严重）。看起来如果你想做任何有关成员函数指针的比较有趣的事，你就必须做好与这个语言的漏洞进行挑战的准备。要是你想否定C++的成员函数指针设计有缺陷的观点，看来是很难的。<br><br>在写这篇文章中，我有一点需要指明：&#8220;允许成员函数指针之间进行转换（cast），而不允许在转换完成后调用其中的函数&#8221;，把这个规则纳入C++的标准中是可笑的。首先，很多流行的编译器对这种转换不支持（所以，转换是标准要求的，但不是可移植的）。其次，所有的编译器，如果转换成功，调用转换后的成员函数指针时仍然可以实现你预期的功能：那编译器就没有所谓的&#8220;undefined behavior（未定义的行为）&#8221;这类错误出现的必要了（调用（Invocation）是可行的，但这不是标准！）。第三，允许转换而不允许调用是完全没有用处的，只有转换和调用都可行，才能方便而有效地实现委托，从而使这种语言受益。<br><br>为了让你确信这一具有争议的论断，考虑一下在一个文件中只有下面的一段代码，这段代码是合法的：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;SomeClass;<br><br>typedef&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;(SomeClass::</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;SomeClassFunction)(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">);<br><br></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;Invoke(SomeClass&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">pClass,&nbsp;SomeClassFunction&nbsp;funcptr)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(pClass</span><span style="color: #000000;">-&gt;*</span><span style="color: #000000;">funcptr)();<br>};</span></div>
<br><br>注意到编译器必须生成汇编代码来调用成员函数指针，其实编译器对SomeClass类一无所知。显然，除非链接器进行了一些极端精细的优化措施，否则代码会忽视类的实际定义而能够正确地运行。而这造成的直接后果是，你可以&#8220;安全地&#8221;调用从完全不同的其他类中转换过来的成员函数指针。<br><br>为解释我的断言的另一半——转 换并不能按照标准所说的方式进行，我需要在细节上讨论编译器是怎样实现成员函数指针的。我同时会解释为什么使用成员函数指针的规则具有如此严格的限制。获 得详细论述成员函数指针的文档不是太容易，并且大家对错误的言论已经习以为常了，所以，我仔细检查了一系列编译器生成的汇编代码&#8230;&#8230;<br><br><img src ="http://www.cppblog.com/colys/aggbug/25790.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-06-08 00:17 <a href="http://www.cppblog.com/colys/articles/25790.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++成员函数指针的应用</title><link>http://www.cppblog.com/colys/articles/25785.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Thu, 07 Jun 2007 15:33:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/25785.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/25785.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/25785.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/25785.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/25785.html</trackback:ping><description><![CDATA[<font size="3">&nbsp;C++中，成员指针是最为复杂的语法结构。但在事件驱动和多线程应用中被广泛用于调用回叫函数。在多线程应用中，每个线程都通过指向成员函数的指针来调用该函数。在这样的应用中，如果不用成员指针，编程是非常困难的。 <br><br>　　刚遇到这种语法时也许会让你止步不前。但你会发现，使用恰当的类型定义之后，复杂的语法是可以简化的。本文引导你了解成员函数指针的声明，赋值和调用回叫函数。 <br><br>　　<strong>成员函数指针的声明</strong> <br><br>　　一个成员函数指针包括成员函数的返回类型，后随::操作符类名，指针名和函数的参数。初看上去，语法有点复杂。其实可以把它理解为一个指向原函数的指针，格式是：函数返回类型，类名，::操作符，指针星号，指针名，函数参数。 <br><br>　　一个指向外部函数的指针声明为： <br><br>　　void (*pf)(char *, const char *); <br><br>　　void strcpy(char * dest, const char * source); <br><br>　　pf=strcpy; <br><br>　　一个指向类A成员函数的指针声明为： <br><br>　　void (A::*pmf)(char *, const char *); <br><br>　　声明的解释是：pmf是一个指向A成员函数的指针，返回无类型值，函数带有二个参数，参数的类型分别是char * 和 const char *。除了在星号前增加A:: ，与声明外部函数指针的方法一样。 <br><br>　　<strong>赋值</strong> <br><br>　　给成员指针赋值的方法是将函数名通过指针符号&amp;赋予指针名。如下所示： <br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;"><font>class</font></span><span style="color: #000000;"><font>&nbsp;A<br>{<br><br>　　</font></span><span style="color: #0000ff;"><font>public</font></span><span style="color: #000000;"><font>:<br><br>　　　</font></span><span style="color: #0000ff;"><font>void</font></span><span style="color: #000000;"><font>&nbsp;strcpy(</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>,&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>);<br><br>　　　</font></span><span style="color: #0000ff;"><font>void</font></span><span style="color: #000000;"><font>&nbsp;strcat(</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>,&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>);<br><br>};<br>pmf&nbsp;</font></span><span style="color: #000000;"><font>=</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>&amp;</font></span><span style="color: #000000;"><font>A::strcpy;&nbsp;</font></span></div>
<br><br>　　有些老的编译器可以通过没有&amp;号的赋值方式，但标准C++强制要求加上&amp;号。 <br><br>　　<strong>使用类型定义</strong> <br><br>　　可以用类型定义来隐藏复杂的成员指针语法。例如，下面的语句定义了PMA是一个指向A成员函数的指针，函数返回无类型值，函数参数类型为char * 和 const char *： <br><br>　　typedef void(A::*PMA)(char *, const char *); <br><br>　　PMA pmf= &amp;A::strcat; // pmf是PMF类型(类A成员指针)的变量 <br><br>　　下文会看到使用类型定义特别有利于声明成员指针数组。 <br><br>　　<strong>通过成员指针调用成员函数</strong> <br><br>
可以在不必知道函数名的情况下，通过成员指针调用对象的成员函数。例如，函数dispatcher有一个变量pmf，通过它调用类成员函数，不管它调用
的是strcpy()函数还是strcat()函数。指向外部原函数的指针和指向类成员函数的指针是有很大区别的。后者必须指向被调函数的宿主对象。因
此，除了要有成员指针外，还要有合法对象或对象指针。 <br><br>　　现举例做进一步说明。假设A有二个实例，成员函数指针支持多态性。这样在成员指针调用虚成员函数时是动态处理的(即所谓后联编 - 译注)。注意，不可调用构造和析构函数。示例如下： <br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;"><font>&nbsp;&nbsp;&nbsp; A&nbsp;a1,&nbsp;a2;<br><br>　　A&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>p</font></span><span style="color: #000000;"><font>=</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>&amp;</font></span><span style="color: #000000;"><font>a1;&nbsp;</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>创建指向A的指针<br><br>　　</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>创建指向成员的指针并初始化</font></span><span style="color: #008000;"><font><br></font></span><span style="color: #000000;"><font><br>　　</font></span><span style="color: #0000ff;"><font>void</font></span><span style="color: #000000;"><font>&nbsp;(A::</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>pmf)(</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>,&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>)&nbsp;</font></span><span style="color: #000000;"><font>=</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>&amp;</font></span><span style="color: #000000;"><font>A::strcpy;<br><br>　　</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>要将成员函数绑定到pmf，必须定义呼叫的对象。<br><br>　　</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>可以用*号引导：</font></span><span style="color: #008000;"><font><br></font></span><span style="color: #000000;"><font><br>　　</font></span><span style="color: #0000ff;"><font>void</font></span><span style="color: #000000;"><font>&nbsp;dispatcher(A&nbsp;a,&nbsp;</font></span><span style="color: #0000ff;"><font>void</font></span><span style="color: #000000;"><font>&nbsp;(A::</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>pmf)(</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>,&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>))<br><br>　　{<br><br>　　　</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;str[</font></span><span style="color: #000000;"><font>4</font></span><span style="color: #000000;"><font>];<br><br>　　　(a.</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>pmf)(str,&nbsp;&#8220;abc&#8221;);&nbsp;</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>将成员函数绑定到pmf</font></span><span style="color: #008000;"><font><br></font></span><span style="color: #000000;"><font><br>　　}<br><br>　　</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>或用A的指针表达方式指向成员指针：</font></span><span style="color: #008000;"><font><br></font></span><span style="color: #000000;"><font><br>　　</font></span><span style="color: #0000ff;"><font>void</font></span><span style="color: #000000;"><font>&nbsp;dispatcher(A&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>&nbsp;p,&nbsp;</font></span><span style="color: #0000ff;"><font>void</font></span><span style="color: #000000;"><font>&nbsp;(A::</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>pmf)(</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>,&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>))<br><br>　　{<br><br>　　　</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;str[</font></span><span style="color: #000000;"><font>4</font></span><span style="color: #000000;"><font>];&nbsp;(p</font></span><span style="color: #000000;"><font>-&gt;*</font></span><span style="color: #000000;"><font>pmf)(str,&nbsp;&#8220;abc&#8221;);<br><br>　　}<br><br>　　</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>函数的调用方法为：</font></span><span style="color: #008000;"><font><br></font></span><span style="color: #000000;"><font><br>　　dispatcher(a,&nbsp;pmf);&nbsp;</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>&nbsp;.*&nbsp;方式</font></span><span style="color: #008000;"><font><br></font></span><span style="color: #000000;"><font><br>　　dispatcher(</font></span><span style="color: #000000;"><font>&amp;</font></span><span style="color: #000000;"><font>a,&nbsp;pmf);&nbsp;</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>&nbsp;-&gt;*&nbsp;方式&nbsp;</font></span></div>
<br>高级使用技巧 <br><br>　　以上是成员函数的基本知识。现在介绍它的高级使用技巧。 <br><br>　　<strong>成员指针数组</strong> <br><br>　　在下例，声明了一个含有二个成员指针的数组，并分配类的成员函数地址给成员指针： <br><br>　　PMA pmf[2]= {&amp;A::strcpy, &amp;A::strcat};&nbsp;<br>也就是<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void (A::*PMA[2])(char *, const char *)= {&amp;A::strcpy, &amp;A::strcat}; <br><br>　　这样的数组在菜单驱动应用中很有用。选择菜单项后，应用将调用相应的回叫函数，如下所示： <br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;"><font>&nbsp;&nbsp;&nbsp; enum</font></span><span style="color: #000000;"><font>&nbsp;MENU_OPTIONS&nbsp;{&nbsp;COPY,&nbsp;CONCAT&nbsp;};<br><br>　　</font></span><span style="color: #0000ff;"><font>int</font></span><span style="color: #000000;"><font>&nbsp;main()<br>　　{<br>　　　MENU_OPTIONS&nbsp;option;&nbsp;</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;str[</font></span><span style="color: #000000;"><font>4</font></span><span style="color: #000000;"><font>];<br>　　　</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>从外部资源读取选项</font></span><span style="color: #008000;"></span><span style="color: #000000;"><font><br>　　　</font></span><span style="color: #0000ff;"><font>switch</font></span><span style="color: #000000;"><font>&nbsp;(option)<br>　　　{<br>　　　　</font></span><span style="color: #0000ff;"><font>case</font></span><span style="color: #000000;"><font>&nbsp;COPY:<br><br>　　　　　(pa</font></span><span style="color: #000000;"><font>-&gt;*</font></span><span style="color: #000000;"><font>pmf[COPY])(str,&nbsp;&#8220;abc&#8221;);<br><br>　　　　　</font></span><span style="color: #0000ff;"><font>break</font></span><span style="color: #000000;"><font>;<br><br>　　　　</font></span><span style="color: #0000ff;"><font>case</font></span><span style="color: #000000;"><font>&nbsp;CONCAT:<br><br>　　　　　(pa</font></span><span style="color: #000000;"><font>-&gt;*</font></span><span style="color: #000000;"><font>pmf[CONCAT])(str,&nbsp;&#8220;abc&#8221;);<br><br>　　　　　</font></span><span style="color: #0000ff;"><font>break</font></span><span style="color: #000000;"><font>;<br><br>　　　　　</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>&#8230;</font></span><span style="color: #008000;"><font><br></font></span><span style="color: #000000;"><font><br>　　　}<br>　　}&nbsp;</font></span></div>
<br><br>　　<strong>Const 类型的成员函数</strong> <br><br>　　成员指针的类型应该与成员函数类型一致。上面例子中的pmf 可以指向A的任意函数，只要该函数不是const类型。如下所示，如果将touppercase()的地址分配给pmf，将导致编译出错，因为touppercase() 的类型是const。 <br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;"><font>&nbsp;&nbsp; Class&nbsp;A<br>　 {<br><br>　　</font></span><span style="color: #0000ff;"><font> public</font></span><span style="color: #000000;"><font>:<br><br>　　　&nbsp; </font></span><span style="color: #0000ff;"><font>void</font></span><span style="color: #000000;"><font>&nbsp;strpcy(</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>,&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>);<br><br>　　　</font></span><span style="color: #0000ff;"><font>&nbsp; void</font></span><span style="color: #000000;"><font>&nbsp;strcat(</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>,&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>);<br><br>　　　</font></span><span style="color: #0000ff;"><font>&nbsp; void</font></span><span style="color: #000000;"><font>&nbsp;touppercase(</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>,&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>)&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>;<br><br>　　};<br><br>　　pmf</font></span><span style="color: #000000;"><font>=&amp;</font></span><span style="color: #000000;"><font>A::touppercase;&nbsp;</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>出错，类型不匹配<br><br>　　</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>解决的方法是声明一个const类型的成员指针：</font></span><span style="color: #008000;"><font><br></font></span><span style="color: #000000;"><font><br>　　</font></span><span style="color: #0000ff;"><font>void</font></span><span style="color: #000000;"><font>&nbsp;(A::pcmf)(</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>,&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #0000ff;"><font>char</font></span><span style="color: #000000;"><font>&nbsp;</font></span><span style="color: #000000;"><font>*</font></span><span style="color: #000000;"><font>)&nbsp;</font></span><span style="color: #0000ff;"><font>const</font></span><span style="color: #000000;"><font>;<br><br>　　pcmf</font></span><span style="color: #000000;"><font>=&amp;</font></span><span style="color: #000000;"><font>A::touppercase;&nbsp;</font></span><span style="color: #008000;"><font>//</font></span><span style="color: #008000;"><font>&nbsp;现在可以了&nbsp;</font></span></div>
<br><br>　　有些差劲的编译器允许一个非const类型的成员指针指向const类型的成员函数。这在标准C++是不允许的。 </font><img src ="http://www.cppblog.com/colys/aggbug/25785.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-06-07 23:33 <a href="http://www.cppblog.com/colys/articles/25785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++ typedef 函数指针</title><link>http://www.cppblog.com/colys/articles/25381.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Sun, 03 Jun 2007 07:07:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/25381.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/25381.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/25381.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/25381.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/25381.html</trackback:ping><description><![CDATA[<span style="font-family: 宋体;"><font size="3">函数指针<span lang="EN-US"><o:p></o:p></span></font></span>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　一个函数在编译时被分配一个入口地址，将这个入口地址称为函数的指针，可<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　以用一个指针变量指向该函数指针，然后通过该变量来调用函数。<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　有关说明：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　<span lang="EN-US">1</span>、函数指针的声明格式：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　　 函数返回值类型（＊指针变量名）（参数类型列表）<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　<span lang="EN-US"><span>&nbsp;&nbsp; </span></span>或者是：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　<span lang="EN-US"><span>&nbsp;&nbsp; </span>typedef</span>　函数返回值类型　（＊指针变量名）（参数类型列表）<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2</span><span style="font-family: 宋体;">、一个函数指针只能指向一种类型的函数，即具有相同的返回值和相同的参　　　　　　　　　　　　<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　　 数的函数<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　３、关于函数指针的加减运算没有意义<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　 函数指针数组定义：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">函数定义：<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>void fun1(void *p);<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>void fun2(void *p);<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>void fun3(void *p);<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　 函数指针数组定义：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　 <span lang="EN-US">void(*fun[3])(void*);//typedef void(*pfun)(void*);pfun fun[3];<o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　 指针赋值：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>fun[0] = fun1;<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>fun[1] = fun2;<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>fun[2] = fun3;<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">函数调用：<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;"><font size="3">　　　　　　 <span lang="EN-US">fun[0](&amp;a);<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//int a;<o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>fun[1](&amp;b);<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//int b;<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>fun[3](&amp;c);<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//int c;<o:p></o:p></font></span></p>
<h5 style="margin: auto 0cm; text-indent: 18pt;"><font face="宋体"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;</span></span><span style="font-weight: normal; font-size: 10.5pt;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;</span></span><span style="font-weight: normal; font-size: 10.5pt;">声明一个指向成员函数的指针<span lang="EN-US"><o:p></o:p></span></span></font></h5>
<p style="margin-left: 68.25pt; text-indent: 2.1pt;"><span style="font-size: 10.5pt;"><font face="宋体">一个指向成员函数的指针包括成员函数的返回类型，带<em><span lang="EN-US">::</span></em>符号的类名称，函数参数表。虽然这一语法看似复杂，其实它和普通的指针是一样的。指向外部函数的指针可如下声明：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p style="margin-left: 68.25pt;"><span style="font-size: 10.5pt;" lang="EN-US"><font face="宋体">void (*pf)(char *, const char *);<br>void strcpy(char * dest, const char * source);<br>pf=strcpy;<o:p></o:p></font></span></p>
<p style="margin-left: 68.25pt;"><span style="font-size: 10.5pt;"><font face="宋体">相应指向类<span lang="EN-US">A</span>的成员函数的指针如下表示：<span lang="EN-US"> <o:p></o:p></span></font></span></p>
<pre style="text-indent: 65.1pt;"><span style="font-size: 10.5pt;" lang="EN-US"><font face="宋体">void (A::*pmf)(char *, const char *);<o:p></o:p></font></span></pre>
<p style="margin-left: 65.1pt;"><span style="font-size: 10.5pt;"><font face="宋体">以上<em><span lang="EN-US">pmf</span></em>是指向类<span lang="EN-US">A</span>的一个成员函数的指针，传递两个变量<em><span lang="EN-US">char *</span></em>和 <em><span lang="EN-US">const char *</span></em>，没有返回值。注意星号前面的<span lang="EN-US">A::</span>符号，这和前面的声明是一致的。<span lang="EN-US"> <o:p></o:p></span></font></span></p>
<h5 style="margin: auto 0cm; text-indent: 67pt;"><span style="font-weight: normal;"><font face="宋体">赋值<span lang="EN-US"><o:p></o:p></span></font></span></h5>
<h5 style="margin: auto 0cm auto 64.25pt;"><font face="宋体"><span style="font-weight: normal;">为了给一个指向成员函数的指针赋值，可以采用成员函数名并再其前面加一个<span lang="EN-US">&amp;</span>的方式</span><span style="font-weight: normal; font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span></font></h5>
<h5 style="margin: auto 0cm; text-indent: 65.1pt;"><span style="font-weight: normal; font-size: 10.5pt;"><font face="宋体">使用<span lang="EN-US">typedef<o:p></o:p></span></font></span></h5>
<p style="margin-left: 65.1pt;"><span style="font-size: 10.5pt;"><font face="宋体">你可以使用<span lang="EN-US">typedef</span>来隐藏一些指向成员函数的复杂指针。例如，下面的代码定义了一个类<span lang="EN-US">A</span>中的成员函数的指针<em><span lang="EN-US">PMA</span></em>，并传递<em><span lang="EN-US">char *</span></em>和<em><span lang="EN-US">const char *</span></em>参数。<span lang="EN-US"><o:p></o:p></span></font></span></p>
<pre style="margin-left: 65.1pt;"><span style="font-size: 10.5pt;" lang="EN-US"><font face="宋体">typedef void(A::*PMA)(char *, const char *);<br>PMA pmf= &amp;A::strcat; // use a typedef to define a pointer to member<o:p></o:p></font></span></pre>
<p style="text-indent: 65.1pt;"><span style="font-size: 10.5pt;"><font face="宋体">使用<em><span lang="EN-US">typedef</span></em>特别有用，尤其是对于指向成员函数的数组指针。<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: -21pt;"><span style="font-family: 宋体;" lang="EN-US"><span><font size="3">■</font><span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><font size="3"><span style="font-family: 宋体;" lang="EN-US">void</span><span style="font-family: 宋体;">类型的指针<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US">void</span><span style="font-family: 宋体;">含义：<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US">void</span><span style="font-family: 宋体;">是&#8220;无类型&#8221;，<span lang="EN-US">void*</span>则为无类型指针，<span lang="EN-US">void*</span>可以指向任何类型的数据。<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US">void a</span><span style="font-family: 宋体;">；<span lang="EN-US">//</span>此变量没有任何实际意义，无法编译通过&#8220;<span lang="EN-US">illegal use of type</span>&#8221;<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US">void </span><span style="font-family: 宋体;">的作用：<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp; </span>1</span><span style="font-family: 宋体;">、对程序返回的限定<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp; </span>2</span><span style="font-family: 宋体;">、对函数参数的限定<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;"><font size="3">我们知道，如何指针<span lang="EN-US">p1</span>和<span lang="EN-US">p2</span>的类型相同，那么我们可以直接在<span lang="EN-US">p1</span>和<span lang="EN-US">p2</span>间赋值，如果不同，必须使用强制类型转换。<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;"><font size="3">如：<span lang="EN-US">float *p1;<span>&nbsp;&nbsp; </span>int *p2;<o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: 21pt;"><span style="font-family: 宋体;"><font size="3">若：<span lang="EN-US">p1 = p2; </span>编译出错：&#8220;<span lang="EN-US">can not covert from int* to float*</span>&#8221;<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: 21pt;"><span style="font-family: 宋体;"><font size="3">必须为：<span lang="EN-US">p1 = (float*)p2;<o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">而<span lang="EN-US">void*</span>不同，任何类型的指针都可以直接赋为它，不需要强制类型转换：<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">如：<span lang="EN-US">void *p1;<span>&nbsp;&nbsp; </span>int *p2;<o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">可作：<span lang="EN-US">p1 =p2;<o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">无类型可以包容有类型，有类型不能包容无类型：<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">必须为：<span lang="EN-US">p2 = (int*)p1;<o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>viod </span><span style="font-family: 宋体;">和<span lang="EN-US"> void*</span>使用规则总结：<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 81pt; text-indent: -18pt;"><span style="font-family: 宋体;" lang="EN-US"><span><font size="3">●</font><span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><font size="3"><span style="font-family: 宋体;">如果函数没有返回值，那么应声明为</span><span lang="EN-US"><font face="Times New Roman">void</font></span><span style="font-family: 宋体;">类型</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt;"><font size="3"><span style="font-family: 宋体;">在</span><span lang="EN-US"><font face="Times New Roman">C</font></span><span style="font-family: 宋体;">语言中，凡不加返回值类型限定的函数，就会被编译器作为返回整型值处理。但是许多程序员却误以为其为</span><span lang="EN-US"><font face="Times New Roman">void</font></span><span style="font-family: 宋体;">类型</span><span lang="EN-US"><font face="Times New Roman">. </font></span><st1:personname w:st="on" productid="林锐"><span style="font-family: 宋体;">林锐</span></st1:personname><span style="font-family: 宋体;">博士《高质量</span><span lang="EN-US"><font face="Times New Roman">C/C++</font></span><span style="font-family: 宋体;">编程》中提到：</span><span lang="EN-US"><font face="Times New Roman">&#8220;C++</font></span><span style="font-family: 宋体;">语言有很严格的类型安全检查，不允许上述情况（指函数不加类型声明）发生</span><span lang="EN-US"><font face="Times New Roman">&#8221;</font></span><span style="font-family: 宋体;">。可是编译器并不一定这么认定，譬如在</span><span lang="EN-US"><font face="Times New Roman">Visual C++6.0</font></span><span style="font-family: 宋体;">中上述</span><span lang="EN-US"><font face="Times New Roman">add</font></span><span style="font-family: 宋体;">函数的编译无错也无警告且运行正确，所以不能寄希望于编译器会做严格的类型检查。</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt;"><font size="3"><span style="font-family: 宋体;">因此，为了避免混乱，我们在编写</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">C/C++</font></span><span style="font-family: 宋体;">程序时，对于任何函数都必须一个不漏地指定其类型。如果函数没有返回值，一定要声明为</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">void</font></span><span style="font-family: 宋体;">类型。这既是程序良好可读性的需要，也是编程规范性的要求。另外，加上</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">void</font></span><span style="font-family: 宋体;">类型声明后，也可以发挥代码的</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">&#8220;</font></span><span style="font-family: 宋体;">自注释</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">&#8221;</font></span><span style="font-family: 宋体;">作用。代码的</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">&#8220;</font></span><span style="font-family: 宋体;">自注释</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">&#8221;</font></span><span style="font-family: 宋体;">即代码能自己注释自己。</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span style="font-family: 宋体;">●</span><span style="font-family: ˎ̥;"><font face="Times New Roman"> </font></span><span style="font-family: 宋体;">如果函数无参数，那么应声明其参数为</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">void<o:p></o:p></font></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span style="font-family: 宋体;">●</span><span style="font-family: ˎ̥;"><font face="Times New Roman"> </font></span><span style="font-family: 宋体;">小心使用</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">void</font></span><span style="font-family: 宋体;">指针类型</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span style="font-family: 宋体;">按照</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">ANSI</font></span><span style="font-family: 宋体;">的标准，不能对</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">void</font></span><span style="font-family: 宋体;">指针进行算法操作，即下列操作是不合法的：</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><span style="font-family: ˎ̥;" lang="EN-US"><font size="3"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>void *pvoid;<o:p></o:p></font></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>pvoid ++;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//ansi</font></span><span style="font-family: 宋体;">错误</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>pvoid += 1;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//ansi </font></span><span style="font-family: 宋体;">错误</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ansi</font></span><span style="font-family: 宋体;">标准之所以这样认定，是因为它坚持，进行算法操作的指针必须是确定知道其指向数据类型的大小的。</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span style="font-family: 宋体;">但</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">GUN</font></span><span style="font-family: 宋体;">（</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">GUN</font></span><span style="font-family: 宋体;">&#8217;</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">s<span>&nbsp; </span>Not<span>&nbsp; </span>Unix</font></span><span style="font-family: 宋体;">）则不这么认为，它指定</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">void*</font></span><span style="font-family: 宋体;">的算法操作与</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">char*</font></span><span style="font-family: 宋体;">一致。因此在</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">GUN</font></span><span style="font-family: 宋体;">编译器中上述语句是正确的。</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;</span></font></span><span style="font-family: 宋体;">在实际的程序中，为了迎合</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">ansi</font></span><span style="font-family: 宋体;">标准，并提高程序的可移植性，我们可以这样实现同样功能的代码：</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><span style="font-family: ˎ̥;" lang="EN-US"><font size="3"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>void *pvoid;<o:p></o:p></font></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><span style="font-family: ˎ̥;" lang="EN-US"><font size="3"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>(char*)pvoid++;<o:p></o:p></font></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><span style="font-family: ˎ̥;" lang="EN-US"><font size="3"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>(char*)pvoid += 1;<o:p></o:p></font></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span style="font-family: 宋体;">● </span><span style="font-family: 宋体;">如果函数的参数可以是任意类型指针，那么应声明其参数为</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">void *<o:p></o:p></font></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span style="font-family: 宋体;">典型的如内存操作函数</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">memcpy</font></span><span style="font-family: 宋体;">和</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">memset</font></span><span style="font-family: 宋体;">的函数原型分别为：</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><span style="font-family: ˎ̥;" lang="EN-US"><font size="3"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;</span>void* memcpy(void *dest, const void *src, size_t len);<o:p></o:p></font></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><span style="font-family: ˎ̥;" lang="EN-US"><font size="3"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>void* memset(void *buffer,int c, size_t num);<o:p></o:p></font></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span style="font-family: 宋体;">这样，任何类型的指针都可以传入</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">memcpy</font></span><span style="font-family: 宋体;">和</span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">memset</font></span><span style="font-family: 宋体;">中，这也真实地体现了内存操作函数的意义，因为它操作的对象仅仅是一片内存，而不论内存是什类型。</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 84pt; text-indent: -84pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span style="font-family: 宋体;">● </span><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman">void</font></span><span style="font-family: 宋体;">不能代表一个真实的变量</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>void a; //</font></span><span style="font-family: 宋体;">错误</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><font size="3"><span style="font-family: ˎ̥;" lang="EN-US"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>function(void a); //</font></span><span style="font-family: 宋体;">错误</span><span style="font-family: ˎ̥;" lang="EN-US"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: -21pt;"><span style="font-family: 宋体;" lang="EN-US"><span><font size="3">■</font><span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><font size="3"><span style="font-family: 宋体;" lang="EN-US">this</span><span style="font-family: 宋体;">指针<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 57.75pt;"><span style="font-family: 宋体;"><font size="3">《深入浅出<span lang="EN-US">MFC</span>》中解释：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: -5.25pt;"><font size="3"><span style="font-family: 宋体;" lang="EN-US"><span>&nbsp;</span></span><span style="font-family: 宋体;">定义类<span lang="EN-US">CRect</span>，定义两个对象<span lang="EN-US">rect1</span>、<span lang="EN-US">rect2</span>，各有自己的<span lang="EN-US">m_color</span>成员变量，但<span lang="EN-US">rect1.setcolor</span>和<span lang="EN-US">rect2.setcolor</span>却都是通往唯一的<span lang="EN-US">CRect::setcolor</span>成员函数，那么<span lang="EN-US">CRect::setcolor</span>如何处理不同对象的<span lang="EN-US">m_color</span>？答案是由一个隐藏参数，名为<span lang="EN-US">this</span>指针。当你调用：<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">rect1.setcolro(2);<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">rect2.setcolor(3);<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;"><font size="3">时，编译器实际上为你做出来一下的代码：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">CRect::setcolor(2,(CRect*)&amp;rect1);<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">CRect::setcolor(3,(CRect*)&amp;rect2);<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;"><font size="3">多出来的参数，就是所谓的<span lang="EN-US">this</span>指针。<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">class CRect<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">{<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: 10.5pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">&#8230;&#8230;<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: 10.5pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">public:<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: 10.5pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3"><span>&nbsp; </span>void setcolor(int color){m_color = color};<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">};<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;"><font size="3">被编译后，其实为：<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">class CRect<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">{<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: 10.5pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">&#8230;&#8230;<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: 10.5pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">public:<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt; text-indent: 10.5pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3"><span>&nbsp; </span>void setcolor(int color,(CRect*)this){this-&gt;m_color = color};<o:p></o:p></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 63pt;"><span style="font-family: 宋体;" lang="EN-US"><font size="3">};</font></span></p><img src ="http://www.cppblog.com/colys/aggbug/25381.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-06-03 15:07 <a href="http://www.cppblog.com/colys/articles/25381.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>根据路径创建不规则窗体</title><link>http://www.cppblog.com/colys/articles/24791.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Thu, 24 May 2007 15:08:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/24791.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/24791.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/24791.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/24791.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/24791.html</trackback:ping><description><![CDATA[<p>&nbsp;//根据路径创建不规则窗体<br>&nbsp;CDC* pDC;</p>
<p>&nbsp;pDC = this-&gt;GetDC();<br>&nbsp;::BeginPath(pDC-&gt;m_hDC);<br>&nbsp;<br>&nbsp;//设置为透明模式&nbsp;<br>&nbsp;::SetBkMode(pDC-&gt;m_hDC, TRANSPARENT);&nbsp;&nbsp;<br>&nbsp;//<br>&nbsp;RECT rect;<br>&nbsp;this-&gt;GetClientRect(&amp;rect);<br>&nbsp;/*三角型<br>&nbsp;int TopCenterPoint=rect.left + (rect.right - rect.left) /2;<br>&nbsp;pDC-&gt;MoveTo(TopCenterPoint, rect.top);<br>&nbsp;pDC-&gt;LineTo(rect.left, rect.bottom - GLOBAL_OVERLEN);<br>&nbsp;pDC-&gt;LineTo(rect.right, rect.bottom - GLOBAL_OVERLEN);<br>&nbsp;pDC-&gt;LineTo(TopCenterPoint,rect.top);<br>&nbsp;*/</p>
<p>&nbsp;/*比较奇怪的矩形<br>&nbsp;pDC-&gt;MoveTo(rect.left, rect.top);<br>&nbsp;pDC-&gt;LineTo(rect.right, rect.top);</p>
<p>&nbsp;pDC-&gt;LineTo(rect.right, rect.bottom - GLOBAL_OVERLEN);</p>
<p>&nbsp;pDC-&gt;LineTo(rect.left + (rect.right - rect.left) / 2, rect.bottom - GLOBAL_OVERLEN);<br>&nbsp;pDC-&gt;LineTo(rect.left + (rect.right - rect.left) / 2, rect.bottom);<br>&nbsp;pDC-&gt;LineTo(rect.left + (rect.right - rect.left) / 2 - GLOBAL_OVERWIDTH, rect.bottom - GLOBAL_OVERLEN);</p>
<p>&nbsp;pDC-&gt;LineTo(rect.left, rect.bottom - GLOBAL_OVERLEN);<br>&nbsp;pDC-&gt;LineTo(rect.left, rect.top);<br>&nbsp;*/<br>&nbsp;//<br>&nbsp;<br>&nbsp;::EndPath(pDC-&gt;m_hDC);<br>&nbsp;hRgn = ::PathToRegion(pDC-&gt;m_hDC);<br>&nbsp;this-&gt;SetWindowRgn(hRgn, TRUE);</p><img src ="http://www.cppblog.com/colys/aggbug/24791.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-05-24 23:08 <a href="http://www.cppblog.com/colys/articles/24791.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>读写磁盘文件专题</title><link>http://www.cppblog.com/colys/articles/24491.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Sun, 20 May 2007 15:11:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/24491.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/24491.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/24491.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/24491.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/24491.html</trackback:ping><description><![CDATA[<p align=left><span>在</span><span>Windows</span><span>平台上，读写磁盘文件是相当多应用程序经常会涉及到的一种功能。该主题涉及到采用</span><span>C/C++/MFC/Win32(API)</span><span>中提供的接口函数来操作磁盘文件的方法，以及其中需要注意的地方。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>=============================================================</span></p>
<p align=left><span><span>0.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>磁盘文件数据存储方式</span></p>
<p align=left><span>在介绍各种操作文件方式之前，需要先介绍磁盘上文件数据的组织方式。</span></p>
<p align=left><span>实际上，文件是在计算机内存中以二进制表示的数据在外部存储介质上的另一种存放形式。</span><strong><span>文件通常分为二进制文件和文本文件。</span></strong><span>二进制文件是包含在</span><span>ASCII</span><span>及扩展</span><span>ASCII</span><span>字符中编写的数据或程序指令的文件。一般是可执行文件</span><span>(Exe)</span><span>、图形、图像、声音等文件。而文本文件</span><span>(</span><span>通常也成为</span><span>ASCII</span><span>文件</span><span>)</span><span>，它的每一字节存放的是可表示为一个字符的</span><span>ASCII</span><span>代码的文件。这里把文件区分为二进制文件和文本文件，但实际上它们都是以二进制数据的方式来存储的。文本文件里所存储的每一个字节都可以转化为一个</span><span>可读</span><span>的字符。譬如</span><span>&#8217;</span><span>a</span><span>&#8217;</span><span>,</span><span>&#8217;</span><span>b</span><span>&#8217;</span><span>，</span><span>但在内存中并不会存储'</span><span>a'</span><span>, '</span><span>b'</span><span>，而是存储它们的</span><span>ASCII</span><span>码：</span><span>61</span><span>和</span><span>62</span><span>。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>C</span><span>语言对文件操作的支持</span></p>
<p align=left><span>在</span><span>C</span><span>语言中，对于文件的操作都是利用</span><span>FILE</span><span>结构体来进行的。包括文件的打开、文件的读写、文件的关闭、文件指针的定位等。</span></p>
<p align=left><span><span>(1)<span>&nbsp;&nbsp; </span></span></span><span>文件的打开</span></p>
<p align=left><span>文件的打开需要用</span><span>fopen</span><span>函数。该函数带</span><span>2</span><span>个参数，返回值为指向之前定义的</span><span>FILE</span><span>结构体指针。语法定义为</span></p>
<p align=left><span>FILE* fopen(const char* filename, const char* mod);</span></p>
<p align=left><span>参数</span><span>1</span><span>：表示要打开文件的完整路径，例如</span><span>: &#8220;C:\\Test\\Zero_Test.txt&#8221;.</span></p>
<p align=left><span>参数</span><span>2</span><span>：打开文件的方式。取值为下表所示。</span></p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=111>
            <p align=left><span>文件打开模式</span></p>
            </td>
            <td vAlign=top width=457>
            <p align=left><span>意义</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p align=left><span>r/rb</span></p>
            </td>
            <td vAlign=top width=457>
            <p align=left><span>为读取而打开。如果文件不存在或不能找到，函数调用失败。</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p align=left><span>w/wb</span></p>
            </td>
            <td vAlign=top width=457>
            <p align=left><span>为写入而打开一个空文件。如果给定的文件已经存在，则清空其内容。</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p align=left><span>a/ab</span></p>
            </td>
            <td vAlign=top width=457>
            <p align=left><span>为写入而打开一个文件。如果文件存在，则在文件尾部添加新数据，在写新数据之前不会移除原有的</span><span>EOF</span><span>标志。如果文件不存在，则新建一个空文件以待写入。</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p align=left><span>r+/rb+</span></p>
            </td>
            <td vAlign=top width=457>
            <p align=left><span>打开文件用于写入操作和读取操作，文件必须存在。</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p align=left><span>w+/wb+</span></p>
            </td>
            <td vAlign=top width=457>
            <p align=left><span>为写入操作和读取操作打开一个空文件。如果文件已经存在，则清空其内容。</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p align=left><span>a+/ab+</span></p>
            </td>
            <td vAlign=top width=457>
            <p align=left><span>打开文件用于读取操作和添加操作。并且添加操作在添加新数据之前会移除该文件中已有的</span><span>EOF</span><span>标志，然后当写入操作完成之后再恢复</span><span>EOF</span><span>标志。如果指定文件不存在，那么首先将新建一个文件。</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=left><span>在上表中，没有带</span><span>b</span><span>的模式表示打开的是文本文件，而带</span><span>b</span><span>的模式表示打开的是二进制文件。</span></p>
<p align=left><span>通常在定义结构</span><span>FILE</span><span>时会将其初始化为</span><span>NULL</span><span>。在打开文件将函数</span><span>fopen</span><span>的返回值赋值给它。之后需要判断文件是否成功打开，可采用如下方式：</span></p>
<p align=left><span>if ((pFile = fopen(&#8220;C:\\Test\\Zero_Test.txt&#8221;, &#8220;w&#8221;) == NULL)</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>Print(&#8220;Opening File Error.&#8221;);<span>&nbsp;&nbsp;&nbsp; </span>// FILE* pFile = NULL;</span></p>
<p align=left><span>else</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span></span><span>正常写入数据到文件</span><span>&#8230;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>（</span><span>2</span><span>）文件的关闭</span></p>
<p align=left><span>在使用完一个文件之后应该关闭它，以防止它再被误用。&#8220;关闭&#8221;就是使文件指针变量不再指向该文件，使其脱钩。函数使用方式</span><span>:</span></p>
<p align=left><span>fclose(pFile);</span></p>
<p align=left><span>需要注意的是</span><span>fclose</span><span>的参数必须是有效的文件指针变量，否则运行时会挂掉。</span></p>
<p align=left><span>应该养成在文件数据操作完成后关闭文件的习惯，如果不关闭文件将会丢失数据。同时，在向文件写数据时，是现将数据输出到缓冲区，待缓冲区充满后才正式输出给文件。如果程序运行结束而缓冲区并未充满，则缓冲区中的数据将会丢失。因此利用函数</span><span>fclose</span><span>来关闭文件可以避免这个问题。</span></p>
<p align=left><span>当然，还有另外一个函数</span><span>fflush</span><span>，也可以用来将缓冲区里的数据输出到文件中。函数调用方式</span><span>:</span></p>
<p align=left><span>fflush(pFile);</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>&nbsp;</span><span>（</span><span>3</span><span>）文件的读写</span></p>
<p align=left><span>当涉及到大量数据的读写时，可以采用函数</span><span>fread</span><span>和</span><span>fwrite</span><span>。</span><span>这两个函数通常用于二进制文件的读写。</span><span>函数调用方式如下：</span></p>
<p align=left><span>fread(buffer, size, count, fp);</span></p>
<p align=left><span>fwrite(buffer, size, count, fp);</span></p>
<p align=left><span>buffer</span><span>是一个指针，是用来存放数据的变量指针，例如内置类型变量的指针，结构体变量指针等。</span></p>
<p align=left><span>size</span><span>是要读写的字节数。</span><span>特别要注意的是，此处并不是数组的大小，结构体内变量的个数等。最好采用</span><span>sizeof</span><span>操作符来求得</span><span>buffer</span><span>的内存字节数。</span></p>
<p align=left><span>count</span><span>是</span><span>size</span><span>大小的重复次数。</span></p>
<p align=left><span>fp</span><span>是文件指针。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>对于这样的结构体：</span></p>
<p align=left><span>typedef struct {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>int clr_sel;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// color mode</span><span>的选择</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>int fixval_sel;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// fixed value</span><span>的选择</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>float thres_val;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// threshold value</span><span>的确定</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>float thres_scrlbar_pos;<span> </span>// threshold scroll bar</span><span>位置的确定</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>int method_sel;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// analysis method</span><span>的选择</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>int usediff_sel;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// use difference of MSA/TSE</span><span>方式的选择</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>int usescat_sel;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// use MSA/TSE of scatter signal </span><span>方式的选择</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>int remxtalk_sel;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// remove crosstalk </span><span>方式的选择</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>float timewin_scrlbar_pos;&nbsp;// time window scroll bar</span><span>位置的确定</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>int timewin_sel;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// time window</span><span>模式的选择</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>int freq_sel;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// frequency selection</span><span>模式的选择</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>int path_sel;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// path selection</span><span>模式的选择</span><span><span>&nbsp;&nbsp; </span></span></p>
<p align=left><span>} IMG_SETTINGS;</span><span><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>IMG_SETTINGS m_img_settings;</span></p>
<p align=left><span>文件读写操作时，可采用如下方式：</span></p>
<p align=left><span>fwrite(&amp;m_img_settings, sizeof(m_img_settings), 1, pwFile);</span></p>
<p align=left><span>fread(&amp;m_img_settings, sizeof(m_img_settings), 1, prFile);</span></p>
<p align=left><span>====================================================</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>如果想读写特定格式的文件，可采用</span><span>fprintf</span><span>和</span><span>fscanf</span><span>函数。</span><span>这两个函数通常是针对文本文件进行操作。</span></p>
<p align=left><span>函数调用方式如下：</span></p>
<p align=center><span>fprintf(pFile, &#8220;%d&#8230;&#8221;, i, j, k &#8230;);</span></p>
<p align=center><span>fscanf(pFile, &#8220;%d&#8230;&#8221;, i j, k&#8230;);</span></p>
<p align=left><span>格式化时可以规定读写数据的精度，类型，以及数据之间的分割符等。</span></p>
<p align=left><span>例如：</span></p>
<p align=left><span>fprintf(pFile, " %d %d %d %d %d %d %d %d \n", sigSize, samp_points, samp_rate,40, avrag_num, 0, 0, 0);</span></p>
<p align=left><span>fprintf(pFile, "%d %.2f %s %d %d %d %d \n", vpathdef[i].frequency1/1000,</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>vpathdef[i].amplitude, sig_type.c_str(),&nbsp;<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>psnset-&gt;sensorArray[vpathdef[i].actuator-1].channel-tol,</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>psnset-&gt;sensorArray[vpathdef[i].sensor-1].channel-tol,</span><span><span>&nbsp; </span>vpathdef[i].gain, 30);<span>&nbsp;&nbsp; </span></span></p>
<p align=left><span>特别需要注意的是，如果写入的数据的类型相同时，不可为了简便，将格式化的字符串写成如此形式</span><span>(.., &#8221;%d&#8221;,i,j,k&#8230;); // i,j,k&#8230;</span><span>同整型类型。</span></p>
<p align=left><span>如果这样操作的话，读写的数据便只有数据</span><span>i</span><span>了。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>最后针对一个面试题来对</span><span>C</span><span>语言操作文件的方式作一个总结</span><span>.</span></p>
<p align=left><span>面试题：给你一个整数，例如</span><span>12345</span><span>，将这个整数保存到文件中，要求在以记事本打开该文件时，显示的是</span><span>:12345</span><span>。</span></p>
<p align=left><span>给出三种代码：</span></p>
<p align=left><span><span>（1）<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>代码</span><span>1</span></p>
<p align=left><span>FILE* pwFile = NULL;</span></p>
<p align=left><span>pwFile = fopen(&#8220;c:\\Test.txt&#8221;, &#8220;w&#8221;);&nbsp;// create and open file with text mode.</span></p>
<p align=left><span>int i = 12345;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// However, write number with binary mode.</span></p>
<p align=left><span>fwrite(&amp;i, 4, 1, pwFile);<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// sizeof(int) = 4.</span></p>
<p align=left><span>fclose(fwFile);</span></p>
<p align=left><span>========================</span></p>
<p align=left><span><span>（2）<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>代码</span><span>2</span></p>
<p align=left><span>FILE* pwFile = NULL;</span></p>
<p align=left><span>pwFile = fopen(&#8220;c:\\Test.txt&#8221;, &#8220;w&#8221;);</span></p>
<p align=left><span>char ch[5] = {1+48, 2+48, 3+48, 4+48, 5+48 };</span></p>
<p align=left><span>fwrite(ch, 1, 5, pwFile);<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// sizeof(char) = 1, 5*sizeof(char) = 5</span></p>
<p align=left><span>fclose(pwFile);</span></p>
<p align=left><span>=======================</span></p>
<p align=left><span><span>（3）<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>代码</span><span>3</span></p>
<p align=left><span>FILE* pwFile = NULL;</span></p>
<p align=left><span>pwFile = fopen(&#8220;c:\\Test.txt&#8221;, &#8220;w&#8221;);</span></p>
<p align=left><span>int i = 12345;</span></p>
<p align=left><span>char ch[5];</span></p>
<p align=left><span>itoa(i, ch, 10);<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// transform int number to string</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>fwrite(ch, 1, 5, fwFile);</span></p>
<p align=left><span>fclose(pFile);</span></p>
<p align=left><span>==============================</span></p>
<p align=left><span><span>（4）<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>代码</span><span>4</span></p>
<p align=left><span>FILE* pwFile = NULL;</span></p>
<p align=left><span>pwFile = fopen(&#8220;c:\\Test.txt&#8221;, &#8220;w&#8221;);</span></p>
<p align=left><span>int i = 12345;</span></p>
<p align=left><span>fprintf(pwFile, &#8220;%d&#8221;, i);<span>&nbsp;&nbsp; </span>// write number with specified format.</span></p>
<p align=left><span>fclose(pwFile);</span></p>
<p align=left><span>==============================</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>将</span><span>4</span><span>种代码在</span><span>vc</span><span>中进行编译运行，可以发现<span>只有方式（</span></span><span>1</span><span>）不满足题目要求</span><span>。<br></span></p>
<br>to be continued...<br><img src ="http://www.cppblog.com/colys/aggbug/24491.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-05-20 23:11 <a href="http://www.cppblog.com/colys/articles/24491.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>菜单编程专题</title><link>http://www.cppblog.com/colys/articles/24487.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Sun, 20 May 2007 14:54:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/24487.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/24487.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/24487.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/24487.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/24487.html</trackback:ping><description><![CDATA[<p align=left><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>菜单响应的类顺序</span></p>
<p align=left><span>依次是视类、文档类、框架类，最后才是应用程序类。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Windows</span><span>消息的分类</span><span> </span></p>
<p align=left><span>实际上，菜单命令也是一种消息。在</span><span>Windows</span><span>中，消息分为以下</span><span>3</span><span>种：</span></p>
<p align=left><span><span>（1）<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>标准消息</span></p>
<p align=left><span>除了</span><span>WM_COMMAND</span><span>之外，所有以</span><span>WM_</span><span>开头的消息都是标准消息。从</span><span>CWnd</span><span>派生的类，都可以接收到该类消息。</span></p>
<p align=left><span><span>（2）<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>命令消息</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span></span><span>来自菜单、加速键或工具栏按钮的消息。这类消息都是以</span><span>WM_COMMAND</span><span>形式呈现。在</span><span>MFC</span><span>中，通过菜单项的标识</span><span>(ID)</span><span>来区分不同的命令消息；在</span><span>SDK</span><span>中，通过消息的</span><span>wParam</span><span>参数来标识。从</span><span>CCmdTarget</span><span>派生的类，都可以接收到这类消息。</span></p>
<p align=left><span><span>（3）<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>通告消息</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span></span><span>由控件产生的消息，例如按钮的单击、列表框的选择等都会产生这类消息，目的是为了向其父窗口通知事件的发生。这类消息也是以</span><span>WM_COMMAND</span><span>形式呈现的。从</span><span>CCmdTarget</span><span>派生的类，都可以接收到这类消息。</span></p>
<p align=left><span>由于</span><span>CWnd</span><span>是从</span><span>CCmdTarget</span><span>派生的，故从</span><span>CWnd</span><span>派生的类，它们既可以接收标准消息，也可以接收命令消息和通告消息。而对于那些从</span><span>CCmdTarget</span><span>派生的类，则只能接收命令消息和通告消息，不能接收标准消息。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>3.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>菜单命令消息路由的具体过程</span></p>
<p align=left><span>当点击某个菜单项时，最先接收到这个菜单命令消息的是框架类。框架类将把接收到的这个消息交给它的子窗口，即视类，由视类首先进行处理。视类首先根据命令消息映射机制查找自身是否对此消息进行了响应，如果响应了，就调用响应函数对这个消息进行处理，消息路由过程结束；如果视类没有对此命令消息做处响应，就交由文档类，文档类同样查找自身是否对这个菜单命令进行了响应，如果响应了，就由文档类的命令消息响应函数进行处理，路由过程结束。如果文档类也未做出响应，就把这个命令消息交还给视类，后者又把该消息交还给框架类。框架类查看自己是否对这个命令消息进行了响应，如果它也没有作处响应，就把这个菜单命令消息交换给应用程序类，由后者来进行处理。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>4.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>菜单操作</span></p>
<p align=left><span>要想获得某个菜单资源，需使用下面的函数调用：</span></p>
<p align=left><span>CMenu* GetMenu() const ;</span></p>
<p align=left><span>该函数调用者是</span><span>CWnd</span><span>的对象。返回值为</span><span>CMenu</span><span>类对象的指针。</span></p>
<p align=left><span>通过获得的菜单指针便可以获得其上的某个菜单栏的指针了。调用方式为：</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>CMenu* GetSubMenu(int nPos) const;</span></p>
<p align=left><span>调用者是菜单资源的类对象指针，或者是某个菜单栏的对象指针。</span></p>
<p align=left><span>如果某个菜单栏下面还有子菜单项，通过可以通过</span><span>GetSubMenu</span><span>函数来获得其子菜单项的操作指针。子菜单项的索引都是从</span><span>0</span><span>开始的，同时分割栏也是要占据索引值的。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>5.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>CASE</span><span>：</span></p>
<p align=left><span>在资源编辑器中编辑</span><span>Popup Menu</span><span>资源</span><span>: </span><span>IDR_SENSOR_DRAW_MENU</span><span>。</span></p>
<p align=left></p>
<p align=left><span>Grids Style</span><span>子菜单中的各个选项是相互排斥的。要求选择其中的一个时，需在其菜单前面标志选择它</span><span>&#8221;</span><span>&#183;</span><span>&#8221;</span><span>，其它都为为选中。也就是说</span><span>Style</span><span>中只能选中一个。</span></p>
<p align=left><span>可采用两种方式：</span></p>
<p align=left><span>（</span><span>1</span><span>）映射消息：</span><span>ON_WM_CONTEXTMENU()</span></p>
<p align=left><span>void ..::OnContextMenu(CWnd* /*pWnd*/, CPoint point)</span></p>
<p align=left><span>（</span><span>2</span><span>）映射消息：</span><span>ON_WM_RBUTTONDOWN()</span></p>
<p align=left><span>void ..::OnRightBtnDown(.. ..)</span></p>
<p align=left><span>响应函数实现代码：</span></p>
<p align=left><span>{</span></p>
<p align=left><span>CMenu menu;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>menu.LoadMenu(IDR_SENSOR_DRAW_MENU);&nbsp;// </span><span>装载菜单资源</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>CMenu* pMenu = menu.GetSubMenu(0);<span>&nbsp;&nbsp; </span>// </span><span>获得</span><span>Sensor Menu</span><span>菜单栏的对象指针</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>CMenu* pSubMenu = pMenu-&gt;GetSubMenu(0); // </span><span>获得</span><span>Grids Style</span><span>子菜单项的对象指针</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// </span><span>以此类推，如果是</span><span>Edit Structure</span><span>字菜单项的对象指针，参数应该是</span><span>1</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>int idxsel = 0;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>switch (m_GridStyle) {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>case GRIDSOFF:</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>idxsel = 0;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>break;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>case GRIDS10X:</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>idxsel = 2;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// separator is one resource, so take it into account.</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>break;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>case GRIDS20X:</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>idxsel = 3;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>break;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>case GRIDS30X:</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>idxsel = 4;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>break;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left><span>// Grids Style</span><span>子菜单项又有</span><span>N</span><span>个子菜单项，根据索引值位置来设置其状态。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>pSubMenu-&gt;CheckMenuRadioItem(0, 4, idxsel, MF_BYPOSITION);</strong></span></p>
<p align=left><strong><span>// </span></strong><span>如果是</span><span>WM_RBUTTONDOWN</span><span>响应，则需要调用函数</span><strong></strong></p>
<p align=left><span>ClientToScreen(&amp;point);&nbsp;// </span><span>将客户坐标转化为屏幕坐标。</span></p>
<p align=left><span>// </span><span>以下函数的参数</span><span>x,y</span><span>是屏幕坐标值。</span></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>pMenu-&gt;TrackPopupMenu(TPM_RIGHTBUTTON,point.x,point.y,this,NULL);</span></strong></p>
<p align=left><span>}</span></p><img src ="http://www.cppblog.com/colys/aggbug/24487.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-05-20 22:54 <a href="http://www.cppblog.com/colys/articles/24487.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中dll的lib文件和dll有什么不同？ </title><link>http://www.cppblog.com/colys/articles/24350.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Fri, 18 May 2007 14:08:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/24350.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/24350.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/24350.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/24350.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/24350.html</trackback:ping><description><![CDATA[dll是在你的程序运行的时候才连接的文件，因此它是一种比较小的可执行文件格式，.dll还有其他的文件格式如.ocx等，所有的.dll文件都是可执行。 <br>.lib是在你的程序编译连接的时候就连接的文件，因此你必须告知编译器连接的lib文件在那里。一般来说，与动态连接文件相对比，lib文件也被称为是静态连接库。当你把代码编译成这几种格式的文件时，在以后他们就不可能再被更改。 <br>如果你想使用lib文件，就必须：<br>1 包含一个对应的头文件告知编译器lib文件里面的具体内容<br>2 设置lib文件允许编译器去查找已经编译好的二进制代码 <br>如 果你想从你的代码分离一个dll文件出来代替静态连接库，仍然需要一个lib文件。这个lib文件将被连接到程序告诉操作系统在运行的时候你想用到什么 dll文件，一般情况下，lib文件里有相应的dll文件的名字和一个指明dll输出函数入口的顺序表。如果不想用lib文件或者是没有lib文件，可以 用WIN32 API函数LoadLibrary、GetProcAddress。事实上，我们可以在Visual C++ IDE中以二进制形式打开lib文件，大多情况下会看到ASCII码格式的C++函数或一些重载操作的函数名字。 <br>一般我们最主要的关于lib文件的麻烦就是出现unresolved symble 这类错误，这就是lib文件连接错误或者没有包含.c、.cpp文件到工程里，关键是如果在C++工程里用了C语言写的lib文件，就必需要这样包含：<br><font style="BACKGROUND-COLOR: rgb(211,211,211)">extern "C"<br>{<br>#include "myheader.h"<br>}<br></font>这是因为C语言写的lib文件没有C++所必须的名字破坏，C函数不能被重载，因此连接器会出错。<img src ="http://www.cppblog.com/colys/aggbug/24350.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-05-18 22:08 <a href="http://www.cppblog.com/colys/articles/24350.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用 C 语言编写 Windows 服务程序的五个步骤</title><link>http://www.cppblog.com/colys/articles/24238.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Wed, 16 May 2007 11:56:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/24238.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/24238.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/24238.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/24238.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/24238.html</trackback:ping><description><![CDATA[<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <p><strong>Author: Yevgeny Menaker</strong> <br><br><br><a href="http://www.cppblog.com/Files/colys/memorystatus.rar">下载代码</a><br>原文出处：<a href="http://www.devx.com/cplus/Article/9857/1954?pf=true" target=_blank>Five Steps to Writing Windows Services in C</a><br><br><strong>摘要</strong><br><br>　　Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务。为了学习这种控制台应用程序的基础知识，C（不是C++）是最佳选择。本文将建立并实现一个简单的服务程序，其功能是查询系统中可用物理内存数量，然后将结果写入一个文本文件。最后，你可以用所学知识编写自己的 Windows 服务。<br>　　当初我写第一个 NT 服务时，我到 MSDN 上找例子。在那里我找到了一篇 Nigel Thompson 写的文章：&#8220;<a href="http://www.vckbase.com/document/viewdoc/?id=1447" target=_blank><u><font color=#0000ff>Creating a Simple Win32 Service in C++</font></u></a>&#8221;，这篇文章附带一个 C++ 例子。虽然这篇文章很好地解释了服务的开发过程，但是，我仍然感觉缺少我需要的重要信息。我想理解通过什么框架，调用什么函数，以及何时调用，但 C++ 在这方面没有让我轻松多少。面向对象的方法固然方便，但由于用类对底层 Win32 函数调用进行了封装，它不利于学习服务程序的基本知识。这就是为什么我觉得 C 更加适合于编写初级服务程序或者实现简单后台任务的服务。在你对服务程序有了充分透彻的理解之后，用 C++ 编写才能游刃有余。当我离开原来的工作岗位，不得不向另一个人转移我的知识的时候，利用我用 C 所写的例子就非常容易解释 NT 服务之所以然。<br>　　服务是一个运行在后台并实现勿需用户交互的任务的控制台程序。Windows NT/2000/XP 操作系统提供为服务程序提供专门的支持。人们可以用服务控制面板来配置安装好的服务程序，也就是 Windows 2000/XP 控制面板|管理工具中的&#8220;服务&#8221;（或在&#8220;开始&#8221;|&#8220;运行&#8221;对话框中输入 services.msc /s——译者注）。可以将服务配置成操作系统启动时自动启动，这样你就不必每次再重启系统后还要手动启动服务。<br>　　本文将首先解释如何创建一个定期查询可用物理内存并将结果写入某个文本文件的服务。然后指导你完成生成，安装和实现服务的整个过程。<br><br><br><strong>第一步：主函数和全局定义</strong><br><br>首先，包含所需的头文件。例子要调用 Win32 函数（windows.h）和磁盘文件写入（stdio.h）：</p>
            <pre>#include &lt;windows.h&gt;
            #include &lt;stdio.h&gt;</pre>
            <p>接着，定义两个常量：</p>
            <pre>#define SLEEP_TIME 5000
            #define LOGFILE "C:\\MyServices\\memstatus.txt"</pre>
            <p>SLEEP_TIME 指定两次连续查询可用内存之间的毫秒间隔。在第二步中编写服务工作循环的时候要使用该常量。<br>LOGFILE 定义日志文件的路径，你将会用 WriteToLog 函数将内存查询的结果输出到该文件，WriteToLog 函数定义如下：</p>
            <pre>int WriteToLog(char* str)
            {
            FILE* log;
            log = fopen(LOGFILE, "a+");
            if (log == NULL)
            return -1;
            fprintf(log, "%s\n", str);
            fclose(log);
            return 0;
            }</pre>
            <p>声明几个全局变量，以便在程序的多个函数之间共享它们值。此外，做一个函数的前向定义：</p>
            <pre>SERVICE_STATUS ServiceStatus;
            SERVICE_STATUS_HANDLE hStatus;
            void ServiceMain(int argc, char** argv);
            void ControlHandler(DWORD request);
            int InitService();</pre>
            <p>　　现在，准备工作已经就绪，你可以开始编码了。服务程序控制台程序的一个子集。因此，开始你可以定义一个 main 函数，它是程序的入口点。对于服务程序来说，main 的代码令人惊讶地简短，因为它只创建分派表并启动控制分派机。</p>
            <pre>void main()
            {
            SERVICE_TABLE_ENTRY ServiceTable[2];
            ServiceTable[0].lpServiceName = "MemoryStatus";
            ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
            ServiceTable[1].lpServiceName = NULL;
            ServiceTable[1].lpServiceProc = NULL;
            // 启动服务的控制分派机线程
            StartServiceCtrlDispatcher(ServiceTable);
            }</pre>
            <p>　　一个程序可能包含若干个服务。每一个服务都必须列于专门的分派表中（为此该程序定义了一个 ServiceTable 结构数组）。这个表中的每一项都要在 SERVICE_TABLE_ENTRY 结构之中。它有两个域：</p>
            <ul>
                <li>lpServiceName: 指向表示服务名称字符串的指针；当定义了多个服务时，那么这个域必须指定；
                <li>lpServiceProc: 指向服务主函数的指针（服务入口点）； </li>
            </ul>
            <p>　　分派表的最后一项必须是服务名和服务主函数域的 NULL 指针，文本例子程序中只宿主一个服务，所以服务名的定义是可选的。<br>　　服务控制管理器（SCM：Services Control Manager）是一个管理系统所有服务的进程。当 SCM 启动某个服务时，它等待某个进程的主线程来调用 StartServiceCtrlDispatcher 函数。将分派表传递给 StartServiceCtrlDispatcher。这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程，该线程运行分派表中每个服务的 ServiceMain 函数（本文例子中只有一个服务）分派器还监视程序中所有服务的执行情况。然后分派器将控制请求从 SCM 传给服务。<br><br>注意：如果 StartServiceCtrlDispatcher 函数30秒没有被调用，便会报错，为了避免这种情况，我们必须在 ServiceMain 函数中（参见本文例子）或在非主函数的单独线程中初始化服务分派表。本文所描述的服务不需要防范这样的情况。<br><br>　　分派表中所有的服务执行完之后（例如，用户通过&#8220;服务&#8221;控制面板程序停止它们），或者发生错误时。StartServiceCtrlDispatcher 调用返回。然后主进程终止。<br><br><br><strong>第二步：ServiceMain 函数</strong><br><br>　　<a href="http://www.vckbase.com/document/journal/vckbase42/figures/5step_listing1.txt" target=_blank><u><font color=#0000ff>Listing 1</font></u></a> 展示了 ServiceMain 的代码。该函数是服务的入口点。它运行在一个单独的线程当中，这个线程是由控制分派器创建的。ServiceMain 应该尽可能早早为服务注册控制处理器。这要通过调用 RegisterServiceCtrlHadler 函数来实现。你要将两个参数传递给此函数：服务名和指向 ControlHandlerfunction 的指针。<br>　　它指示控制分派器调用 ControlHandler 函数处理 SCM 控制请求。注册完控制处理器之后，获得状态句柄（hStatus）。通过调用 SetServiceStatus 函数，用 hStatus 向 SCM 报告服务的状态。<br><a href="http://www.vckbase.com/document/journal/vckbase42/figures/5step_listing1.txt" target=_blank><u><font color=#0000ff>Listing 1</font></u></a> 展示了如何指定服务特征和其当前状态来初始化 ServiceStatus 结构，ServiceStatus 结构的每个域都有其用途：
            <ul>
                <li>dwServiceType：指示服务类型，创建 Win32 服务。赋值 SERVICE_WIN32；
                <li>dwCurrentState：指定服务的当前状态。因为服务的初始化在这里没有完成，所以这里的状态为 SERVICE_START_PENDING；
                <li>dwControlsAccepted：这个域通知 SCM 服务接受哪个域。本文例子是允许 STOP 和 SHUTDOWN 请求。处理控制请求将在第三步讨论；
                <li>dwWin32ExitCode 和 dwServiceSpecificExitCode：这两个域在你终止服务并报告退出细节时很有用。初始化服务时并不退出，因此，它们的值为 0；
                <li>dwCheckPoint 和 dwWaitHint：这两个域表示初始化某个服务进程时要30秒以上。本文例子服务的初始化过程很短，所以这两个域的值都为 0。 </li>
            </ul>
            <p>　　调用 SetServiceStatus 函数向 SCM 报告服务的状态时。要提供 hStatus 句柄和 ServiceStatus 结构。注意 ServiceStatus 一个全局变量，所以你可以跨多个函数使用它。ServiceMain 函数中，你给结构的几个域赋值，它们在服务运行的整个过程中都保持不变，比如：dwServiceType。<br>　　在报告了服务状态之后，你可以调用 InitService 函数来完成初始化。这个函数只是添加一个说明性字符串到日志文件。如下面代码所示：</p>
            <pre>// 服务初始化
            int InitService()
            {
            int result;
            result = WriteToLog("Monitoring started.");
            return(result);
            }</pre>
            <p>　　在 ServiceMain 中，检查 InitService 函数的返回值。如果初始化有错（因为有可能写日志文件失败），则将服务状态置为终止并退出 ServiceMain：</p>
            <pre>error = InitService();
            if (error)
            {
            // 初始化失败，终止服务
            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            ServiceStatus.dwWin32ExitCode = -1;
            SetServiceStatus(hStatus, &amp;ServiceStatus);
            // 退出 ServiceMain
            return;
            }</pre>
            <p>如果初始化成功，则向 SCM 报告状态：</p>
            <pre>// 向 SCM 报告运行状态
            ServiceStatus.dwCurrentState = SERVICE_RUNNING;
            SetServiceStatus (hStatus, &amp;ServiceStatus);</pre>
            <p>接着，启动工作循环。每五秒钟查询一个可用物理内存并将结果写入日志文件。<br><br>如 <a href="http://www.vckbase.com/document/journal/vckbase42/figures/5step_listing1.txt" target=_blank><u><font color=#0000ff>Listing 1</font></u></a> 所示，循环一直到服务的状态为 SERVICE_RUNNING 或日志文件写入出错为止。状态可能在 ControlHandler 函数响应 SCM 控制请求时修改。<br>&nbsp;<br><br><strong>第三步：处理控制请求</strong><br><br>　　在第二步中，你用 ServiceMain 函数注册了控制处理器函数。控制处理器与处理各种 Windows 消息的窗口回调函数非常类似。它检查 SCM 发送了什么请求并采取相应行动。<br>　　每次你调用 SetServiceStatus 函数的时候，必须指定服务接收 STOP 和 SHUTDOWN 请求。<a href="http://www.vckbase.com/document/journal/vckbase42/figures/5step_listing2.txt" target=_blank><u><font color=#0000ff>Listing 2</font></u></a> 示范了如何在 ControlHandler 函数中处理它们。<br>　　STOP 请求是 SCM 终止服务的时候发送的。例如，如果用户在&#8220;服务&#8221;控制面板中手动终止服务。SHUTDOWN 请求是关闭机器时，由 SCM 发送给所有运行中服务的请求。两种情况的处理方式相同：</p>
            <ul>
                <li>写日志文件，监视停止；
                <li>向 SCM 报告 SERVICE_STOPPED 状态； </li>
            </ul>
            <p>　　由于 ServiceStatus 结构对于整个程序而言为全局量，ServiceStatus 中的工作循环在当前状态改变或服务终止后停止。其它的控制请求如：PAUSE 和 CONTINUE 在本文的例子没有处理。<br>　　控制处理器函数必须报告服务状态，即便 SCM 每次发送控制请求的时候状态保持相同。因此，不管响应什么请求，都要调用 SetServiceStatus。<br><br><img height=452 src="http://www.vckbase.com/document/journal/vckbase42/images/5stepsimg1.gif" width=690 border=0><br>图一 显示 MemoryStatus 服务的服务控制面板<br><br><br><strong>第四步：安装和配置服务</strong><br><br>　　程序编好了，将之编译成 exe 文件。本文例子创建的文件叫 MemoryStatus.exe，将它拷贝到 C:\MyServices 文件夹。为了在机器上安装这个服务，需要用 SC.EXE 可执行文件，它是 Win32 Platform SDK 中附带的一个工具。（译者注：Visaul Studio .NET 2003 IDE 环境中也有这个工具，具体存放位置在：C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\Bin\winnt）。使用这个实用工具可以安装和移除服务。其它控制操作将通过服务控制面板来完成。以下是用命令行安装 MemoryStatus 服务的方法：</p>
            <pre>sc create MemoryStatus binpath= c:\MyServices\MemoryStatus.exe</pre>
            <p>　　发出此创建命令。指定服务名和二进制文件的路径（注意 binpath= 和路径之间的那个空格）。安装成功后，便可以用服务控制面板来控制这个服务（参见图一）。用控制面板的工具栏启动和终止这个服务。<br><br><img height=550 src="http://www.vckbase.com/document/journal/vckbase42/images/5stepsimg2.gif" width=542 border=0><br>图二 MemoryStatus 服务的属性窗口<br><br>　　MemoryStatus 的启动类型是手动，也就是说根据需要来启动这个服务。右键单击该服务，然后选择上下文菜单中的&#8220;属性&#8221;菜单项，此时显示该服务的属性窗口。在这里可以修改启动类型以及其它设置。你还可以从&#8220;常规&#8221;标签中启动/停止服务。以下是从系统中移除服务的方法：</p>
            <pre>sc delete MemoryStatus</pre>
            <p>指定 &#8220;delete&#8221; 选项和服务名。此服务将被标记为删除，下次西通重启后，该服务将被完全移除。<br><br><br><strong>第五步：测试服务</strong><br><br>　　从服务控制面板启动 MemoryStatus 服务。如果初始化不出错，表示启动成功。过一会儿将服务停止。检查一下 C:\MyServices 文件夹中 memstatus.txt 文件的服务输出。在我的机器上输出是这样的：</p>
            <pre>Monitoring started.
            273469440
            273379328
            273133568
            273084416
            Monitoring stopped.</pre>
            <p>　　为了测试 MemoryStatus 服务在出错情况下的行为，可以将 memstatus.txt 文件设置成只读。这样一来，服务应该无法启动。<br>　　去掉只读属性，启动服务，在将文件设成只读。服务将停止执行，因为此时日志文件写入失败。如果你更新服务控制面板的内容，会发现服务状态是已经停止。<br>&nbsp;<br><br><strong>开发更大更好的服务程序</strong><br><br>　　理解 Win32 服务的基本概念，使你能更好地用 C++ 来设计包装类。包装类隐藏了对底层 Win32 函数的调用并提供了一种舒适的通用接口。修改 MemoryStatus 程序代码，创建满足自己需要的服务！为了实现比本文例子所示范的更复杂的任务，你可以创建多线程的服务，将作业划分成几个工作者线程并从 ServiceMain 函数中监视它们的执行。<br>　</p>
            </td>
        </tr>
        <tr>
            <td><img src="http://www.vckbase.com/image/paragraph.gif"> <strong>作者简介</strong><br>　　　　<strong>Yevgeny Menaker</strong> 是一名有着超过5年经验开发人员，作家和 Linux 顾问。过去的三年，Yevgeny 专注于开发新的高级的 Internet 技术。他牵头编写了《Programming Perl in the .NET Environment》一书（Prentice-Hall）。此外，作为 Linux 顾问，他还在 Object Innovations 任职。Yevgeny Menaker 的联系方式是：jeka_books@hotmail.com</td>
        </tr>
    </tbody>
</table><img src ="http://www.cppblog.com/colys/aggbug/24238.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-05-16 19:56 <a href="http://www.cppblog.com/colys/articles/24238.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>窗口全屏代码</title><link>http://www.cppblog.com/colys/articles/24174.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Tue, 15 May 2007 14:48:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/24174.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/24174.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/24174.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/24174.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/24174.html</trackback:ping><description><![CDATA[<p>&nbsp;全屏</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">&nbsp;CMDIChildWnd</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;pChild</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">MDIGetActive();<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">pChild)&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;m_bToolBarWasVisible</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(m_wndToolBar.IsWindowVisible()</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;m_wndToolBar.ShowWindow(SW_HIDE);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">隐藏工具栏</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;m_bStatusBarWasVisible</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(m_wndStatusBar.IsWindowVisible()</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;m_wndStatusBar.ShowWindow(SW_HIDE);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">隐藏状态栏<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #008000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;first&nbsp;create&nbsp;the&nbsp;new&nbsp;toolbar<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #008000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;this&nbsp;will&nbsp;contain&nbsp;the&nbsp;full-screen&nbsp;off&nbsp;button</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;m_pwndFullScreenBar</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;CToolBar;<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;m_pwndFullScreenBar</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Create(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;m_pwndFullScreenBar</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">LoadToolBar(IDR_FULLSCREEN);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">显示退出全屏工具栏</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;m_pwndFullScreenBar</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">SetBarStyle(m_pwndFullScreenBar</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">GetBarStyle()&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;CBRS_TOOLTIPS&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;CBRS_FLYBY&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;CBRS_SIZE_DYNAMIC);<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;to&nbsp;look&nbsp;better:</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;m_pwndFullScreenBar</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ModifyStyle(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;TBSTYLE_FLAT);<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">&nbsp;m_pwndFullScreenBar</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">EnableDocking(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;place&nbsp;the&nbsp;full-screen&nbsp;off&nbsp;button&nbsp;somewhere:</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;CPoint&nbsp;pt(</span><span style="COLOR: #000000">300</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">200</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #000000">&nbsp;FloatControlBar(m_pwndFullScreenBar,pt);<br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000">&nbsp;<br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;now&nbsp;save&nbsp;the&nbsp;old&nbsp;positions&nbsp;of&nbsp;the&nbsp;main&nbsp;and&nbsp;child&nbsp;windows</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;GetWindowRect(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">m_mainRect);<br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;remove&nbsp;the&nbsp;caption&nbsp;of&nbsp;the&nbsp;mainWnd:</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">28</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;LONG&nbsp;style</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">::GetWindowLong(m_hWnd,GWL_STYLE);<br></span><span style="COLOR: #008080">29</span>&nbsp;<span style="COLOR: #000000">&nbsp;style</span><span style="COLOR: #000000">&amp;=~</span><span style="COLOR: #000000">WS_CAPTION;<br></span><span style="COLOR: #008080">30</span>&nbsp;<span style="COLOR: #000000">&nbsp;::SetWindowLong(m_hWnd,GWL_STYLE,style);<br></span><span style="COLOR: #008080">31</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;screenx</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">GetSystemMetrics(SM_CXSCREEN);<br></span><span style="COLOR: #008080">32</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;screeny</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">GetSystemMetrics(SM_CYSCREEN);<br></span><span style="COLOR: #008080">33</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">34</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;resize:</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">35</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;SetWindowPos(NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,screenx,screeny,SWP_NOZORDER);<br></span><span style="COLOR: #008080">36</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">SetWindowPos(NULL,-5,-5,80,80,SWP_NOZORDER);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">37</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;style</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">::GetWindowLong(pChild</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_hWnd,GWL_STYLE);<br></span><span style="COLOR: #008080">38</span>&nbsp;<span style="COLOR: #000000">&nbsp;m_bChildMax</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(style&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;WS_MAXIMIZE)</span><span style="COLOR: #000000">?</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">:</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">39</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;note&nbsp;here:&nbsp;m_bMainMax&nbsp;is&nbsp;not&nbsp;needed&nbsp;since&nbsp;m_hWnd&nbsp;only<br></span><span style="COLOR: #008080">40</span>&nbsp;<span style="COLOR: #008000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;changed&nbsp;its&nbsp;caption<img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">41</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">///</span><span style="COLOR: #008000">***************</span><span style="COLOR: #808080"><br></span><span style="COLOR: #008080">42</span>&nbsp;<span style="COLOR: #808080"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">43</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Save&nbsp;the&nbsp;Original&nbsp;Menu&nbsp;and&nbsp;set&nbsp;menu&nbsp;to&nbsp;NULL</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">44</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;ASSERT(m_OrgMenu.GetSafeHmenu()</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">NULL);<br></span><span style="COLOR: #008080">45</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;CMenu</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;pOldMenu</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">GetMenu();<br></span><span style="COLOR: #008080">46</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;m_OrgMenu.Attach(pOldMenu</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Detach());<br></span><span style="COLOR: #008080">47</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;SetMenu((CMenu</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)NULL);<br></span><span style="COLOR: #008080">48</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">49</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">************<br></span><span style="COLOR: #008080">50</span>&nbsp;<span style="COLOR: #008000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;and&nbsp;maximize&nbsp;the&nbsp;child&nbsp;window<br></span><span style="COLOR: #008080">51</span>&nbsp;<span style="COLOR: #008000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;it&nbsp;will&nbsp;remove&nbsp;its&nbsp;caption,&nbsp;too.<br></span><span style="COLOR: #008080">52</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">pChild-&gt;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">53</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ShowWindow&nbsp;(SW_SHOWMAXIMIZED);<br></span><span style="COLOR: #008080">54</span>&nbsp;<span style="COLOR: #000000">&nbsp;style</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">::GetWindowLong(pChild</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_hWnd,GWL_STYLE);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">获得窗口风格</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">55</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;style</span><span style="COLOR: #000000">&amp;=~</span><span style="COLOR: #000000">WS_CAPTION;<br></span><span style="COLOR: #008080">56</span>&nbsp;<span style="COLOR: #000000">&nbsp;::SetWindowLong(pChild</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_hWnd,GWL_STYLE,style);&nbsp;<br></span><span style="COLOR: #008080">57</span>&nbsp;<span style="COLOR: #000000">&nbsp;pChild</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ShowWindow(SW_SHOWMAXIMIZED);<br></span><span style="COLOR: #008080">58</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">59</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">RecalcLayout();</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">60</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;<br></span><span style="COLOR: #008080">61</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">62</span>&nbsp;<span style="COLOR: #000000"></span></div>
<br>退出全屏<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">ASSERT(m_OrgMenu.GetSafeHmenu()</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">NULL);<br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;SetMenu(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">m_OrgMenu);<br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;m_OrgMenu.Detach();<br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;You&nbsp;can&nbsp;use&nbsp;SaveBarState()&nbsp;in&nbsp;OnClose(),<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;so&nbsp;remove&nbsp;the&nbsp;newly&nbsp;added&nbsp;toolbar&nbsp;entirely<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;in&nbsp;order&nbsp;SaveBarState()&nbsp;not<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;to&nbsp;save&nbsp;its&nbsp;state.&nbsp;That&nbsp;is&nbsp;why&nbsp;I&nbsp;used&nbsp;dynamic<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;allocation</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">10</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;m_pwndFullScreenBar;<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;LONG&nbsp;style</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">::GetWindowLong(m_hWnd,GWL_STYLE);<br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;style</span><span style="COLOR: #000000">|=</span><span style="COLOR: #000000">WS_CAPTION;<br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;::SetWindowLong(m_hWnd,GWL_STYLE,style);<br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(m_bToolBarWasVisible)<br></span><span style="COLOR: #008080">15</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_wndToolBar.ShowWindow(SW_SHOW);<br></span><span style="COLOR: #008080">16</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(m_bStatusBarWasVisible)<br></span><span style="COLOR: #008080">17</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_wndStatusBar.ShowWindow(SW_SHOW);<br></span><span style="COLOR: #008080">18</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;MoveWindow(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">m_mainRect);<br></span><span style="COLOR: #008080">19</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;RecalcLayout();<br></span><span style="COLOR: #008080">20</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;CMDIChildWnd</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;pChild</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">MDIGetActive();<br></span><span style="COLOR: #008080">21</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br></span><span style="COLOR: #008080">22</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;style</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">::GetWindowLong(pChild</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_hWnd,GWL_STYLE);<br></span><span style="COLOR: #008080">23</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;style</span><span style="COLOR: #000000">|=</span><span style="COLOR: #000000">WS_CAPTION;<br></span><span style="COLOR: #008080">24</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;::SetWindowLong(pChild</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_hWnd,GWL_STYLE,style);<br></span><span style="COLOR: #008080">25</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;pchild&nbsp;can&nbsp;be&nbsp;NULL&nbsp;if&nbsp;the&nbsp;USER&nbsp;closed&nbsp;all&nbsp;the<br></span><span style="COLOR: #008080">26</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;childs&nbsp;during&nbsp;Full&nbsp;Screen&nbsp;Mode:</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">27</span><span style="COLOR: #008000"><img id=Codehighlighter1_844_916_Open_Image onclick="this.style.display='none'; Codehighlighter1_844_916_Open_Text.style.display='none'; Codehighlighter1_844_916_Closed_Image.style.display='inline'; Codehighlighter1_844_916_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_844_916_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_844_916_Closed_Text.style.display='none'; Codehighlighter1_844_916_Open_Image.style.display='inline'; Codehighlighter1_844_916_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(pChild)</span><span id=Codehighlighter1_844_916_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_844_916_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">28</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(m_bChildMax)<br></span><span style="COLOR: #008080">29</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MDIMaximize(pChild);<br></span><span style="COLOR: #008080">30</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;MDIRestore(pChild);<br></span><span style="COLOR: #008080">31</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div><img src ="http://www.cppblog.com/colys/aggbug/24174.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-05-15 22:48 <a href="http://www.cppblog.com/colys/articles/24174.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用C++控制DVD/CD驱动器的开关</title><link>http://www.cppblog.com/colys/articles/24113.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Mon, 14 May 2007 13:51:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/24113.html</guid><description><![CDATA[在Windows资源浏览器中，可在DVD/CD光驱图标上单击鼠标右键，选择"弹出"来打开光驱仓门，你可能也发现了，菜单中并没有"关闭"命令来关闭光驱。下面，就让我们用程序来控制打开、关闭光驱。 <br><br>　　程序的主要工作部分为CD_OpenClose(BOOL bOpen, TCHAR cDrive)函数：<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #008000">//</span><span style="COLOR: #008000">cDrive是光驱盘符，或者0x01为默认驱动器。<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">例如：<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">CD_OpenCloseDrive(TRUE,&nbsp;'G');&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">打开光驱G:<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">CD_OpenCloseDrive(FALSE,&nbsp;'G');&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">关闭光驱G:<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">CD_OpenCloseDrive(TRUE,&nbsp;1);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">打开第一个逻辑光驱</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;CD_OpenCloseDrive(BOOL&nbsp;bOpenDrive,&nbsp;TCHAR&nbsp;cDrive)<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">　MCI_OPEN_PARMS&nbsp;op;<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">　MCI_STATUS_PARMS&nbsp;st;<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">　DWORD&nbsp;flags;<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">　TCHAR&nbsp;szDriveName[</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">];<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">　strcpy(szDriveName,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">X:</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">　::ZeroMemory(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">op,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(MCI_OPEN_PARMS));<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">　op.lpstrDeviceType&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(LPCSTR)&nbsp;MCI_DEVTYPE_CD_AUDIO;<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">　</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(cDrive&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">　{<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">　　szDriveName[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;cDrive;<br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #000000">　　op.lpstrElementName&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;szDriveName;<br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000">　　flags&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MCI_OPEN_TYPE&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;MCI_OPEN_TYPE_ID&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;MCI_OPEN_ELEMENT</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;MCI_OPEN_SHAREABLE;<br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">　}<br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #000000">　</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;flags&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MCI_OPEN_TYPE&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;MCI_OPEN_TYPE_ID&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;MCI_OPEN_SHAREABLE;<br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #000000">　</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">mciSendCommand(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,MCI_OPEN,flags,(unsigned&nbsp;</span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">op))<br></span><span style="COLOR: #008080">28</span>&nbsp;<span style="COLOR: #000000">　{<br></span><span style="COLOR: #008080">29</span>&nbsp;<span style="COLOR: #000000">　　st.dwItem&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MCI_STATUS_READY;<br></span><span style="COLOR: #008080">30</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">31</span>&nbsp;<span style="COLOR: #000000">　　</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(bOpenDrive)<br></span><span style="COLOR: #008080">32</span>&nbsp;<span style="COLOR: #000000">　　　mciSendCommand(op.wDeviceID,MCI_SET,MCI_SET_DOOR_OPEN,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">33</span>&nbsp;<span style="COLOR: #000000">　　</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">34</span>&nbsp;<span style="COLOR: #000000">　　　mciSendCommand(op.wDeviceID,MCI_SET,MCI_SET_DOOR_CLOSED,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">35</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">36</span>&nbsp;<span style="COLOR: #000000">　　mciSendCommand(op.wDeviceID,MCI_CLOSE,MCI_WAIT,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">37</span>&nbsp;<span style="COLOR: #000000">　}<br></span><span style="COLOR: #008080">38</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<br><br>　为了方便对多个光驱进行操作，添加了下面这个函数，其会调用上面的CD_OpenCloseDrive()函数：<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;CD_OpenCloseAllDrives(BOOL&nbsp;bOpenDrives)<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">　</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">判定所有光驱，并逐个打开或关闭。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nPos&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">　UINT&nbsp;nCount&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">　TCHAR&nbsp;szDrive[</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">];<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">　strcpy(szDrive,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">?:</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">　DWORD&nbsp;dwDriveList&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;::GetLogicalDrives&nbsp;();<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">　</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(dwDriveList)&nbsp;{<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">　　</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(dwDriveList&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">　　{<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">　　　szDrive[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0x41</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;nPos;<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">　　　</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(::GetDriveType(szDrive)&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;DRIVE_CDROM)<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">　　　　CD_OpenCloseDrive(bOpenDrives,&nbsp;szDrive[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">]);<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">　　}<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">　　dwDriveList&nbsp;</span><span style="COLOR: #000000">&gt;&gt;=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">　　nPos</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">　}<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<br>　最后一点，别忘了在程序开头包括Mmsystem.h头文件，及在链接选项里写上Winmm.lib。<br><img src ="http://www.cppblog.com/colys/aggbug/24113.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-05-14 21:51 <a href="http://www.cppblog.com/colys/articles/24113.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>进制介绍</title><link>http://www.cppblog.com/colys/articles/22816.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Wed, 25 Apr 2007 11:35:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/22816.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/22816.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/22816.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/22816.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/22816.html</trackback:ping><description><![CDATA[<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">1</span><span style="color: #000000;">.&nbsp;十进制数<br>十进制数的两个主要特点：<br><br>⑴有十个不同的数字：</span><span style="color: #000000;">0</span><span style="color: #000000;">、</span><span style="color: #000000;">1</span><span style="color: #000000;">、</span><span style="color: #000000;">2</span><span style="color: #000000;">、</span><span style="color: #000000;">3</span><span style="color: #000000;">、</span><span style="color: #000000;">4</span><span style="color: #000000;">、</span><span style="color: #000000;">5</span><span style="color: #000000;">、</span><span style="color: #000000;">6</span><span style="color: #000000;">、</span><span style="color: #000000;">7</span><span style="color: #000000;">、</span><span style="color: #000000;">8</span><span style="color: #000000;">、</span><span style="color: #000000;">9</span><span style="color: #000000;">;<br><br>⑵逢十进一的进位法,10是十进制数的基数(进制中所用不同数字的个数)。<br><br>(</span><span style="color: #000000;">1993</span><span style="color: #000000;">)</span><span style="color: #000000;">10</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">10<sup>3</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">9</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">10<sup>2</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">9</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">10<sup>1</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">3</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">10<sup>0</sup></span><span style="color: #000000;">(每位上的系数只在0—9中取用)<br><br></span><span style="color: #000000;">2</span><span style="color: #000000;">.&nbsp;二进制数<br>二进制数的两个主要特点：<br><br>⑴有两个不同的数字：</span><span style="color: #000000;">0</span><span style="color: #000000;">、</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br><br>⑵逢二进一的进位法,2是二进制数的基数。<br><br>(</span><span style="color: #000000;">1011</span><span style="color: #000000;">)</span><span style="color: #000000;">2</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">2<sup>3</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">0</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">2<sup>2</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">2<sup>1</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">2<sup>0</sup></span><span style="color: #000000;">(每位上的系数只在0、1中取用)<br><br></span><span style="color: #000000;">3</span><span style="color: #000000;">.&nbsp;八进制数<br>八进制数的两个主要特点：<br><br>⑴采用八个不同的数字：</span><span style="color: #000000;">0</span><span style="color: #000000;">、</span><span style="color: #000000;">1</span><span style="color: #000000;">、</span><span style="color: #000000;">2</span><span style="color: #000000;">、</span><span style="color: #000000;">3</span><span style="color: #000000;">、</span><span style="color: #000000;">4</span><span style="color: #000000;">、</span><span style="color: #000000;">5</span><span style="color: #000000;">、</span><span style="color: #000000;">6</span><span style="color: #000000;">、</span><span style="color: #000000;">7</span><span style="color: #000000;">;<br><br>⑵逢八进一的进位法,8是八进制数的基数。<br><br>(</span><span style="color: #000000;">1725</span><span style="color: #000000;">)</span><span style="color: #000000;">8</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">8<sup>3</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">7</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">8<sup>2</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">2</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">8<sup>1</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">5</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">8<sup>0</sup></span><span style="color: #000000;">(每位上的系数只在0—7中取用)<br><br></span><span style="color: #000000;">4</span><span style="color: #000000;">.&nbsp;十六进制<br>十六进制数的两个主要特点：<br><br>⑴有十六个不同的数字：</span><span style="color: #000000;">0</span><span style="color: #000000;">、</span><span style="color: #000000;">1</span><span style="color: #000000;">、</span><span style="color: #000000;">2</span><span style="color: #000000;">、</span><span style="color: #000000;">3</span><span style="color: #000000;">、</span><span style="color: #000000;">4</span><span style="color: #000000;">、</span><span style="color: #000000;">5</span><span style="color: #000000;">、</span><span style="color: #000000;">6</span><span style="color: #000000;">、</span><span style="color: #000000;">7</span><span style="color: #000000;">、</span><span style="color: #000000;">8</span><span style="color: #000000;">、</span><span style="color: #000000;">9</span><span style="color: #000000;">、A、B、C、D、E、F(其中后六个数字符号其值对应于十进制的10,</span><span style="color: #000000;">11</span><span style="color: #000000;">,</span><span style="color: #000000;">12</span><span style="color: #000000;">,</span><span style="color: #000000;">13</span><span style="color: #000000;">,</span><span style="color: #000000;">14</span><span style="color: #000000;">,</span><span style="color: #000000;">15</span><span style="color: #000000;">；也有选用S,T,U,V,W,X的记法);<br><br>⑵逢十六进一的进位法,16是十六进制数的基数。<br><br>(B56E)</span><span style="color: #000000;">16</span><span style="color: #000000;">=</span><span style="color: #000000;">B&#215;</span><span style="color: #000000;">16<sup>3</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">5</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">16<sup>2</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">6</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">16<sup>1</sup></span><span style="color: #000000;">+</span><span style="color: #000000;">E&#215;</span><span style="color: #000000;">16<sup>0</sup></span><span style="color: #000000;">=</span><span style="color: #000000;">11</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">163</span><span style="color: #000000;">+</span><span style="color: #000000;">5</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">162</span><span style="color: #000000;">+</span><span style="color: #000000;">6</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">161</span><span style="color: #000000;">+</span><span style="color: #000000;">14</span><span style="color: #000000;">&#215;</span><span style="color: #000000;">160<br><br>二进制换算为十六进制是这样:<br></span>
<div style="margin-left: 40px;"><span style="color: #000000;">先把二进制从低位（也就是从右到左）按四位一组分开，分到最后不够四位的也按一组来算。</span><br><span style="color: #000000;">分好以后再把每组的二进制换算成十六进制，之后再接换算好的组合起来就可以了。<br><br></span><span style="color: #000000;">如：</span><span style="color: #000000;">&nbsp; 1101110111010<br><br></span><span style="color: #000000;">分组后是:&nbsp;&nbsp; 1，1011，1011，1010<br><br></span><span style="color: #000000;">每组换算成十六进制是1，B,B,A 组合是1BBA
</span><br><span style="color: #000000;"></span></div>
</div>
<br><img src ="http://www.cppblog.com/colys/aggbug/22816.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-04-25 19:35 <a href="http://www.cppblog.com/colys/articles/22816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]设计模式学习之 Singleton（一）</title><link>http://www.cppblog.com/colys/articles/22552.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Sat, 21 Apr 2007 16:02:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/22552.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/22552.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/22552.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/22552.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/22552.html</trackback:ping><description><![CDATA[<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">去年接触</span><span lang=EN-US style="FONT-SIZE: 9pt">ACE</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">时学习了一段时间的设计模式，</span><span style="FONT-SIZE: 9pt"> </span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">简单地看了</span><span lang=EN-US style="FONT-SIZE: 9pt">Gof</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的设计模式，</span><span lang=EN-US style="FONT-SIZE: 9pt"><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">结合</span><span lang=EN-US style="FONT-SIZE: 9pt">ACE</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">大略的看了</span><span lang=EN-US style="FONT-SIZE: 9pt">POSA1</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</span><span lang=EN-US style="FONT-SIZE: 9pt"> POSA2</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span><span lang=EN-US style="FONT-SIZE: 9pt"><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对设计模式的理解还是很肤浅，</span><span style="FONT-SIZE: 9pt"> </span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">突然想深入地学习设计模式，</span><span style="FONT-SIZE: 9pt"> </span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对每一种模式</span><span lang=EN-US style="FONT-SIZE: 9pt"><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">都辅助相关的</span><span lang=EN-US style="FONT-SIZE: 9pt">code</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来理解，</span><span style="FONT-SIZE: 9pt"> </span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">并把设计模式和</span><span lang=EN-US style="FONT-SIZE: 9pt">MFC</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</span><span lang=EN-US style="FONT-SIZE: 9pt"> ACE</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</span><span lang=EN-US style="FONT-SIZE: 9pt"> cppunit</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">等框架联系起来，</span><span lang=EN-US style="FONT-SIZE: 9pt"><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">更好地理解和应用这些编程的框架（还有</span><span lang=EN-US style="FONT-SIZE: 9pt">log4plus</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">等）</span><span lang=EN-US style="FONT-SIZE: 9pt"><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US style="FONT-SIZE: 9pt"><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">今天总结一下简单的单件模式：</span><span lang=EN-US style="FONT-SIZE: 9pt"><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; LINE-HEIGHT: 120%; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><strong><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; mso-font-kerning: 0pt">Singleton(</span></strong><strong><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">单件</span></strong><strong><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; mso-font-kerning: 0pt">)</span></strong><strong><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">——对象创建型模式</span></strong><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; LINE-HEIGHT: 120%; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">保证一个类仅有一个实例，并提供一个访问它的全局访问点。<span lang=EN-US><o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; LINE-HEIGHT: 120%; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><strong><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">1</span></strong><strong><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">&#183;典型</span></strong><strong><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; mso-font-kerning: 0pt">Singleton</span></strong><strong><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">类</span></strong><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">：<span lang=EN-US><o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt"><o:p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">class&nbsp;Singleton<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Instance();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>protected:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Singleton();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;_instance;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>};<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Singleton::_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Singleton::Instance()<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(_instance&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Singleton;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;_instance;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left></o:p></span>&nbsp;</p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; LINE-HEIGHT: 120%; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">客户仅通过</span><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; mso-font-kerning: 0pt">Instance</span><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">成员函数访问这个单件。变量</span><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; mso-font-kerning: 0pt">_instance</span><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">初始化为</span><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; mso-font-kerning: 0pt">0</span><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">，而静态成员函数</span><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; mso-font-kerning: 0pt">Instance</span><span style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">返回该变量值。注意：构造器是保护型的，保证了仅有一个实例被创建。<span lang=EN-US><o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; LINE-HEIGHT: 120%; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; LINE-HEIGHT: 120%; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">这种方式的实现对于线程来说并不是安全的，因为在多线程的环境下有可能得到</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">类的多个实例。如果同时有两个线程去判断（</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">_instance == null</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">），并且得到的结果为真，这时两个线程都会创建类</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">的实例，这样就违背了</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">模式的原则。实际上在上述代码中，有可能在计算出表达式的值之前，对象实例已经被创建，但是内存模型并不能保证对象实例在第二个线程创建之前被发现。</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"> <o:p></o:p></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">&nbsp;</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">该实现方式主要有两个优点：&#183;由于实例是在</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"> <strong><span lang=EN-US>Instance</span></strong><span lang=EN-US> </span></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">属性方法内部创建的，因此类可以使用附加功能（例如，对子类进行实例化），即使它可能引入不想要的依赖性。&#183;</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">&nbsp; </span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">直到对象要求产生一个实例才执行实例化；这种方法称为</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">&#8220;</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">惰性实例化</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">&#8221;</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">。惰性实例化避免了在应用程序启动时实例化不必要的</span><strong><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"> singleton</span></strong><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"><o:p></o:p></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><strong style="mso-bidi-font-weight: normal"><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">2</span></strong><strong style="mso-bidi-font-weight: normal"><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">&#183;线程安全的</span></strong><strong style="mso-bidi-font-weight: normal"><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">singleton<o:p></o:p></span></strong></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma"></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">class&nbsp;Singleton<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Instance();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>protected:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Singleton();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;_instance;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;Cmutext&nbsp;_mutex;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>};<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Singleton::_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Singleton::Instance()<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_mutex.acque();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(_instance&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Singleton;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_mutex.release();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;_instance;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left>&nbsp;</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma">这种方式的实现对于线程来说是安全的。我们首先创建了一个进程辅助对象，线程在进入时先对辅助对象加锁然后再检测对象是否被创建，这样可以确保只有一个实例被创建，因为在同一个时刻加了锁的那部分程序只有一个线程可以进入。这种情况下，对象实例由最先进入的那个线程创建，后来的线程在进入时（</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma">_instence == null</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma">）为假，不会再去创建对象实例了。但是这种实现方式增加了额外的开销，损失了性能。</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma"><o:p></o:p></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><strong><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma">3</span></strong><strong><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma">．双重锁定</span></strong><strong><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma"><o:p></o:p></span></strong></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma"><span style="mso-spacerun: yes">&nbsp;</span></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma">这种实现方式对多线程来说是安全的，同时线程不是每次都加锁，只有判断对象实例没有被创建时它才加锁，有了我们上面第一部分的里面的分析，我们知道，加锁后还得再进行对象是否已被创建的判断。它解决了线程并发问题，同时避免在每个</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma"> <strong><span lang=EN-US style="FONT-FAMILY: Tahoma">Instance</span></strong><span lang=EN-US> </span></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma">属性方法的调用中都出现独占锁定。它还允许您将实例化延迟到第一次访问对象时发生。实际上，应用程序很少需要这种类型的实现。大多数情况下我们会用静态初始化。这种方式仍然有很多缺点：无法实现延迟初始化。<br><br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">class&nbsp;Singleton<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Instance();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>protected:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Singleton();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;_instance;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;CMutex&nbsp;_mutex;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>};<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Singleton::_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Singleton::Instance()<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(_instance&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_mutex.acque();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Singleton;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_mutex.release<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;_instance;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><br></p>
</span>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><strong><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma"><br>实现要点</span></strong><span style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"> <span lang=EN-US><o:p></o:p></span></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"><span style="mso-spacerun: yes">&nbsp;</span></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">&#183;</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">模式是限制而不是改进类的创建。</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"> <o:p></o:p></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"><span style="mso-spacerun: yes">&nbsp;</span></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">&#183;</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">类中的实例构造器可以设置为</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Protected</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">以允许子类派生。</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"><o:p></o:p></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"><span style="mso-spacerun: yes">&nbsp;</span></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">&#183;</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">模式一般不要支持</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Icloneable</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">接口，因为这可能导致多个对象实例，与</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">模式的初衷违背。</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"><o:p></o:p></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"><span style="mso-spacerun: yes">&nbsp;</span></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">&#183;</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"> Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">模式一般不要支持序列化，这也有可能导致多个对象实例，这也与</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">模式的初衷违背。</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"> <span lang=EN-US><o:p></o:p></span></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"><span style="mso-spacerun: yes">&nbsp;</span></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">&#183;</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">&nbsp;Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">只考虑了对象创建的管理，没有考虑到销毁的管理，就支持垃圾回收的平台和对象的开销来讲，我们一般没必要对其销毁进行特殊的管理。</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"><o:p></o:p></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"><span style="mso-spacerun: yes">&nbsp;</span></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">&#183;理解和扩展</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">模式的核心是</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">&#8220;</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">如何控制用户使用</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">new</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">对一个类的构造器的任意调用</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">&#8221;</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">。</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt"> <o:p></o:p></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">&nbsp;<o:p></o:p></span></p>
<p class=MsoNormal style="BACKGROUND: white; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><strong><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma">总结：</span></strong><strong><span style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma"> </span></strong><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma">Singleton</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma">设计模式是一个非常有用的机制，可用于在面向对象的应用程序中提供单个访问点。</span><span lang=EN-US style="FONT-SIZE: 9pt"><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><strong><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">应该注意的几点</span></strong><strong><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana">:</span></strong><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana"><br>&nbsp;&nbsp;&nbsp; 1,</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">我们不应该来序列化和反序列化用单件模式实现的对象</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">否则多次反序列化则可以创建多的实例</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">这与单件模式是相矛盾的</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana">.<br>&nbsp;&nbsp;&nbsp; 2,</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">我们不应该克隆用单件模式实现的对象</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">否则多次克隆则可以创建多的实例</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana">,</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">这与单件模式是相矛盾的</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana">.<br>&nbsp;&nbsp;&nbsp; 3,</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在多线程环境中使用单件模式时要小心</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana">.<br style="mso-special-character: line-break"><br style="mso-special-character: line-break"><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt; COLOR: red; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">关于</span><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: red; FONT-FAMILY: Verdana">ACE</span><span style="FONT-SIZE: 9pt; COLOR: red; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">中单件模式</span><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: red; FONT-FAMILY: Verdana">ACE_Singleton</span><span style="FONT-SIZE: 9pt; COLOR: red; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的设计和应用可以参考一博友的文章，</span><span style="FONT-SIZE: 9pt; COLOR: red; FONT-FAMILY: Verdana"> </span><span style="FONT-SIZE: 9pt; COLOR: red; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">感觉写的很好</span><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: red; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana"><a href="http://blog.csdn.net/joise/archive/2006/09/29/1305849.aspx"><u><font color=#800080>http://blog.csdn.net/joise/archive/2006/09/29/1305849.aspx</font></u></a><o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Verdana"><o:p>&nbsp;</o:p></span></p>
<img height=1 src="http://www.cppblog.com/Galaxy/aggbug/22502.html" width=1><br><br>
<div align=right><a style="TEXT-DECORATION: none" href="http://www.cppblog.com/Galaxy/" target=_blank>Galaxy</a> 2007-04-21 17:18 <a style="TEXT-DECORATION: none" href="http://www.cppblog.com/Galaxy/archive/2007/04/21/22502.html#Feedback" target=_blank>发表评论</a></div>
<br>文章来源:<a href="http://www.cppblog.com/Galaxy/archive/2007/04/21/22502.html">http://www.cppblog.com/Galaxy/archive/2007/04/21/22502.html</a><img src ="http://www.cppblog.com/colys/aggbug/22552.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-04-22 00:02 <a href="http://www.cppblog.com/colys/articles/22552.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]科学计算相关的c++库</title><link>http://www.cppblog.com/colys/articles/22553.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Sat, 21 Apr 2007 16:02:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/22553.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/22553.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/22553.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/22553.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/22553.html</trackback:ping><description><![CDATA[<p>Blitz++ </p>
<p>参考网站：<a href="http://www.oonumerics.org/blitz/">http://www.oonumerics.org/blitz/</a></p>
<p>Blitz++ 是一个高效率的数值计算函数库，它的设计目的是希望建立一套既具像C++ 一样方便，同时又比Fortran速度更快的数值计算环境。通常，用C++所写出的数值程序，比 Fortran慢20%左右，因此Blitz++正是要改掉这个缺点。方法是利用C++的template技术，程序执行甚至可以比Fortran更快。Blitz++目前仍在发展中，对于常见的SVD，FFTs，QMRES等常见的线性代数方法并不提供，不过使用者可以很容易地利用Blitz++所提供的函数来构建。 </p>
<p>POOMA </p>
<p>参考网站：<a href="http://www.c'>http://www.c'>http://www.c'>http://www.codesourcery.com/pooma/pooma">http://www.c'&gt;http://www.c'&gt;http://www.c'&gt;http://www.codesourcery.com/pooma/pooma</a></p>
<p>POOMA是一个免费的高性能的C++库，用于处理并行式科学计算。POOMA的面向对象设计方便了快速的程序开发，对并行机器进行了优化以达到最高的效率，方便在工业和研究环境中使用。 </p>
<p>MTL </p>
<p>参考网站：<a href="http://www.osl.iu.edu/research/mtl/'>http://www.osl.iu.edu/research/mtl/">http://www.osl.iu.edu/research/mtl/'&gt;http://www.osl.iu.edu/research/mtl/</a></p>
<p>Matrix Template Library(MTL)是一个高性能的泛型组件库，提供了各种格式矩阵的大量线性代数方面的功能。在某些应用使用高性能编译器的情况下，比如Intel的编译器，从产生的汇编代码可以看出其与手写几乎没有两样的效能。 </p>
<p>CGAL </p>
<p>参考网站：<a href="http://www.cgal.org/">www.cgal.org</a></p>
<p>Computational Geometry Algorithms Library的目的是把在计算几何方面的大部分重要的解决方案和方法以C++库的形式提供给工业和学术界的用户。 <br></p>
<img height=1 src="http://www.cppblog.com/Galaxy/aggbug/20725.html" width=1><br><br>
<div align=right><a style="TEXT-DECORATION: none" href="http://www.cppblog.com/Galaxy/" target=_blank>Galaxy</a> 2007-03-27 17:59 <a style="TEXT-DECORATION: none" href="http://www.cppblog.com/Galaxy/archive/2007/03/27/20725.html#Feedback" target=_blank>发表评论</a></div>
<br>文章来源:<a href="http://www.cppblog.com/Galaxy/archive/2007/03/27/20725.html">http://www.cppblog.com/Galaxy/archive/2007/03/27/20725.html</a><img src ="http://www.cppblog.com/colys/aggbug/22553.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-04-22 00:02 <a href="http://www.cppblog.com/colys/articles/22553.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]核心对象激发状态的意义</title><link>http://www.cppblog.com/colys/articles/21023.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Sat, 31 Mar 2007 15:03:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/21023.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/21023.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/21023.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/21023.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/21023.html</trackback:ping><description><![CDATA[<p class=MsoNormal style="MARGIN: 0in 0in 10pt"><span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">&#8220;激发&#8221;</span> <font face=Calibri>signaled</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">对于不同的核心对象有不同的意义</span> </p>
<p class=MsoNormal style="MARGIN: 0in 0in 10pt"><font face=Calibri>Thread</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">线程，当线程结束时，线程对象即被激发。当线程还在进行时，则对象处于未激发状态。</span> </p>
<p class=MsoNormal style="MARGIN: 0in 0in 10pt"><font face=Calibri>Process</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">进程，当进程结束时，进程对象即被激发。当进程还在进行时，则对象处于未激发状态。</span> </p>
<p class=MsoNormal style="MARGIN: 0in 0in 10pt"><font face=Calibri>Change Notification</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">，当一个特定的磁盘子目录中发生一件特别的变化时，此对象即被激发。此对象系由</span> <font face=Calibri>FindFirstChangeNotification()</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">产生</span> </p>
<p class=MsoNormal style="MARGIN: 0in 0in 10pt"><font face=Calibri>Console Input</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">，当</span> <font face=Calibri>console</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">窗口的输入缓冲区中有数据可用时，此对象将处于激发状态。</span> <font face=Calibri>CreateFile</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（）和</span> <font face=Calibri>GetStdFile</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（）两函数可以获得</span> <font face=Calibri>console handle</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">。</span> </p>
<p class=MsoNormal style="MARGIN: 0in 0in 10pt"><font face=Calibri>Event</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">，</span> <font face=Calibri>Event</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">对象的状态直接受控于应用程序所使用的三个</span> <font face=Calibri>Win32</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">函数：</span> <font face=Calibri>SetEvent</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（），</span> <font face=Calibri>PulseEvent</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（），</span> <font face=Calibri>ResetEvent</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（）。</span> <font face=Calibri>CreateEvent</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（）和</span> <font face=Calibri>OpenEvent</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（）都可以传回一个</span> <font face=Calibri>event object handle</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">。</span> <font face=Calibri>Event</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">对象的状态也可以被操作系统设定——如果使用于&#8220;</span> <font face=Calibri>overlapped</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">&#8221;操作时。</span> </p>
<p class=MsoNormal style="MARGIN: 0in 0in 10pt"><font face=Calibri>Mutex</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">，如果</span> <font face=Calibri>mutex</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">没有被任何线程拥有，他就是处于激发状态。一旦一个等待</span> <font face=Calibri>mutex</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">的函数返回了，</span> <font face=Calibri>mutex</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">也就自动重置为未激发状态。</span> <font face=Calibri>CreateMutex</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（）和</span> <font face=Calibri>OpenMutex</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（）都可以获得一个</span> <font face=Calibri>Mutext</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">的</span> <font face=Calibri>handle</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">。</span> </p>
<p class=MsoNormal style="MARGIN: 0in 0in 10pt"><font face=Calibri>Semaphore</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">，</span> <font face=Calibri>Semaphore</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">有点像</span> <font face=Calibri>mutex</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">，但他有个计数器，可以约束其拥有者（线程）的个数。当计数器内容大于</span> <font face=Calibri>0</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">时，</span> <font face=Calibri>semaphore</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">处于激发状态，当计数器内容等于</span> <font face=Calibri>0</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">时，</span> <font face=Calibri>semaphore</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">处于未激发状态。</span> <font face=Calibri>CreateSemaphore</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（）和</span> <font face=Calibri>OpenSemaphore</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">（）可以传回一个</span> <font face=Calibri>semaphore handle</font> <span lang=ZH-CN style="FONT-FAMILY: 宋体; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-ascii-font-family: Calibri; mso-fareast-font-family: 宋体; mso-hansi-font-family: Calibri">。</span></p><img src ="http://www.cppblog.com/colys/aggbug/21023.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-03-31 23:03 <a href="http://www.cppblog.com/colys/articles/21023.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ Builder下在一个窗体的panel中显示加一个窗体的控件</title><link>http://www.cppblog.com/colys/articles/21021.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Sat, 31 Mar 2007 14:57:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/21021.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/21021.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/21021.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/21021.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/21021.html</trackback:ping><description><![CDATA[<br />/*<br /> *已知两窗体TfrmSetting和 frmModifyPath<br /> *显示frmModifyPath的TPanel控件PanContent到TfrmSetting的TPanel控件panClient<br /> */<br /><br />int TfrmSetting::ShowModifyPathWin()<br />{<br />    if(frmModifyPath)<br />    {<br />        if(frmModifyPath-&gt;PanContent -&gt;Parent !=panClient)<br />        {<br />            frmModifyPath-&gt;PanContent-&gt;Parent= panClient;<br />            frmModifyPath-&gt;PanContent-&gt;Align=alClient;          <br />        }<br />    }<br />}<br /><img src ="http://www.cppblog.com/colys/aggbug/21021.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-03-31 22:57 <a href="http://www.cppblog.com/colys/articles/21021.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一道算法面试题</title><link>http://www.cppblog.com/colys/articles/20418.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Fri, 23 Mar 2007 02:41:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/20418.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/20418.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/20418.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/20418.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/20418.html</trackback:ping><description><![CDATA[<p>题目：</p>
		<p>从1到N(100000)中任意拿掉两个数，把剩下的99998个数顺序打乱，并且放入数组A中。要求只扫描一遍数组，把这两个数找出来。可以使用最到不超过5个局部变量，不能用数组变量，并且不能改变原数组的值。<br /></p><img src ="http://www.cppblog.com/colys/aggbug/20418.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-03-23 10:41 <a href="http://www.cppblog.com/colys/articles/20418.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ASSERT( booleanExpression ) 的作用</title><link>http://www.cppblog.com/colys/articles/19665.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Mon, 12 Mar 2007 14:15:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/19665.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/19665.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/19665.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/19665.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/19665.html</trackback:ping><description><![CDATA[<a name="16773806"> 
<div class="f14">ASSERT( booleanExpression )； <br />首先：booleanExpression 参数是一个bool表达式。 <br />用法： <br />当程序运行到该语句的时候，程序会检查booleanExpression 这个表达式是真还是假。 <br />如果条件符合，程序继续运行下面的代码； <br />如果是不符合，那么持续运行会被卡在这里。不往下面走，并有程序弹出错误对话框，指示是由于booleanExpression 这个条件符合导致的报错。 <br />作用： <br />ASSERT(booleanExpression )语句一般用来检查一些必须符合的条件，如果不符合条件，则不让程序继续运行下去。 <br /><br />比如： <br />一个班有55个人，有一个函数可以对班上的55个人进行处理，一个单独处理一个同学也可以，也可以同时处理多个同学。函数申明为：CONTROLSTUDENT(int number);其中number为要处理的学生的个数。 <br />在使用CONTROLSTUDENT函数前，一般我们会使用 <br />ASSERT(number&lt;=55); <br />CONTROLSTUDENT(number); <br />这样可以保证输入的学生数目绝对小于等于55个人。 <br />如果输入的number参数大于55，程序将报错，不执行。 <br /><br />总结：该指令可以用来做为某些条件的防护，避免不符合条件的东西产生导致程序的崩溃。 </div><div class="gray" align="right"></div></a> <div id="Lg"></div><a name="16775737"><div class="f14">只有在生成DEBUG码时ASSERT()才起作用. <br /><br />在生成Release码时编译器会跳过ASSERT(). <br /><br />ASSERT()用来检查上面运行结果有无错,例如送返的指针对不对,表达式返回值是不是"假",有错则打出有关信息并退出程序. </div></a><img src ="http://www.cppblog.com/colys/aggbug/19665.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-03-12 22:15 <a href="http://www.cppblog.com/colys/articles/19665.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数组的引用 </title><link>http://www.cppblog.com/colys/articles/19598.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Mon, 12 Mar 2007 01:24:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/19598.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/19598.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/19598.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/19598.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/19598.html</trackback:ping><description><![CDATA[<p>        象如下定义就得到一个数组的引用<br />        类型名 （&amp;变量明）[N]；<br />        <br />        实例<br />        int int_array[10];<br />        int (&amp;int_ref)[10] = int_array;<br />        这样就得到了一个数组的应用</p>
		<p>        在函数的声明中用数组的引用定义，就不怕数组退化了。如下<br />        for_each( int (&amp;int_ref)[10] )<br />        {<br />                 for( int i=0; i&lt;10; ++i )<br />                         std::cout &lt;&lt; int_ref[i] &lt;&lt; std::endl;<br />         }</p>
		<p>         int main( int argc, char* argv[] )<br />         {<br />                 int int_array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }<br />         <br />                 for_each( int_array );<br />                 return 0;<br />          }</p>
		<p>          在上面的代码中，如果你传入不是10个尺寸的数组，是编译通不过的。代码的安全性提高了。   </p>
		<p>         想要定义一个数组引用类型，方法如下<br />         typedef 类型明 (&amp;数组引用类型明)[N];</p>
		<p>         实例<br />         typedef int (&amp;Array_Ref)[10];<br />         Array_Ref就是一个数组的引用类型了。<br /></p><img src ="http://www.cppblog.com/colys/aggbug/19598.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-03-12 09:24 <a href="http://www.cppblog.com/colys/articles/19598.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>给MSN Messager装个钩子[转载]</title><link>http://www.cppblog.com/colys/articles/18554.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Thu, 08 Feb 2007 12:47:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/18554.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/18554.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/18554.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/18554.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/18554.html</trackback:ping><description><![CDATA[
		<div>最近研究怎么样使用HOOK拦截其他应用程序的消息，于是就动手写了一个钩子程序来挂到最常用的通讯及时通讯工具MSN，虽然没有什么实际意义，但作为学习研究却能够帮助我们理解利用HOOK是怎么样将自己编写的DLL注入已经存在的程序空间中的。<br /><p>我们需要做的是通过我们自己编写的应用程序去拦截别人写好的应用程序消息，实际上这是在两个进程之间进行的，难度就在这里，如果是同一个进程什么都好办，只要将系统响应WINDOWS消息的处理函数修改为我们自己编写的函数就可以，但现在不能这么做，因为两个进程有各自的进程地址空间，理论上你没有办法直接去访问别的进程的地址空间，那么怎么办来？办法还是很多的，这里仅仅介绍通过HOOK来达到目的。</p><p>需要拦截别的应用程序的消息，需要利用将自己编写的DLL注入到别人的DLL地址空间中才可以达到拦截别人消息的目的。只有将我们的DLL插入到别的应用程序的地址空间中才能够对别的应用程序进行操作，HOOK帮助我们完成了这些工作，我们只需要使用HOOK来拦截指定的消息，并提供必要的处理函数就行了。我们这里介绍拦截在MSN聊天对话框上的鼠标消息，对应的HOOK类型是WH_MOUSE。</p><p>首先我们要建立一个用来HOOK的DLL。这个DLL的建立和普通的DLL建立没有什么具体的区别，不过我们这里提供的方法有写不同。这里使用隐式导入DLL的方法。代码如下：</p><p>头文件</p><p>#pragma once<br />#ifndef MSNHOOK_API<br />#define MSNHOOK_API __declspec(dllimport)<br />#endif</p><p>MSNHOOK_API BOOL WINAPI SetMsnHook(DWORD dwThreadId);//安装MSN钩子函数<br />MSNHOOK_API void WINAPI GetText(int &amp;x,int &amp;y,char ** ptext);//安装MSN钩子函数<br />MSNHOOK_API HWND WINAPI GetMyHwnd();//安装MSN钩子函数</p><p>==================================================</p><p>DLL 的CPP文件</p><p>#include "stdafx.h"<br />#include "MSNHook.h"<br />#include &lt;stdio.h&gt; </p><p>// 下面几句的含义是告诉编译器将各变量放入它自己的数据共享节中</p><p>#pragma data_seg("Shared")<br />HHOOK g_hhook = NULL;<br />DWORD g_dwThreadIdMsn = 0;<br />POINT MouseLoc={0,0};<br />char text[256]={0};<br />HWND g_Hwnd = NULL;<br />#pragma data_seg()</p><p>//告诉编译器设置共享节的访问方式为：读，写，共享</p><p>#pragma comment(linker,"/section:Shared,rws")</p><p>HINSTANCE g_hinstDll = NULL;</p><p>BOOL APIENTRY DllMain( HANDLE hModule, <br />DWORD ul_reason_for_call, <br />LPVOID lpReserved<br />)<br />{<br />switch (ul_reason_for_call)<br />{<br />case DLL_PROCESS_ATTACH:<br />g_hinstDll = (HINSTANCE)hModule;<br />break;<br />case DLL_THREAD_ATTACH:<br />case DLL_THREAD_DETACH:<br />case DLL_PROCESS_DETACH:<br />break;<br />}<br />return TRUE;<br />}</p><p>LRESULT WINAPI GetMsgProc(int nCode,WPARAM wParam, LPARAM lParam);</p><p>BOOL WINAPI SetMsnHook(DWORD dwThreadId)<br />{<br />OutputDebugString("SetMsnHook");<br />BOOL fOK = FALSE;<br />if(dwThreadId != 0)<br />{<br />OutputDebugString("SetMsnHook dwThreadId != 0");<br />g_dwThreadIdMsn = GetCurrentThreadId();</p><p>//安装WM_MOUSE钩子和处理函数GetMsgProc<br />g_hhook = SetWindowsHookEx(WH_MOUSE,GetMsgProc,g_hinstDll,dwThreadId);<br />fOK = (g_hhook != NULL);<br />if(fOK)<br />{<br />fOK = PostThreadMessage(dwThreadId,WM_NULL,0,0);<br />}<br />else<br />{<br />fOK = UnhookWindowsHookEx(g_hhook);<br />g_hhook = NULL;<br />}<br />}<br />return(fOK);<br />}</p><p>LRESULT WINAPI GetMsgProc(int nCode,WPARAM wParam, LPARAM lParam)<br />{<br /><br />char temp[20];<br />sprintf(temp,"%dn",nCode);<br />OutputDebugString("temp");<br />if (nCode==HC_ACTION)<br />{<br />MOUSEHOOKSTRUCT *l=(MOUSEHOOKSTRUCT *)lParam;<br />MouseLoc=l-&gt;pt; //送鼠标位置<br /><br />//char text[256] = "";<br />HWND hWnd = WindowFromPoint(l-&gt;pt);<br />if(hWnd)<br />{<br />//GetWindowText(hWnd,text,256);<br />SendMessage(hWnd,WM_GETTEXT,256,(LPARAM)(LPCTSTR)text);<br />// strcpy(text,"123455555");<br />SendMessage(hWnd,WM_SETTEXT,256,(LPARAM)(LPCTSTR)text);<br />g_Hwnd = hWnd;<br />}<br />//SendMessage(WindowFromPoint(l-&gt;pt),WM_GETTEXT,256,(LPARAM)(LPCTSTR)psw);<br />}</p><p>return(CallNextHookEx(g_hhook,nCode,wParam,lParam));<br />}</p><p>void WINAPI GetText(int &amp;x,int &amp;y,char ** ptext)<br />{<br />x = MouseLoc.x;<br />y = MouseLoc.y;<br />*ptext = text;<br />}</p><p>HWND WINAPI GetMyHwnd()<br />{<br />return g_Hwnd;<br />}</p><p>上面是处理钩子的DLL代码，下面我们要让这个DLL起作用还需要一个启动部分，通过这个启动部分我们才能让我们的钩子函数真正的注入到系统其他函数中。我们这里使用个对话框的程序，程序非常简单：一个按钮用来启动钩子，一个用来停止，一个TIMER用来刷新显示，还有一个EDITBOX用来接受信息。</p><p>程序如下：</p><p>//包含DLL函数导出的头文件<br />#include "MSNHook.h"</p><p>//隐式导入</p><p>#pragma comment(lib,"MSNHook.lib") </p><p>//声明导入函数</p><p>__declspec(dllimport) BOOL WINAPI SetMsnHook(DWORD dwThreadId);<br />__declspec(dllimport) void WINAPI GetText(int &amp;x,int &amp;y,char ** ptext);<br />__declspec(dllimport) HWND WINAPI GetMyHwnd();//安装MSN钩子函数</p><p></p><p>void CTestMSNHookDlg::OnBnClickedOk()<br />{</p><p>//通过SPY++可以看到MSN聊天对话框窗口类是IMWindowClass，通过这个得到该窗口句柄<br />CWnd *pMsnWin = FindWindow(TEXT("IMWindowClass"),NULL);<br />if(pMsnWin == NULL) return ;</p><p>//通过窗口句柄得到对应的线程的ID<br />SetMsnHook(GetWindowThreadProcessId(pMsnWin-&gt;GetSafeHwnd(),NULL));<br />MSG msg;<br />GetMessage(&amp;msg,NULL,0,0);<br />SetTimer(101,100,NULL);<br /><br />}</p><p>void CTestMSNHookDlg::OnTimer(UINT_PTR nIDEvent)<br />{</p><p>//刷新消息<br />char * pText = NULL;<br />int x = 0,y = 0;<br />GetText(x,y,&amp;pText);<br />if(x ==0 &amp;&amp; y ==0) return ;<br />m_Edit.Format("%d:%d:%s",x,y,pText);<br />//m_Edit = pText;<br />UpdateData(FALSE);</p><p>HWND hWnd = GetMyHwnd();<br />CWnd * pWnd = CWnd::FromHandle(hWnd);<br />pWnd-&gt;GetWindowText(m_Edit);<br />CDialog::OnTimer(nIDEvent);<br />}</p><p>void CTestMSNHookDlg::OnBnClickedButton1()<br />{</p><p>//关闭<br />KillTimer(101);<br />SetMsnHook(0); <br />OnCancel();<br />}</p><p></p><p>好了，基本上就这些了。这里有个问题，我本想得到MSN用户聊天时输入的聊天信息，这里通过WM_GETTEXT消息的不到，如果有知道的朋友告诉一声。</p></div>
<img src ="http://www.cppblog.com/colys/aggbug/18554.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-02-08 20:47 <a href="http://www.cppblog.com/colys/articles/18554.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>