??xml version="1.0" encoding="utf-8" standalone="yes"?>久久精品国产亚洲5555,亚洲精品高清久久,久久综合给合久久狠狠狠97色69http://www.shnenglu.com/xpzhou/archive/2007/04/23/22672.html榕树?/dc:creator>榕树?/author>Mon, 23 Apr 2007 11:51:00 GMThttp://www.shnenglu.com/xpzhou/archive/2007/04/23/22672.htmlhttp://www.shnenglu.com/xpzhou/comments/22672.htmlhttp://www.shnenglu.com/xpzhou/archive/2007/04/23/22672.html#Feedback0http://www.shnenglu.com/xpzhou/comments/commentRss/22672.htmlhttp://www.shnenglu.com/xpzhou/services/trackbacks/22672.htmlVC6.0~译器参数的讄主要通过VC的菜单项Project->Settings->C/C++|完成。我们可以看到这一늚最下面Project Options中的内容Q一般如下:

/nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /Fp"Debug/WritingDlgTest.pch" /Yu"stdafx.h" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c

各个参数代表的意义,可以参考Msdn。比?nologo表示~译时不在输出窗口显C些设|(我们可以把这个参数去掉来看看效果Q等{。一般我们不会直接修改这些设|,而是通过q一|上面的Category中的各项来完?.....
Q{载-


主要通过VC的菜单项Project->Settings->C/C++|完成。我们可以看到这一늚最下面Project Options中的内容Q一般如下:

/nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /Fp"Debug/WritingDlgTest.pch" /Yu"stdafx.h" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c

各个参数代表的意义,可以参考Msdn。比?nologo表示~译时不在输出窗口显C些设|(我们可以把这个参数去掉来看看效果Q等{。一般我们不会直接修改这些设|,而是通过q一|上面的Category中的各项来完成?/font>

1) GeneralQ一些M讄?/font>

Warning level 用来控制警告信息Q其中Level 1是最严重的别;
Warnings as errors 警告信息当作错误处理;
Optimizations 代码优化Q可以在Category的Optimizations中q行更细的设|;
Generate browse info 用以生成.sbr文gQ记录类、变量等W号信息Q可以在Category的Listing Files中q行更多的设|?
Debug info 生成调试信息Q?
NoneQ不产生M调试信息Q编译比较快Q;
Line Numbers OnlyQ仅生成全局的和外部W号的调试信息到.OBJ文g?EXE文gQ减目标文件的寸Q?
C 7.0- CompatibleQ记录调试器用到的所有符号信息到.OBJ文g?EXE文gQ?
Program DatabaseQ创?PDB文g记录所有调试信息;
Program Database for "Edit & Continue"Q创?PDB文g记录所有调试信息,q且支持调试时编辑?

2) C++ Language

Pointer-to-member representation 用来讄cd?引用的先后关p:
Best-Case AlwaysQ表C在引用cM前该c肯定已l定义;
General-Purpose AlwaysQ?
Point to Any Class
Point to Single- and Multiple-Inheritance Classes
Point to Single-Inheritance Classes
Enable Exception HandlingQ进行同步的异常处理Q?
Enable Run-Time Type Information qɾ~译器增加代码在q行时进行对象类型检查;
Disable Construction Displacements 讄cL?析构函数调用虚函数问题?

3) Code Generation

Processor 表示代码指o优化Q可以ؓ80386?0486、Pentium、Pentium ProQ或者Blend表示混合以上各种优化?
Use run-time library 用以指定E序q行时用的q行时库Q有一个原则就是,一个进E不要同时用几个版本的q行时库。连接了单线E库׃支持多线E调用,q接了多U程库就要求创徏多线E的应用E序?
Single-ThreadedQ单U程Release版本Q静态连接LIBC.LIB库;
Debug Single-ThreadedQ单U程Debug版本Q静态连接LIBCD.LIB库;
MultithreadedQ多U程Release版本Q静态连接LIBCMT.LIB库;
Debug MultithreadedQ多U程Debug版本Q静态连接LIBCMTD.LIB库;
Multithreaded DLLQ动态连接MSVCRT.DLL库;
Debug Multithreaded DLLQ动态连接MSVCRTD.DLL库?
Calling convention 可以用来讑֮调用U定Q有三种Q__cdecl、__fastcall和__stdcall?br>  各种调用U定的主要区别在于:1. 函数调用Ӟ函数的参数是从左到右压入堆栈q是从右到左压入堆栈Q?. 在函数返回时Q由函数的调用者来清理压入堆栈的参数还是由函数本n来清理;3. 以及在编译时对函数名q行的命名修饎ͼ可以通过Listing Files看到各种命名修饰方式Q?
Struct member alignment 用以指定数据l构中的成员变量在内存中是按几字节对齐的Q根据计机数据ȝ的位敎ͼ不同的对齐方式存取数据的速度不一栗这个参数对数据包网l传输等应用ؓ重要Q不是存取速度问题Q而是数据位的_定义问题Q一般在E序中?pragma pack来指定?

4) Customize

Disable Language ExtensionsQ表CZ使用微Y为标准C做的语言扩展Q?
Eliminate Duplicate StringsQ主要用于字W串优化Q将字符串放到缓充池里以节省I间Q,使用q个参数Q?br>            char *sBuffer = "This is a character buffer";
            char *tBuffer = "This is a character buffer";
            sBuffer 和tBuffer指向的是同一块内存空_
Enable Function-Level Linking Q告诉编译器各个函数按打包格式~译Q?
Enables minimal rebuildQ通过保存兌信息?IDB文gQɾ~译器只Ҏ(gu)新类定义改动q的源文件进行重~译Q提高编译速度Q?
Enable Incremental CompilationQ同样通过.IDB文g保存的信息,只重~译最新改动过的函敎ͼ
Suppress Startup Banner and Information MessagesQ用以控制参数是否在outputH口输出?/font>


5) Listing Files

Generate browse info 上面已经提到q。这里可以进行更多的讄?
Exclude Local Variables from Browse Info 表示是否局部变量的信息攑ֈ.SBR文g中?
Listing file type 可以讄生成的列表信息文件的内容Q?
Assembly-Only Listing 仅生成汇~代码文Ӟ.ASM扩展名)Q?
Assembly With Machine Code 生成机器代码和汇~代码文Ӟ.COD扩展名)Q?
Assembly With Source Code 生成源代码和汇编代码文gQ?ASM扩展名)Q?
Assembly, Machine Code, and Source 生成机器码、源代码和汇~代码文Ӟ.COD扩展名)?
Listing file name 生成的信息文件的路径Q一般ؓDebug或Release目录下,生成的文件名自动取源文g的文件名?

6) Optimizations 代码优化讄?/font>

Maximize Speed 生成最快速的代码Q?
Minimize Size 生成最尺寸的E序Q?
Customize 定制优化。定制的内容包括Q?
Assume No AliasingQ不使用别名Q提高速度Q;
Assume Aliasing Across Function CallsQ仅函数内部不用别名;
Global OptimizationsQ全局优化Q比如经常用到的变量使用寄存器保存,或者@环内的计优化,如i = -100;while( i < 0 ){i += x + y;}会被优化为i = -100;t = x + y;while( i < 0 ){i += t;}Q?
Generate Intrinsic FunctionsQ用内部函数替换一些函数调用(提高速度Q;
Improve Float ConsistencyQQ点运方面的优化Q?
Favor Small CodeQ程序(exe或dllQ尺怼化优先于代码速度优化Q?
Favor Fast CodeQ程序(exe或dllQ代码速度优化优先于尺怼化;
Frame-Pointer OmissionQ不使用帧指针,以提高函数调用速度Q?
Full OptimizationQ组合了几种参数Q以生成最快的E序代码?
Inline function expansionQ内联函数扩展的三种优化Q用内联可以节省函数调用的开销Q加快程序速度Q:
DisableQ不使用内联Q?
Only __inlineQ仅函数定义前有inline或__inline标记使用内联Q?
Any SuitableQ除了inline或__inline标记的函数外Q编译器"觉得"应该使用内联的函敎ͼ都用内联?

7) Precompiled Headers 预编译头文g的设|。用预~译可以提高重复~译的速度。VC一般将一些公q、不大变动的头文Ӟ比如afxwin.h{)集中攑ֈstdafx.h中,q一部分代码׃必每ơ都重新~译Q除非是Rebuild AllQ?/font>


8) Preprocessor 预编译处理。可以定?解除定义一些常量?/font>

Additional include directoriesQ可以指定额外的包含目录Q一般是相对于本目的目录,?.\Include?/font>


--------------------------------------------------------------------------------
q接参数的设|?br>主要通过VC的菜单项Project->Settings->Link|完成。我们可以看到这一늚最下面Project Options中的内容Q一般如下:

/nologo /subsystem:windows /incremental:yes /pdb:"Debug/WritingDlgTest.pdb" /debug /machine:I386 /out:"Debug/WritingDlgTest.exe" /pdbtype:sept

下面我们分别来看一下Category中的各项讄?/font>

1) General 一些M讄。可以设|生成的文g路径、文件名Q连接的库文Ӟ

Generate debug infoQ生成Debug信息?PDB文gQ具体格式可以在Category->Debug中设|)Q?
Ignore All Default LibrariesQ放弃所有默认的库连接;
Link IncrementallyQ通过生成. ILK文g实现递增式连接以提高后箋q接速度Q但一般这U方式下生成的文ӞEXE或DLLQ较大;
Generate MapfileQ生?MAP文g记录模块相关信息Q?
Enable ProfilingQ这个参数通常与Generate Mapfile参数同时使用Q而且如果产生Debug信息的话Q不能用.PDB文gQ而且必须用Microsoft Format?

2) Customize q里可以q行使用E序数据库文件的讄?/font>

Force File OutputQ强制生输出文ӞEXE或DLLQ;
Print Progress MessagesQ可以将q接q程中的q度信息输出到OutputH口?

3) Debug 讄是否生成调试信息Q以及调试信息的格式?/font>

Dubug infoQ格式可以有Microsoft Format、COFF FormatQCommon Object File FormatQ和Both Formats三种选择Q?
Separate TypesQ表C将Debug格式信息以独立的.PDB文g存放Q还是直接放在各个源文g?PDB文g中。选中的话Q表C采用后者的方式Q这U方式调试启动比较快?/font>


4) Input q里可以指定要连接的库文Ӟ攑ּq接的库文g。还可以增加额外的库文g目录Q一般是相对于本目的目录,?.\Lib?/font>

Force Symbol ReferencesQ可以指定连接特定符号定义的库?

5) Output 

Base Address 可以改变E序默认的基地址QEXE文g默认?x400000QDLL默认?x10000000Q,操作pȝ装蝲一个程序时L试着先从q个基地址开始?
Entry-Point Symbol 可以指定E序的入口地址Q一般ؓ一个函数名Q且必须采用__stdcall调用U定Q。一般Win32的程序,EXE的入口ؓ WinMainQDLL的入口ؓDllEntryPointQ最好让q接器自动设|程序的入口炏V默认情况下Q通过一个C的运行时库函数来实现Q控制台E序采用mainCRTStartup (或wmainCRTStartup)去调用程序的main (或wmain)函数QWindowsE序采用WinMainCRTStartup (?wWinMainCRTStartup)调用E序的WinMain (?wWinMainQ必采用__stdcall调用U定)QDLL采用_DllMainCRTStartup调用DllMain函数Q必采?__stdcall调用U定Q?
Stack allocations 用以讄E序使用的堆栈大(请用十q制Q,默认?兆字节?
Version Information 告诉q接器在EXE或DLL文g的开始部分放上版本号?

值得注意的是Q?/font>

上面各个参数是大写敏感的;
在参数后加上"-"表示该参数无效;
各个参数值选项?*"的表CZؓ该参数的默认|
可以使用右上角?Reset"按钮来恢复该늚所有默认设|?

--------------------------------------------------------------------------------
其它一些参数设|?/font>

1) Project->Settings->GeneralQ可以设|连接MFC库的方式Q静态或动态)。如果是动态连接,在MFC软g发布时不要忘了带上MFC的DLL?/font>

2) Project->Settings->DebugQ可以设|调试时q行的可执行文gQ以及命令行参数{?/font>

3) Project->Settings->Custom BuildQ可以设|编?q接成功后自动执行一些操作。比较有用的是,写COM时希望VC对编译通过的COM文g自动注册Q可以如下设|:

Description: Register COM

Commands: regsvr32 /s /c $(TargetPath)

echo regsvr32 exe.time > $(TargetDir)\$(TargetName).trg

Outputs: $(TargetDir)\$(TargetName).trg


4) Tools->Options->DirectoriesQ设|系l的Include、Library路径?/font>

--------------------------------------------------------------------------------
窍? 目中的.ncb?opt?aps?clw文g以及Debug、Release目录下的所有文仉可以删掉的?/font>



]]>
VC中基?Windows 的精定?/title><link>http://www.shnenglu.com/xpzhou/archive/2007/04/20/22426.html</link><dc:creator>榕树?/dc:creator><author>榕树?/author><pubDate>Fri, 20 Apr 2007 13:03:00 GMT</pubDate><guid>http://www.shnenglu.com/xpzhou/archive/2007/04/20/22426.html</guid><wfw:comment>http://www.shnenglu.com/xpzhou/comments/22426.html</wfw:comment><comments>http://www.shnenglu.com/xpzhou/archive/2007/04/20/22426.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/xpzhou/comments/commentRss/22426.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/xpzhou/services/trackbacks/22426.html</trackback:ping><description><![CDATA[在工业生产控制系l中Q有许多需要定时完成的操作Q如定时昄当前旉Q定时刷新屏q上的进度条Q上?wbr> 机定时向下位机发送命令和传送数据等。特别是在对控制性能要求较高的实时控制系l和数据采集pȝ中,更需要精定时操作?br>  众所周知QWindows 是基于消息机制的pȝQQ何事件的执行都是通过发送和接收消息来完成的?wbr> q样带来了一些问题,如一旦计机的CPU被某个进E占用,或系l资源紧张时Q发送到消息队列<wbr> 中的消息暂时被挂vQ得不到实时处理。因此,不能单地通过Windows消息引发一个对定时要求<wbr> 严格的事件。另外,׃在Windows中已l封装了计算机底层硬件的讉KQ所以,要想通过直接利用<wbr> 讉Kg来完成精定Ӟ也比较困难。所以在实际应用Ӟ应针对具体定时精度的要求Q采取相?应的定时Ҏ(gu)?br>  VC中提供了很多关于旉操作的函敎ͼ利用它们控制E序能够_地完成定时和计时操作。本文详l介l了<wbr> VC中基于Windows的精定时的七种方式Q如下图所C:<br><br><img src="http://www.vckbase.com/document/journal/vckbase37/images/MultiTimerDemoimg.gif" border=0><br>图一 囑փ描述 <br><br>  方式一QVC中的WM_TIMER消息映射能进行简单的旉控制。首先调用函数SetTimer()讄定时<wbr> 间隔Q如SetTimer(0,200,NULL)即ؓ讄200ms的时间间隔。然后在应用E序中增加定时响应函?wbr> OnTimer()Qƈ在该函数中添加响应的处理语句Q用来完成到辑֮时时间的操作。这U定时方法非?wbr> 单,可以实现一定的定时功能Q但其定时功能如同Sleep()函数的g时功能一P_ֺ非常低,最?wbr> 计时_ֺ仅ؓ30msQCPU占用低,且定时器消息在多d操作pȝ中的优先U很低,不能得到及时?wbr> 应,往往不能满实时控制环境下的应用。只可以用来实现诸如位图的动态显C等对定时精度要求不高的情况。如CZ工程中的Timer1?<br>  方式二:VC中用sleep()函数实现延时Q它的单位是msQ如延时2U,用sleep(2000)。精度非?wbr> 低,最计时精度仅?0msQ用sleep函数的不利处在于延时期间不能处理其他的消息,如果旉?wbr> 长,好象死ZPCPU占用率非帔RQ只能用于要求不高的延时E序中。如CZ工程中的Timer2?br>  方式三:利用COleDateTimecdCOleDateTimeSpancȝ合WINDOWS的消息处理过E来实现U延时。如CZ工程中的Timer3和Timer3_1。以下是实现2U的延时代码Q?<br>COleDateTime      start_time = COleDateTime::GetCurrentTime();<br>COleDateTimeSpan  end_time= COleDateTime::GetCurrentTime()-start_time;<br>while(end_time.GetTotalSeconds()< 2) //实现延时2U?br>{<br>MSG   msg;<br>GetMessage(&msg,NULL,0,0);<br>TranslateMessage(&msg);<br>DispatchMessage(&msg);<br>//以上四行是实现在延时或定时期间能处理其他的消息,<br>//虽然q样可以降低CPU的占有率Q?br>//但降低了延时或定时精度,实际应用中可以去掉?br>end_time = COleDateTime::GetCurrentTime()-start_time;<br>}//q样在g时的时候我们也能够处理其他的消息?nbsp;       方式四:在精度要求较高的情况下,VC中可以利用GetTickCount()函数Q该函数的返回值是<wbr>  DWORD型,表示以ms为单位的计算机启动后l历的时间间隔。精度比WM_TIMER消息映射高,在较<wbr> 短的定时中其计时误差?5msQ在较长的定时中其计时误差较低,如果定时旉太长Q就好象L一PCPU占用率非帔RQ只能用于要求不高的延时E序中。如CZ工程中的Timer4和Timer4_1。下列代码可以实?0ms的精定Ӟ<br> <pre>DWORD dwStart = GetTickCount(); DWORD dwEnd = dwStart; do { dwEnd = GetTickCount()-dwStart; }while(dwEnd <50);</pre> ZGetTickCount()函数在g时或定时期间能处理其他的消息Q可以把代码改ؓQ?br> <pre>DWORD dwStart = GetTickCount(); DWORD dwEnd = dwStart; do { MSG msg; GetMessage(&msg,NULL,0,0); TranslateMessage(&msg); DispatchMessage(&msg); dwEnd = GetTickCount()-dwStart; }while(dwEnd <50);</pre> 虽然q样可以降低CPU的占有率Qƈ在g时或定时期间也能处理其他的消息,但降低了延时或定时精度?br>  方式五:与GetTickCount()函数cM的多媒体定时器函数DWORD timeGetTime(void)Q该函数定时_?wbr> 度ؓmsU,q回从Windows启动开始经q的毫秒数。微软公司在其多媒体Windows中提供了_定时器的?wbr> 层API持,利用多媒体定时器可以很精地dpȝ的当前时_q且能在非常_的时间间隔内完成一<wbr> 个事件、函数或q程的调用。不同之处在于调用DWORD timeGetTime(void) 函数之前必须?Winmm.lib <wbr> ?Mmsystem.h d到工E中Q否则在~译时提CDWORD timeGetTime(void)函数未定义。由于用该<wbr> 函数是通过查询的方式进行定时控制的Q所以,应该建立定时循环来进行定时事件的控制。如CZ工程中的Timer5和Timer5_1?br>  方式六:使用多媒体定时器timeSetEvent()函数Q该函数定时_ֺ为msU。利用该函数可以实现周期性的函数调用。如CZ工程中的Timer6和Timer6_1。函数的原型如下Q?<br> <pre>MMRESULT timeSetEventQ?UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, WORD dwUser, UINT fuEvent Q?/pre>   该函数设|一个定时回调事Ӟ此事件可以是一个一ơ性事件或周期性事件。事件一旦被Ȁz,便调用指定的回调函数Q?wbr> 成功后返回事件的标识W代码,否则q回NULL。函数的参数说明如下Q?br> <pre>uDelayQ以毫秒指定事g的周期? UresolutionQ以毫秒指定延时的精度,数D定时器事g分L率越高。缺省gؓ1ms? LpTimeProcQ指向一个回调函数? DwUserQ存攄h供的回调数据? FuEventQ指定定时器事gcdQ? TIME_ONESHOTQuDelay毫秒后只产生一ơ事? TIME_PERIODIC Q每隔uDelay毫秒周期性地产生事g? </pre>   具体应用Ӟ可以通过调用timeSetEvent()函数Q将需要周期性执行的d定义在LpTimeProc回调函数<wbr> ?如:定时采样、控制等)Q从而完成所需处理的事件。需要注意的是,d处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后,<wbr> 应及时调用timeKillEvent()之释放?<br>  方式七:对于_度要求更高的定时操作Q则应该使用QueryPerformanceFrequency()?wbr> QueryPerformanceCounter()函数。这两个函数是VC提供的仅供Windows 95及其后箋版本使用的精时间函敎ͼq要求计机从硬件上支持_定时器。如CZ工程中的Timer7、Timer7_1、Timer7_2、Timer7_3?br>QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型如下:<br> <pre>BOOL QueryPerformanceFrequency(LARGE_INTEGER QlpFrequency); BOOL QueryPerformanceCounter(LARGE_INTEGER QlpCount);</pre>   数据cdARGE_INTEGER既可以是一?字节长的整型敎ͼ也可以是两个4字节长的整型数的联合l构Q?wbr> 其具体用法根据编译器是否支持64位而定。该cd的定义如下:<br> <pre>typedef union _LARGE_INTEGER { struct { DWORD LowPart ;// 4字节整型? LONG HighPart;// 4字节整型? }; LONGLONG QuadPart ;// 8字节整型? }LARGE_INTEGER ;</pre>   在进行定时之前,先调用QueryPerformanceFrequency()函数获得机器内部定时器的旉频率Q?wbr> 然后在需要严格定时的事g发生之前和发生之后分别调用QueryPerformanceCounter()函数Q利用两ơ获得的计数之差及时钟频率,计算Z件经<wbr> 历的_旉。下列代码实?ms的精定Ӟ<br> <pre>LARGE_INTEGER litmp; LONGLONG QPart1,QPart2; double dfMinus, dfFreq, dfTim; QueryPerformanceFrequency(&litmp); dfFreq = (double)litmp.QuadPart;// 获得计数器的旉频率 QueryPerformanceCounter(&litmp); QPart1 = litmp.QuadPart;// 获得初始? do { QueryPerformanceCounter(&litmp); QPart2 = litmp.QuadPart;//获得中止? dfMinus = (double)(QPart2-QPart1); dfTim = dfMinus / dfFreq;// 获得对应的时间|单位为秒 }while(dfTim<0.001);</pre>   其定时误差不过1微秒Q精度与CPU{机器配|有兟?下面的程序用来测试函数Sleep(100)的精持l时_<br> <pre>LARGE_INTEGER litmp; LONGLONG QPart1,QPart2; double dfMinus, dfFreq, dfTim; QueryPerformanceFrequency(&litmp); dfFreq = (double)litmp.QuadPart;// 获得计数器的旉频率 QueryPerformanceCounter(&litmp); QPart1 = litmp.QuadPart;// 获得初始? Sleep(100); QueryPerformanceCounter(&litmp); QPart2 = litmp.QuadPart;//获得中止? dfMinus = (double)(QPart2-QPart1); dfTim = dfMinus / dfFreq;// 获得对应的时间|单位为秒 </pre>   ׃Sleep()函数自n的误差,上述E序每次执行的结果都会有微小误差。下列代码实?微秒的精定Ӟ<br> <pre>LARGE_INTEGER litmp; LONGLONG QPart1,QPart2; double dfMinus, dfFreq, dfTim; QueryPerformanceFrequency(&litmp); dfFreq = (double)litmp.QuadPart;// 获得计数器的旉频率 QueryPerformanceCounter(&litmp); QPart1 = litmp.QuadPart;// 获得初始? do { QueryPerformanceCounter(&litmp); QPart2 = litmp.QuadPart;//获得中止? dfMinus = (double)(QPart2-QPart1); dfTim = dfMinus / dfFreq;// 获得对应的时间|单位为秒 }while(dfTim<0.000001);</pre> 其定时误差一般不过0.5微秒Q精度与CPU{机器配|有兟?br> <p><a >CZ工程下蝲</a><br><br></p><img src ="http://www.shnenglu.com/xpzhou/aggbug/22426.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/xpzhou/" target="_blank">榕树?/a> 2007-04-20 21:03 <a href="http://www.shnenglu.com/xpzhou/archive/2007/04/20/22426.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>STL实践指南http://www.shnenglu.com/xpzhou/archive/2007/04/20/22341.html榕树?/dc:creator>榕树?/author>Fri, 20 Apr 2007 00:18:00 GMThttp://www.shnenglu.com/xpzhou/archive/2007/04/20/22341.htmlhttp://www.shnenglu.com/xpzhou/comments/22341.htmlhttp://www.shnenglu.com/xpzhou/archive/2007/04/20/22341.html#Feedback0http://www.shnenglu.com/xpzhou/comments/commentRss/22341.htmlhttp://www.shnenglu.com/xpzhou/services/trackbacks/22341.html介绍
q是一指导?zhn)如何在Microsoft Visual Studio下学习STLq进行实늚文章。这文章从STL的基知识讲vQ@序渐q,逐步深入Q涉及到了STL~写代码的方法、STL代码的编译和调试、命名空_namespaceQ、STL中的ANSI / ISO字符丌Ӏ各U不同类型的容器QcontainerQ、模板(templateQ、游标(IteratorQ、算法(AlgorithmsQ、分配器QAllocatorQ、容器的嵌套{方面的问题Q作者在q篇文章中对读者提Z一些徏议,q指Z使用STL时应该注意的问题。这文章覆盖面q,视角全面。不仅仅适合初学者学习STLQ更是广大读者用STL~程的实跉|南?


q是一指导?zhn)如何在Microsoft Visual Studio下学习STLq进行实늚文章。这文章从STL的基知识讲vQ@序渐q,逐步深入Q涉及到了STL~写代码的方法、STL代码的编译和调试、命名空_namespaceQ、STL中的ANSI / ISO字符丌Ӏ各U不同类型的容器QcontainerQ、模板(templateQ、游标(IteratorQ、算法(AlgorithmsQ、分配器QAllocatorQ、容器的嵌套{方面的问题Q作者在q篇文章中对读者提Z一些徏议,q指Z使用STL时应该注意的问题。这文章覆盖面q,视角全面。不仅仅适合初学者学习STLQ更是广大读者用STL~程的实跉|南?br>
STL?br>
STL (标准模版库,Standard Template Library)是当今每个从事C++~程的h需要掌握的一不错的技术。我觉得每一个初学STL的h应该p一D|间来熟?zhn)它,比如Q学习STL时会有急剧升降的学习曲U,q且有一些命名是不太Ҏ(gu)凭直觉就能够C的(也许是好记的名字已经被用光了Q,然而如果一旦你掌握了STLQ你׃会觉得头痛了。和MFC相比QSTL更加复杂和强大?br>STL有以下的一些优点:

可以方便Ҏ(gu)地实现搜索数据或Ҏ(gu)据排序等一pd的算法;

调试E序时更加安全和方便Q?br>
即是h们用STL在UNIXq_下写的代码你也可以很Ҏ(gu)地理解(因ؓSTL是跨q_的)?br>
背景知识

写这一部分是让一些初学计机的读者在富有挑战性的计算机科学领域有一个良好的开端,而不必费力地了解那无Ih的行话术语和沉L规则Q在q里仅仅把那些行话和规则当作STLer们用于自q创造品吧?br>
使用代码
本文使用的代码在STL实践中主要具有指导意义?br>
一些基概念的定?br>
模板QTemplateQ——类Q以及结构等各种数据cd和函敎ͼ的宏QmacroQ。有时叫做甜饼切割机Qcookie cutterQ,正规的名U应叫做范型QgenericQ——一个类的模板叫做范型类Qgeneric classQ,而一个函数的模板也自然而然地被叫做范型函数Qgeneric functionQ?br>STL——标准模板库Q一些聪明h写的一些模板,现在已成为每个h所使用的标准C++语言中的一部分?br>容器QContainerQ——可容纳一些数据的模板cRSTL中有vectorQsetQmapQmultimap和deque{容器?br>向量QVectorQ——基本数l模板,q是一个容器?br>游标QIteratorQ——这是一个奇特的东西Q它是一个指针,用来指向STL容器中的元素Q也可以指向其它的元素?br>
Hello WorldE序

我愿意在我的黄金旉在这里写下我的程序:一个hello worldE序。这个程序将一个字W串传送到一个字W向量中Q然后每ơ显C向量中的一个字W。向量就像是盛放变长数组的花园,大约所有STL容器中有一半是Z向量的,如果你掌握了q个E序Q你便差不多掌握了整个STL的一半了?br>

//E序Qvector演示一
//目的Q理解STL中的向量

// #include "stdafx.h" -如果你用预~译的头文g包含这个头文g
#include <vector>  // STL向量的头文g。这里没?.h"?br>#include <iostream>  // 包含cout对象的头文g?br>using namespace std;  //保证在程序中可以使用std命名I间中的成员?br>
char* szHW = "Hello World";  
//q是一个字W数l,?#8221;\0”l束?br>
int main(int argc, char* argv[])
{
  vector <char> vec;  //声明一个字W向量vector (STL中的数组)

  //为字W数l定义一个游标iterator?br>  vector <char>::iterator vi;

  //初始化字W向量,Ҏ(gu)个字W串q行循环Q?br>  //用来把数据填攑ֈ字符向量中,直到遇到”\0”时结束?br>  char* cptr = szHW;  // 一个指针指?#8220;Hello World”字符?br>  while (*cptr != '\0')
  {  vec.push_back(*cptr);  cptr++;  }
  // push_back函数数据放在向量的N?br>
  // 向量中的字W一个个地显C在控制?br>  for (vi=vec.begin(); vi!=vec.end(); vi++)  
  // q是STL循环的规范化的开始——通常?"!=" Q?而不?"<"
  // 因ؓ"<" 在一些容器中没有定义?
  // begin()q回向量起始元素的游标(iteratorQ,end()q回向量末尾元素的游标(iteratorQ?br>  {  cout << *vi;  }  // 使用q算W?“*” 数据从游标指针中提取出来?br>  cout << endl;  // 换行

  return 0;
}


push_back是将数据攑օvectorQ向量)或dequeQ双端队列)的标准函数。Insert是一个与之类似的函数Q然而它在所有容器中都可以用,但是用法更加复杂。end()实际上是取末֊一Q取容器中末前一个元素)Q以便让循环正确q行——它q回的指针指向最靠近数组界限的数据。就像普通@环中的数l,比如for (i=0; i<6; i++) {ar[i] = i;} ——ar[6]是不存在的,在@环中不会辑ֈq个元素Q所以在循环中不会出现问题?br>
STL的烦g一——初始化

STL令h烦恼的地Ҏ(gu)在它初始化的时候。STL中容器的初始化比C/C++数组初始化要ȝ的多。你只能一个元素一个元素地来,或者先初始化一个普通数l再通过转化填放到容器中。我认ؓZ通常可以q样做:


//E序Q初始化演示
//目的Qؓ了说明STL中的向量是怎样初始化的?br>
#include <cstring>  // <cstring>?lt;string.h>相同
#include <vector>
using namespace std;

int ar[10] = {  12, 45, 234, 64, 12, 35, 63, 23, 12, 55  };
char* str = "Hello World";

int main(int argc, char* argv[])
{
  vector <int> vec1(ar, ar+10);
  vector <char> vec2(str, str+strlen(str));
  return 0;
}



在编E中Q有很多U方法来完成同样的工作。另一U填充向量的Ҏ(gu)是用更加熟?zhn)的方括号Q比如下面的E序Q?br>
//E序Qvector演示?br>//目的Q理解带有数l下标和Ҏ(gu)LSTL向量

#include <cstring>
#include <vector>
#include <iostream>
using namespace std;

char* szHW = "Hello World";
int main(int argc, char* argv[])
{
  vector <char> vec(strlen(sHW)); //为向量分配内存空?br>  int i, k = 0;
  char* cptr = szHW;
  while (*cptr != '\0')
  {  vec[k] = *cptr;  cptr++;  k++;  }
  for (i=0; i<vec.size(); i++)
  {  cout << vec[i];  }
  cout << endl;
  return 0;
}


q个例子更加清晰Q但是对游标QiteratorQ的操作了Qƈ且定义了额外的整形数作ؓ下标Q而且Q你必须清楚地在E序中说明ؓ向量分配多少内存I间?br>
命名I间QNamespaceQ?br>
与STL相关的概忉|命名I间QnamespaceQ。STL定义在std命名I间中。有3U方法声明用的命名I间Q?br>
1Q用using关键字用这个命名空_在文件的剙Q但在声明的头文件下面加入:
using namespace std;
q对单个工程来说是最单也是最好的Ҏ(gu)Q这个方法可以把你的代码限定在std命名I间中?br>
2Q用每一个模板前Ҏ(gu)一个要使用的对象进行声明(像原Ş化)Q?br>using std::cout;
using std::endl;
using std::flush;
using std::set;
using std::inserter;
管q样写有些冗长,但可以对记忆使用的函数比较有利,q且你可以容易地声明q用其他命名空间中的成员?br>
3Q在每一ơ用std命名I间中的模版Ӟ使用std域标识符。比如:
typedef std::vector VEC_STR;
q种Ҏ(gu)虽然写v来比较冗长,但是是在混合使用多个命名I间时的最好方法。一些STL的狂热者一直用这U方法,q且把不使用q种Ҏ(gu)的h视ؓ异类。一些h会通过q种Ҏ(gu)建立一些宏来简化问题?br>
除此之外Q你可以把using namespace std加入CQ何域中,比如可以加入到函数的头部或一个控制@环体中?br>
一些徏?br>
Z避免在调试模式(debug modeQ出现恼人的警告Q用下面的~译器命令:

#pragma warning(disable: 4786)

另一条需要注意的是,你必ȝ保在两个括号之间或括号和名字之间用空格隔开Q因为是Z避免?#8220;>>”UMq算W؜淆。比?br>vector <list<int>> veclis;
q样写会报错Q而这样写Q?br>vector <list <int> > veclis;
可以避免错误?br>
                                STL实践指南Q中Q?br>
STL实践指南  Practical Guide to STL
作者:Jeff Bogan
译Q周?br>

Q接上篇Q?br>
另一U容器——集合(setQ?br>
q是微Y帮助文中对集合QsetQ的解释Q?#8220;描述了一个控制变长元素序列的对象Q注Qset中的key和value是Keycd的,而map中的key和value是一个pairl构中的两个分量Q的模板c,每一个元素包含了一个排序键Qsort keyQ和一个?value)。对q个序列可以q行查找、插入、删除序列中的Q意一个元素,而完成这些操作的旉同这个序列中元素个数的对数成比例关系Qƈ且当游标指向一个已删除的元素时Q删除操作无效?#8221;
而一个经q更正的和更加实际的定义应该是:一个集合(setQ是一个容器,它其中所包含的元素的值是唯一的。这在收集一个数据的具体值的时候是有用的。集合中的元素按一定的序排列Qƈ被作为集合中的实例。如果你需要一个键/值对QpairQ来存储数据Qmap是一个更好的选择。一个集合通过一个链表来l织Q在插入操作和删除操作上比向量(vectorQ快Q但查找或添加末元素时会有些慢?br>下面是一个例子:

//E序Qset演示
//目的Q理解STL中的集合QsetQ?br>
#include <string>
#include <set>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
  set <string> strset;
  set <string>::iterator si;
  strset.insert("cantaloupes");
  strset.insert("apple");
  strset.insert("orange");
  strset.insert("banana");
  strset.insert("grapes");
  strset.insert("grapes");  
  for (si=strset.begin(); si!=strset.end(); si++)  
  {  cout << *si << " ";  }
  cout << endl;
  return 0;
}

// 输出Q?apple banana cantaloupes grapes orange
//注意Q输出的集合中的元素是按字母大小序排列的,而且每个值都不重复?br>

如果你感兴趣的话Q你可以输出@环用下面的代码替换:

copy(strset.begin(), strset.end(), ostream_iterator<string>(cout, " "));

.集合QsetQ虽然更强大Q但我个为它有些不清晰的地方而且更容易出错,如果你明白了q一点,你会知道用集合(setQ可以做什么?br>
所有的STL容器

容器QContainerQ的概念的出现早于模板(templateQ,它原本是一个计机U学领域中的一个重要概念,但在q里Q它的概念和STL混合在一起了。下面是在STL中出现的7U容器:

vectorQ向量)——STL中标准而安全的数组。只能在vector ?#8220;前面”增加数据?br>dequeQ双端队列double-ended queueQ——在功能上和vector怼Q但是可以在前后两端向其中添加数据?
listQ列表)——游标一ơ只可以Ud一步。如果你寚w表已l很熟?zhn)Q那么STL中的list则是一个双向链表(每个节点有指向前驱和指向后的两个指针)?br>setQ集合)——包含了l过排序了的数据Q这些数据的?value)必须是唯一的?br>mapQ映)——经q排序了的二元组的集合,map中的每个元素都是׃个值组成,其中的keyQ键|一个map中的键值必L唯一的)是在排序或搜索时使用Q它的值可以在容器中重新获取;而另一个值是该元素关联的数倹{比如,除了可以ar[43] = "overripe"q样扑ֈ一个数据,mapq可以通过ar["banana"] = "overripe"q样的方法找C个数据。如果你惌得其中的元素信息Q通过输入元素的全名就可以L实现?br>multisetQ多重集Q——和集合QsetQ相|然而其中的g要求必须是唯一的(卛_以有重复Q?br>multimapQ多重映)——和映射QmapQ相|然而其中的键g要求必须是唯一的(卛_以有重复Q?br>注意Q如果你阅读微Y的帮助文,你会遇到Ҏ(gu)U容器的效率的陈q。比如:log(n*n)的插入时间。除非你要处理大量的数据Q否则这些时间的影响是可以忽略的。如果你发现你的E序有明昄滞后感或者需要处理时间攸养Itime criticalQ的事情Q你可以M解更多有兛_U容器运行效率的话题?br>
怎样在一个map中用类Q?br>
Map是一个通过keyQ键Q来获得value(?的模板类?br>另一个问题是你希望在map中用自qc而不是已有的数据cdQ比如现在已l用q的int。徏立一?#8220;为模板准备的Qtemplate-readyQ?#8221;c,你必ȝ保在该类中包含一些成员函数和重蝲操作W。下面的一些成员是必须的:

~省的构造函敎ͼ通常为空Q?br>
拯构造函?br>
重蝲?#8221;=”q算W?br>
你应该重载尽可能多的q算W来满特定模板的需要,比如Q如果你惛_义一个类作ؓ map中的键(keyQ,你必重载相关的q算W。但在这里不寚w载运符做过多讨Z?br>
//E序Q映自定义的类?br>//目的Q说明在map中怎样使用自定义的cR?br>
#include <string>
#include <iostream>
#include <vector>
#include <map>
using namespace std;

class CStudent
{
public :
  int nStudentID;
  int nAge;
public :
  //~省构造函数——通常为空
  CStudent()  {  }
  // 完整的构造函?br>  CStudent(int nSID, int nA)  {  nStudentID=nSID; nAge=nA;  }
  //拯构造函?br>  CStudent(const CStudent& ob)  
    {  nStudentID=ob.nStudentID; nAge=ob.nAge;  }
  // 重蝲“=”
  void operator = (const CStudent& ob)  
    {  nStudentID=ob.nStudentID; nAge=ob.nAge;  }
};

int main(int argc, char* argv[])
{
  map <string, CStudent> mapStudent;

  mapStudent["Joe Lennon"] = CStudent(103547, 22);
  mapStudent["Phil McCartney"] = CStudent(100723, 22);
  mapStudent["Raoul Starr"] = CStudent(107350, 24);
  mapStudent["Gordon Hamilton"] = CStudent(102330, 22);

  // 通过姓名来访问CstudentcM的成?br>  cout << "The Student number for Joe Lennon is " <<
    (mapStudent["Joe Lennon"].nStudentID) << endl;

  return 0;
}



TYPEDEF

如果你喜Ƣ用typedef关键字,下面是个例子Q?br>typedef set <int> SET_INT;
typedef SET_INT::iterator SET_INT_ITER


~写代码的一个习惯就是用大写字母和下划U来命名数据cd?br>
ANSI / ISO字符?br>
ANSI/ISO字符串在STL容器中用得很普遍。这是标准的字符串类Qƈ得到了广泛地提倡,然而在~Z格式声明的情况下׃出问题。你必须使用“<<”和输入输出流QiostreamQ代码(如dec, width{)字W串串联h?br>可在必要的时候用c_str()来重新获得字W指针?br>        
                
                                STL实践指南Q下Q?br>STL实践指南  Practical Guide to STL
作者:Jeff Bogan
译Q周?br>

Q接中篇Q?br>
游标QIteratorQ?br>
我说q游标是指针Q但不仅仅是指针。游标和指针很像Q功能很像指针,但是实际上,游标是通过重蝲一元的”*”?#8221;->”来从容器中间接地q回一个倹{将q些值存储在容器中ƈ不是一个好LQ因为每当一个新值添加到容器中或者有一个g容器中删除,q些值就会失效。在某种E度上,游标可以看作是句柄(handleQ。通常情况下游标(iteratorQ的cd可以有所变化Q这样容器也会有几种不同方式的{变:
iterator——对于除了vector以外的其他Q何容器,你可以通过q种游标在一ơ操作中在容器中朝向前的方向C步。这意味着对于q种游标你只能?#8220;++”操作W。而不能?#8220;--”?#8220;+=”操作W。而对于vectorq一U容器,你可以?#8220;+=”?#8220;?#8221;?#8220;++”?#8220;-=”中的M一U操作符?#8220;<”?#8220;<=”?#8220;>”?#8220;>=”?#8220;==”?#8220;!=”{比较运符?br>reverse_iterator ——如果你想用向后的方向而不是向前的方向的游标来遍历除vector之外的容器中的元素,你可以用reverse_iterator 来反转遍历的方向Q你q可以用rbegin()来代替begin()Q用rend()代替end()Q而此时的“++”操作W会朝向后的方向遍历?
const_iterator ——一个向前方向的游标Q它q回一个常数倹{你可以使用q种cd的游标来指向一个只ȝ倹{?br>const_reverse_iterator ——一个朝反方向遍历的游标Q它q回一个常数倹{?br>
Set和Map中的排序

除了cd和值外Q模板含有其他的参数。你可以传递一个回调函敎ͼ通常所说的声明“predicate”——这是带有一个参数的函数q回一个布?yu)|。例如,如果你想自动建立一个集合,集合中的元素按升序排列,你可以用明的Ҏ(gu)建立一个setc:

set <int, greater<int> > set1

greater 是另一个模板函敎ͼ范型函数Q,当值放|在容器中后Q它用来些值排序。如果你x降序排列q些|你可以这样写Q?br>
set <int, less<int> > set1

在实现算法时Q将声明QpredicateQ作Z个参C递到一个STL模板cM时会遇到很多的其他情况,下面会对这些情况进行详l描q?br>
STL 的烦g二——错误信?br>
q些模板的命名需要对~译器进行扩充,所以当~译器因某种原因发生故障Ӟ它会列出一D很长的错误信息Qƈ且这些错误信息晦涩难懂。我觉得处理q样的难题没有什么好办法。但最好的Ҏ(gu)是去查找q仔l研I误信息指明代码段的尾端。还有一个烦恼就是:当你双击错误信息Ӟ它会错误指向模版库的内部代码,而这些代码就更难M。一般情况下Q纠错的最好方法是重新查一下你的代码,q行时忽略所有的警告信息?br>
法QAlgorithmsQ?br>
法是模板中使用的函数。这才真正开始体现STL的强大之处。你可以学习一些大多数模板容器中都会用到的一些算法函敎ͼq样你可以通过最便的方式q行排序、查找、交换等操作。STL中包含着一pd实现法的函数。比如:sort(vec.begin()+1, vec.end()-1)可以实现寚wW一个和最后一个元素的其他元素的排序操作?br>容器自n不能使用法Q但两个容器中的游标可以限定容器中用算法的元素。既然这P法不直接受到容器的限制Q而是通过采用游标Q算法才能够得到支持。此外,很多ơ你会遇C递一个已l准备好了的函数Q以前提到的声明QpredicateQ作为参敎ͼ你也可以传递以前的旧倹{?br>下面的例子演CZ怎样使用法Q?br>
//E序Q测试分数统?br>//目的Q通过对向量中保存的分数的操作说明怎样使用法

#include <algorithm>  //如果要用算法函敎ͼ你必要包含q个头文件?br>#include <numeric>  // 包含accumulateQ求和)函数的头文g
#include <vector>
#include <iostream>
using namespace std;

int testscore[] = {67, 56, 24, 78, 99, 87, 56};

//判断一个成l是否通过了考试
bool passed_test(int n)
{
  return (n >= 60);
}

// 判断一个成l是否不及格
bool failed_test(int n)
{
  return (n < 60);
}

int main(int argc, char* argv[])
{
  int total;
  // 初始化向量,使之能够装入testscore数组中的元素
  vector <int> vecTestScore(testscore,
     testscore + sizeof(testscore) / sizeof(int));
  vector <int>::iterator vi;

  // 排序q显C向量中的数?br>  sort(vecTestScore.begin(), vecTestScore.end());
  cout << "Sorted Test Scores:" << endl;
  for (vi=vecTestScore.begin(); vi != vecTestScore.end(); vi++)
  {  cout << *vi << ", ";  }
  cout << endl;

  // 昄l计信息

  // min_element q回一?_iterator_ cd的对象,该对象指向值最的那个元素?br>  //“*”q算W提取元素中的倹{?br>  vi = min_element(vecTestScore.begin(), vecTestScore.end());
  cout << "The lowest score was " << *vi << "." << endl;

  //与min_elementcMQmax_element是选出最大倹{?br>  vi = max_element(vecTestScore.begin(), vecTestScore.end());
  cout << "The highest score was " << *vi << "." << endl;

  // 使用声明函数Qpredicate functionQ指vecTestScore.begin()和vecTestScore.end()Q来定通过考试的h数?br>  cout << count_if(vecTestScore.begin(), vecTestScore.end(), passed_test) <<
    " out of " << vecTestScore.size() <<
    " students passed the test" << endl;

  // 定有多h考试挂了
  cout << count_if(vecTestScore.begin(),
    vecTestScore.end(), failed_test) <<
    " out of " << vecTestScore.size() <<
    " students failed the test" << endl;

  //计算成Wd
  total = accumulate(vecTestScore.begin(),
     vecTestScore.end(), 0);
  // 计算昄q_成W
  cout << "Average score was " <<
    (total / (int)(vecTestScore.size())) << endl;

  return 0;
}


AllocatorQ分配器Q?br>
Allocator用在模板的初始化阶段Q是为对象和数组q行分配内存I间和释攄间操作的模板cR它在各U情况下扮演着很神U的角色Q它兛_的是高层内存的优化,而且寚w盒测试来_使用Allocator是最好的选择。通常Q我们不需要明指明它Q因为它们通常是作Z用添加的~省的参数出现的。如果在专业的测试工作中出现了AllocatorQ你最好搞清楚它是什么?br>
Embed TemplatesQ嵌入式模版Q和Derive TemplatesQ基模板Q?br>
每当你用一个普通的cȝ时候,你也可以在其中用一个STLcR它是可以被嵌入的:

class CParam
{
  string name;
  string unit;
  vector <double> vecData;
};


或者将它作Z个基c:

class CParam : public vector <double>
{
  string name;
  string unit;
};


STL模版cM为基cL需要}慎。这需要你适应q种~程方式?br>
模版中的模版

为构Z个复杂的数据l构Q你可以一个模板植入另一个模板中Q即“模版嵌套”Q。一般最好的Ҏ(gu)是在E序前面使用typedef关键字来定义一个在另一个模板中使用的模版类型?br>
// E序Q在向量中嵌入向量的演示?br>//目的Q说明怎样使用嵌套的STL容器?br>
#include <iostream>
#include <vector>

using namespace std;

typedef vector <int> VEC_INT;

int inp[2][2] = {{1, 1}, {2, 0}};  
  // 要放入模板中?x2的正则数l?br>
int main(int argc, char* argv[])
{
  int i, j;
  vector <VEC_INT> vecvec;
  // 如果你想用一句话实现q样的嵌套,你可以这样写Q?br>  // vector <vector <int> > vecvec;
  
  // 数l填入向?br>  VEC_INT v0(inp[0], inp[0]+2);  
    // 传递两个指?br>    // 数l中的值拷贝到向量?br>  VEC_INT v1(inp[1], inp[1]+2);

  vecvec.push_back(v0);
  vecvec.push_back(v1);

  for (i=0; i<2; i++)
  {
    for (j=0; j<2; j++)
    {
      cout << vecvec[i][j] << "  ";
    }
    cout << endl;
  }
  return 0;
}

// 输出Q?br>// 1 1
// 2 0


虽然在初始化时很ȝQ一旦你数据填如向量中Q你实C一个变长的可扩充的二维数组Q大可扩充直到使用完内存)。根据实际需要,可以使用各种容器的嵌套组合?br>
ȝ

STL是有用的Q但是用过E中的困隑֒ȝ是再所隑օ的。就像中国h所说的Q?#8220;如果你掌握了它,便犹如虎ȝ?#8221;


׃CSDN的文章编辑器可能?<"?>"之间的部分作为html标签qo掉了Q现贴出正确?#8220;试分数l计”E序如下Q?

//E序Q测试分数统?
//目的Q通过对向量中保存的分数的操作说明怎样使用法

#include <algorithm> //如果要用算法函敎ͼ你必要包含q个头文件?
#include <numeric> // 包含accumulateQ求和)函数的头文g
#include <vector>
#include <iostream>
using namespace std;

int testscore[] = {67, 56, 24, 78, 99, 87, 56};

//判断一个成l是否通过了考试
bool passed_test(int n)
{
return (n >= 60);
}

// 判断一个成l是否不及格
bool failed_test(int n)
{
return (n < 60);
}

int main(int argc, char* argv[])
{
int total;
// 初始化向量,使之能够装入testscore数组中的元素
vector <int> vecTestScore(testscore,
testscore + sizeof(testscore) / sizeof(int));
vector <int>::iterator vi;

// 排序q显C向量中的数?
sort(vecTestScore.begin(), vecTestScore.end());
cout << "Sorted Test Scores:" << endl;
for (vi=vecTestScore.begin(); vi != vecTestScore.end(); vi++)
{ cout << *vi << ", "; }
cout << endl;

// 昄l计信息

// min_element q回一?_iterator_ cd的对象,该对象指向值最的那个元素?
//“*”q算W提取元素中的倹{?
vi = min_element(vecTestScore.begin(), vecTestScore.end());
cout << "The lowest score was " << *vi << "." << endl;

//与min_elementcMQmax_element是选出最大倹{?
vi = max_element(vecTestScore.begin(), vecTestScore.end());
cout << "The highest score was " << *vi << "." << endl;

// 使用声明函数Qpredicate functionQ指vecTestScore.begin()和vecTestScore.end()Q来定通过考试的h数?
cout << count_if(vecTestScore.begin(), vecTestScore.end(), passed_test) <<
" out of " << vecTestScore.size() <<
" students passed the test" << endl;

// 定有多h考试挂了
cout << count_if(vecTestScore.begin(),
vecTestScore.end(), failed_test) <<
" out of " << vecTestScore.size() <<
" students failed the test" << endl;

//计算成Wd
total = accumulate(vecTestScore.begin(),
vecTestScore.end(), 0);
// 计算昄q_成W
cout << "Average score was " <<
(total / (int)(vecTestScore.size())) << endl;

return 0;
}



]]>
使用VC6.0实现H口的Q意分?/title><link>http://www.shnenglu.com/xpzhou/archive/2007/04/18/22244.html</link><dc:creator>榕树?/dc:creator><author>榕树?/author><pubDate>Wed, 18 Apr 2007 13:06:00 GMT</pubDate><guid>http://www.shnenglu.com/xpzhou/archive/2007/04/18/22244.html</guid><wfw:comment>http://www.shnenglu.com/xpzhou/comments/22244.html</wfw:comment><comments>http://www.shnenglu.com/xpzhou/archive/2007/04/18/22244.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/xpzhou/comments/commentRss/22244.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/xpzhou/services/trackbacks/22244.html</trackback:ping><description><![CDATA[<p><strong>一、关于CSplitterWndc?/strong><br> 我们在用CuteFtp或者NetAnt{工L时候,一般都会被其复杂的界面所吸引Q在q些界面中窗口被分割q的区域Q真正做CH口的Q意分剌Ӏ?那么我们自己如何创徏cM的界面,也实现窗口的L的分割呢 Q在VC6.0中这需要用到CSplitterWndcRCSplitterWnd看上d是一U特D的框架H口Q每个窗口都被相同的或者不同的视图所填充。当H口被切分后用户可以使用鼠标Ud切分条来调整H口的相对尺寸。虽然VC6.0支持从AppWizard中创建分割窗口,但是自动加入的分割条L不能让我们满意,因此我们q是通过手工增加代码来熟(zhn)这个类?<br> CSplitterWnd的构造函C要包括下面三个?<br><font color=#663333>BOOL Create(CWnd* pParentWnd,int nMaxRows,int nMaxCols,SIZE sizeMin,CCreateContext* pContext,DWORD dwStyle,UINT nID);</font> <br>    功能描述Q该函数用来创徏动态切分窗口?br>    参数含义QpParentWnd 切分H口的父框架H口?br>    nMaxRows,nMaxCols是创建的最大的列数和行数?<br>    sizeMin是窗格的现实大小?<br>    pContext 大多数情况下传给父窗口?<br>    nID是字H口的ID? <br>  <font color=#663333>BOOL CreateStatic(CWnd* pParentWnd,int nRows,int nCols,DWORD dwStyle,UINT nID) </font><br>  功能描述Q用来创建切分窗口?<br>  参数含义同上?<br><font color=#663333>BOOL CreateView (int row,int col,CruntimeClass* pViewClass,SIZE sizeinit,CcreateContext* pContext);</font> <br>  功能描述Qؓ静态切分的H口的网格填充视图。在视图于切分H口联系在一L时候必 d切分窗口创建好?<br>  参数含义Q同上?br>  从CSplitterWnd源程序可以看Z是使用动态创建Createq是使用静态创建CreateStaticQ在函数中都调用了一个保护函数CreateCommonQ从下面的CreateCommon函数中的关键代码可以看出创徏CSplitterWnd的实质是创徏了一pd的MDI子窗口?<br>    <font color=#663333>DWORD dwCreateStyle = dwStyle & ~(WS_HSCROLL|WS_VSCROLL);<br>    if (afxData.bWin4) <br>       dwCreateStyle &= ~WS_BORDER; // create with the same wnd-class as MDI-Frame (no erase bkgnd) <br>    if (!CreateEx(0, _afxWndMDIFrame, NULL, dwCreateStyle, 0, 0, 0, 0,pParentWnd->m_hWnd, (HMENU)nID, NULL)) <br>      return FALSE; // create invisible </font><br><br><strong>二、创建嵌套分割窗?/strong> <br><strong>  2.1创徏动态分割窗?/strong><br>  动态分割窗口用CreateҎ(gu)。下面的代码创?x2的窗根{?<br>  <font color=#663333>m_wndSplitter.Create(this,2,2,CSize(100,100),pContext);</font> <br>  但是动态创建的分割H口的窗格数目不能超q?x2Q而且对于所有的H格Q都必须׃n同一个视图,所受的限制也比较多Q因此我们不动态创Z为重炏V我们的主要_֊攑֜静态分割窗口的创徏上?<br>  <strong>2.2创徏静态分割窗?/strong><br>与动态创建相比,静态创建的代码要简单许多,而且可以最多创?6x16的窗根{不同的H格我们可以使用CreateView填充不同的视图?<br>在这里我们将创徏CuteFtp的窗口分剌ӀCuteFtp的分割情况如下:</p> <div align=center> <table height=223 cellSpacing=1 cellPadding=0 width=446 bgColor=#666666 border=0> <tbody> <tr bgColor=#eeeeee> <td colSpan=2 height=46> <div align=center><font face="Arial, Helvetica, sans-serif" size=2>CCuteFTPView</font></div> </td> </tr> <tr bgColor=#eeeeee> <td height=123> <div align=center><font face="Arial, Helvetica, sans-serif" size=2>CView2</font></div> </td> <td height=123> <div align=center><font face="Arial, Helvetica, sans-serif" size=2>CView3</font></div> </td> </tr> <tr bgColor=#eeeeee> <td colSpan=2 height=44> <div align=center><font face="Arial, Helvetica, sans-serif" size=2>CView4</font></div> </td> </tr> </tbody> </table> </div> <p>  创徏步骤Q?<br>  ?在创Z前我们必d用AppWizard生成单文档CuteFTPQ生成的视类?CCuteFTPView.同时在增加三个视cL者从视类l承而来的派生类CView2,CView3 CView4. <br>  ?<strong>增加成员Q?/strong> <br>  在Cmainfrm.h中我们将增加下面的代码: <br>  <font color=#663333>CSplitterWnd wndSplitter1;<br>  CSplitterWnd wndSplitter2;</font><br>  ?<strong>重蝲CMainFrame::OnCreateClient()函数Q?/strong><br>  <font color=#663333>BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext) <br>  { //创徏一个静态分栏窗口,分ؓ三行一?<br>    if(m_wndSplitter1.CreateStatic(this,3,1)==NULL) <br>      return FALSE;<br>    //CCuteFTPViewq接??列窗g<br>    m_wndSplitter1.CreateView(0,0,RUNTIME_CLASS(CCuteFTPView),CSize(100,100), pContext); <br>    m_wndSplitter1.CreateView(2,0,RUNTIME_CLASS(CView4),CSize(100,100),pContext); //CView4q接???br>    if(m_wndSplitter2.CreateStatic(&m_wndSplitter,1,2,WS_CHILD|WS_VISIBLE, m_wndSplitter.IdFromRowCol(1, 0))==NULL) <br>      return FALSE; //第1?列再分开1??<br>    //CView2c连接到W二个分栏对象的0??br>    m_wndSplitter2.CreateView(0,0,RUNTIME_CLASS(CView2),CSize(400,300),pContext); //CView3c连接到W二个分栏对象的0??br>    m_wndSplitter2.CreateView(0,1,RUNTIME_CLASS(CView3),CSize(400,300),pContext); <br>    return TRUE; <br>  } </font><br><strong>2.3实现各个分割区域的通信</strong> <br>?strong>有文档相q的视图之间的通信<br></strong>由AppWizard生成的CCuteFTPView是与文相连的,同时我们也让CView2与文档相q,因此我们需要修改CCuteFTPApp的InitInstance()函数Q我们将增加下面的部分?br><font color=#663333>AddDocTemplate (new CMultiDocTemplate(IDR_VIEW2TYPE, <br>RUNTIME_CLASS(CMainDoc), <br>RUNTIME_CLASS(CMDIChildWnd), <br>RUNTIME_CLASS(CView2))); </font><br>我们现在来实现CCuteFTPView与CView2之间的通信。由于跟文档cȝq的视图c?是不能安全的与除文档cM外的其余的视囄通信的。因此我们只能让他们都与文 c通信。在文中我们设|相应的指针以用来获的各个视图。我们重?CCuteFTPView::OnOpenDocument()函数Q?<br><font color=#663333>CCuteFTPView* pCuteFTPView;<br>CView2* pView2;<br>POSITION pos;<br>CView* pView;<br>while(pos!=NULL)<br>{<br>  pView=GetNextView(pos); <br>  if(pView->IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL) <br>    pCuteFTPView=(CCuteFTPView*)pView; <br>  else(pView->IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL) <br>    pView2=(CView2*)pView; <br>} </font><br>q样我们在文类中就L了跟它相q的所有的视图的指针?br>如果需要在 CCuteFTPView中调用CView2中的一个方法DoIt()则代码如下: <br><font color=#663333>CCuteFTPDoc* pDoc=GetDocument();<br>CView2* pView2=pDoc->pView3;<br>pView3.DoIt(); </font><br>?strong>无文视图与文档兌视图之间的通信<br></strong>CView3和CView4都是不与文档相关联的。我们现在实现CView3与CView2的通信.正如前面所_CView2只能安全的与CCuteFTPDoc通信Q因此,CView3如果需要跟CView2通信Q也必须借助于文类。因此程序的关键是如何在CView3中获得文的指针。视囄中没有这LcL员可以用来直接访问文类。但是我们知道在ȝ口类MainFrame中我们可以获得程序的LH口cȝ指针。因此我们只要获得程序主H口了的指针Q就可以解决问题了。代码实现在CView3中访问CView2中的DoIt()Ҏ(gu)?br><br>CView3中的代码如下Q?<br><br><font color=#663333>CMainFrame* MainFrame=(CMainFrame*)this->GetParent()->GetParent(); <br>CCuteFTPDoc* Doc=(CCuteFTPDoc*)MainFrame->GetActiveDocument();<br>if(Doc!=NULL) Doc->DoIt(); <br><br>CCuteFTPDoc中的相应的处理函数DoIt()代码如下Q?<br><br>CView2* pView2; <br>POSITION pos; <br>CView* pView; <br>while(pos!=NULL) <br>{ <br>  pView=GetNextView(pos);<br>  if(pView->IsKindOf(RUNTIME_CLASS(CView2))==NULL) <br>  pView2=(CView2*)pView; <br>} <br>pView2->DoIt(); </font><br>?strong>无文关联视图之间的通信<br></strong>CView3和CView4都是不跟文相连的,如何实现他们之间的通信呢?正如我们在上面所说的那样Q由于在L架中我们可以讉KL的视图,因此我们的主要Q 务还是在E序中获得主框架的指针。在CView3中访问CView4中的Ҏ(gu)DoIt()?<br><font color=#663333>CMainFrame* MainFrame=(CMainFrame*)this->GetParent()->GetParent(); <br>CView4* View4=(CView4*)MainFrame->m_wndSplitter1.GetPane(2,0); <br>View4->DoIt(); </font><br><br>到现在我们已l实CCuteFTP的主H口的框架ƈ且能够实C们之间相互通信的框架?同样的我们可以实现其他的一些流行界面例如NetAntsQFoxmail的分剌Ӏ?<br><br><strong>三、关于对话框的分?/strong> <br>到目前ؓ止,只有Z文/视图的程序才能用CSplitterWndQ而基于对话框的应用程序却不支持CSplitterWnd,但是如果我们在承类中重载一些虚拟方法,也能使CSplitterWnd 在对话框E序中用。从MFC的源E序WinSplit.cpp中可以看出,Z获得父窗口的地方E序都调用了虚拟Ҏ(gu)GetParentFrame(),因此如果在对话框中用,我们必须它改ؓGetParent();因此我们CSplitterWnd的下面几个方法重载?br>  <font color=#663333>virtual void StartTracking(int ht); <br>  virtual CWnd* GetActivePane(int* pRow = NULL, int* pCol = NULL); <br>  virtual void SetActivePane( int row, int col, CWnd* pWnd = NULL ); <br>  virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); <br>  virtual BOOL OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult ); <br>  virtual BOOL OnWndMsg( UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult ); </font><br>具体实现如下Q实C我将l出原有代码的主要部分以及修改后的代码以作对比?br>在cpp文g中加入下面的枚Dcd?<br><font color=#663333>enum HitTestValue <br>{ <br>  noHit = 0,//表示没有选中M对象<br>  vSplitterBox = 1,<br>  hSplitterBox = 2,<br>  bothSplitterBox = 3,<br>  vSplitterBar1 = 101,//代表各个方向的水q_割条<br>  vSplitterBar15 = 115,<br>  hSplitterBar1 = 201,//代表垂直方向的各个分割条<br>  hSplitterBar15 = 215,<br>  splitterIntersection1 = 301,//代表各个交叉?br>  splitterIntersection225 = 525<br>};<br><br>CWnd* CxSplitterWnd::GetActivePane(int* pRow, int* pCol)<br>{<br>  ASSERT_VALID(this); <br>  //获得当前的获得焦点的H口<br>  //下面注释_体的是原有的代码的主要部分?br>  // CWnd* pView = NULL;<br>  //CFrameWnd* pFrameWnd = GetParentFrame();<br>  //ASSERT_VALID(pFrameWnd);<br>  //pView = pFrameWnd->GetActiveView();<br>  //if (pView == NULL)<br>  // pView = GetFocus();<br>  CWnd* pView = GetFocus();<br>  if (pView != NULL && !IsChildPane(pView, pRow, pCol))<br>    pView = NULL;<br>  return pView; <br>} <br><br>void CxSplitterWnd::SetActivePane( int row, int col, CWnd* pWnd) <br>{<br>  CWnd* pPane = pWnd == NULL ? GetPane(row, col) : pWnd; <br>  //下面加注释粗体的是原有代码的主要部分?br>  //FrameWnd* pFrameWnd = GetParentFrame();<br>  //ASSERT_VALID(pFrameWnd); <br>  //pFrameWnd->SetActiveView((CView*)pPane); <br>  pPane->SetFocus();//修改后的语句 <br>}<br><br>void CxSplitterWnd::StartTracking(int ht)<br>{<br>  ASSERT_VALID(this); <br>  if (ht == noHit) <br>    return;<br>  // GetHitRect will restrict 'm_rectLimit' as appropriate <br>  GetInsideRect(m_rectLimit);<br>  if (ht >= splitterIntersection1 && ht <= splitterIntersection225) <br>  { <br>    // split two directions (two tracking rectangles) <br>    int row = (ht - splitterIntersection1) / 15; <br>    int col = (ht - splitterIntersection1) % 15; <br>    GetHitRect(row + vSplitterBar1, m_rectTracker); <br>    int yTrackOffset = m_ptTrackOffset.y; <br>    m_bTracking2 = TRUE; <br>    GetHitRect(col + hSplitterBar1, m_rectTracker2); <br>    m_ptTrackOffset.y = yTrackOffset; <br>  } <br>  else if (ht == bothSplitterBox) <br>  { <br>  // hit on splitter boxes (for keyboard) <br>  GetHitRect(vSplitterBox, m_rectTracker); <br>  int yTrackOffset = m_ptTrackOffset.y; <br>  m_bTracking2 = TRUE; <br>  GetHitRect(hSplitterBox, m_rectTracker2); <br>  m_ptTrackOffset.y = yTrackOffset; // center it <br>  m_rectTracker.OffsetRect(0, m_rectLimit.Height()/2); m_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 0); <br>  } <br>  else<br>  { <br>  // only hit one bar <br>  GetHitRect(ht, m_rectTracker); <br>  } <br><br>//下面加注释的从E序中删厅R?<br>//CView* pView = (CView*)GetActivePane(); <br>//if (pView != NULL && pView->IsKindOf(RUNTIME_CLASS(CView))) <br>//{ <br>// ASSERT_VALID(pView); <br>// CFrameWnd* pFrameWnd = GetParentFrame(); <br>//ASSERT_VALID(pFrameWnd); <br>//pView->OnActivateFrame(WA_INACTIVE, pFrameWnd); <br>// } <br>// steal focus and capture<br>  SetCapture();<br>  SetFocus();<br>  // make sure no updates are pending <br>  RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); <br>  // set tracking state and appropriate cursor<br>  m_bTracking = TRUE;<br>  OnInvertTracker(m_rectTracker); <br>  if (m_bTracking2) <br>    OnInvertTracker(m_rectTracker2); <br>  m_htTrack = ht; <br>  SetSplitCursor(ht); <br>  }<br><br>BOOL CxSplitterWnd::OnCommand(WPARAM wParam, LPARAM lParam) <br>{ <br>  if (CWnd::OnCommand(wParam, lParam)) <br>    return TRUE; <br>  //下面_体的是原程序的语句 <br>//<strong>return GetParentFrame()->SendMessage(WM_COMMAND, wParam, lParam); </strong><br>  return GetParent()->SendMessage(WM_COMMAND, wParam, lParam); <br>}<br>BOOL CxSplitterWnd::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult )<br>{<br>  if (CWnd::OnNotify(wParam, lParam, pResult)) <br>    return TRUE; <br>  //下面_体的是源程序的语句<br>  //<strong>*pResult = GetParentFrame()->SendMessage(WM_NOTIFY, wParam, lParam);</strong><br>  *pResult = GetParent()->SendMessage(WM_NOTIFY, wParam, lParam);<br>  return TRUE;<br>} <br><br>BOOL CxSplitterWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) <br>{ <br>  // The code line below is necessary if using CxSplitterWnd in a regular dll <br>  // AFX_MANAGE_STATE(AfxGetStaticModuleState());<br>  return CWnd::OnWndMsg(message, wParam, lParam, pResult); <br>} </font><br>q样我们可以在对话框中使用CxSplitterWndcM?<br><br><strong>四、CSplitterWnd的扩?/strong> <br>CSplitterWnd扩展话题是很多的Q我们可以通过对原有方法的覆盖或者增加新的方法来扩展CSplitterWnd。我们在此仅举两个方面的例子?<br><strong>4.1锁定切分?/strong><br>当用户创建好分割H口后,有时q不希望通过拖动切分条来调节H口的大。这时就必须锁定切分条。锁定切分条的最单的Ҏ(gu)莫过于不让CSplitterWnd来处理WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_SETCURSOR消息Q而是这些消息交lCWndH口q行处理Q从而屏蔽掉q些消息。拿WM_LBUTTONDOWN处理q程来说。修改ؓ如下Q?<br><font color=#663333>void CXXSplitterWnd::OnLButtonDown(UINT nFlags,CPoint point) <br>{ <br>  CWnd::OnLButtonDown(nFlags,point);<br>} </font><br>其余的处理方法类伹{?<br><strong>4.2切分条的定制</strong> <br>由Window自己生成的切分条L固定的,没有M的变化,我们在用一些Y件比如ACDSee的时候却能发现它们的切分条却是和自动生成的切分条不一L。那么如何定制自q切分条呢Q通过重蝲CSplitterWnd的虚Ҏ(gu)OnDrawSplitter和OnInvertTracker可以辑ֈq样的目的。下面的代码生成的效果是分割H口的边界颜色ؓU色Q分割条的颜色ؓl色.代码如下Q?br><font color=#663333>void CSplitterWndEx::OnDrawSplitter(CDC *pDC, ESplitType nType, const CRect &rectArg)<br>{<br>  if(pDC==NULL) <br>  { <br>  RedrawWindow(rectArg,NULL,RDW_INVALIDATE|RDW_NOCHILDREN);<br>  return;<br>  } <br>  ASSERT_VALID(pDC);<br>  CRect rc=rectArg;<br>  switch(nType) <br>  { <br>  case splitBorder:<br>  //重画分割H口边界,使之为红?<br>    pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0));<br>    rc.InflateRect(-CX_BORDER,-CY_BORDER); <br>    pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0)); <br>    return; <br>  case splitBox:<br>    pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));<br>    rc.InflateRect(-CX_BORDER,-CY_BORDER); <br>    pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));<br>    rc.InflateRect(-CX_BORDER,-CY_BORDER);<br>    pDC->FillSolidRect(rc,RGB(0,0,0)); <br>    pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));<br>    return; <br>  case splitBar: <br>  //重画分割条,使之为绿?<br>    pDC->FillSolidRect(rc,RGB(255,255,255));<br>    rc.InflateRect(-5,-5); <br>    pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0)); <br>    return; <br>  default: <br>    ASSERT(FALSE); <br>  } <br>  pDC->FillSolidRect(rc,RGB(0,0,255));<br>} <br>void CSplitterWndEx::OnInvertTracker(CRect &rect) <br>{ <br>  ASSERT_VALID(this);<br>  ASSERT(!rect.IsRectEmpty()); <br>  ASSERT((GetStyle()&WS_CLIPCHILDREN)==0);<br>  CRect rc=rect; <br>  rc.InflateRect(2,2);<br>  CDC* pDC=GetDC(); <br>  CBrush* pBrush=CDC::GetHalftoneBrush();<br>  HBRUSH hOldBrush=NULL;<br>  if(pBrush!=NULL) hOldBrush=(HBRUSH)SelectObject(pDC->m_hDC,pBrush->m_hObject);<br>  pDC->PatBlt(rc.left,rc.top,rc.Width(),rc.Height(),BLACKNESS); <br>  if(hOldBrush!=NULL) <br>  SelectObject(pDC->m_hDC,hOldBrush);<br>  ReleaseDC(pDC); <br>} </font><br>同样我们只要l承CSplitterWnd中的其余的一些虚拟方法就可以生成h自己个性的分割H口了?br></p> <img src ="http://www.shnenglu.com/xpzhou/aggbug/22244.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/xpzhou/" target="_blank">榕树?/a> 2007-04-18 21:06 <a href="http://www.shnenglu.com/xpzhou/archive/2007/04/18/22244.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vc自定义消息的发送与接收的方法实?/title><link>http://www.shnenglu.com/xpzhou/archive/2007/04/18/22185.html</link><dc:creator>榕树?/dc:creator><author>榕树?/author><pubDate>Wed, 18 Apr 2007 00:52:00 GMT</pubDate><guid>http://www.shnenglu.com/xpzhou/archive/2007/04/18/22185.html</guid><wfw:comment>http://www.shnenglu.com/xpzhou/comments/22185.html</wfw:comment><comments>http://www.shnenglu.com/xpzhou/archive/2007/04/18/22185.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/xpzhou/comments/commentRss/22185.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/xpzhou/services/trackbacks/22185.html</trackback:ping><description><![CDATA[<div> <p><span style="FONT-WEIGHT: bold">以下用一个自创的对话框类(MyMessageDlg)向视囄(MessageTestView)<br>发送自定义消息ZQ说明这两种不同Ҏ(gu)的自定义消息?/span></p> <p><span style="COLOR: rgb(255,0,0)">消息传递的Ҏ(gu)一Q用ON_MESSAGE<br></span>使用ON_MESSAGE响应消息Q必配合定义消?define WM_MY_MESSAGE (WM_USER+100)</p> <p>对于<span style="COLOR: rgb(0,0,255)">发送消息?/span>-MyMessageDlgQ?br>在其MyMessageDlg.h中,定义#define WM_MY_MESSAGE (WM_USER+100)<br>在其MyMessageDlg.cpp中要先添加:Qi nclude "MainFrm.h"<br>因ؓ使用了CMainFrame*定义对象?br>q且要有试消息的函敎ͼ<br>void MyMessageDlg::OnButtonMsg()<br>{<br>    // TODO: Add your control notification handler code here<br>    CMainFrame* pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd;  //先通过获取当前框架指针<br>    CView * active = pMF->GetActiveView();//才能获取当前视类指针<br>    if(active != NULL)  //获取了当前视cL针才能发送消?br>    active->PostMessage(WM_MY_MESSAGE,0,0);   //使用PostMessage发送消?br>}</p> <p>对于<span style="COLOR: rgb(51,0,255)">消息的接受?/span>-MessageTestViewQ?br>在其MessageTestView.h中,也要定义#define WM_MY_MESSAGE (WM_USER+100)<br>q定义消息映函?OnMyMessage()<br>protected:<br> //{{AFX_MSG(CMessageTestView)<br> afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);<br> //}}AFX_MSG<br> DECLARE_MESSAGE_MAP()<br>在其MessageTestView.cpp中,<br>先要声明响应消息Q?br>BEGIN_MESSAGE_MAP(CMessageTestView, CEditView)<br> //{{AFX_MSG_MAP(CMessageTestView)<br> ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)<br> //}}AFX_MSG_MAP<br>再添加消息响应的函数实现Q?br>LRESULT CMessageTestView::OnMyMessage(WPARAM wParam, LPARAM lParam)<br>{<br> MessageBox("OnMyMessage!");<br> return 0;<br>}</p> <p><br><span style="COLOR: rgb(255,0,0)">消息传递的Ҏ(gu)二:使用ON_REGISTERED_MESSAGE<br></span>使用ON_REGISTERED_MESSAGE注册消息Q必配?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");</p> <p>对于<span style="COLOR: rgb(213,43,111)">消息的发送?/span>-MyMessageDlgQ?br>在其MyMessageDlg.h中,只要<br>定义static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");<br>可以了?br>在其MyMessageDlg.cpp中要先添加:Qi nclude "MainFrm.h"<br>因ؓ使用了CMainFrame*定义对象?br>q且要有试消息的函敎ͼ<br>void MyMessageDlg::OnButtonMsg()<br>{<br>    // TODO: Add your control notification handler code here<br>    CMainFrame* pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd;  //先通过获取当前框架指针<br>    CView * active = pMF->GetActiveView();//才能获取当前视类指针<br>    if(active != NULL)  //获取了当前视cL针才能发送消?br>    active->PostMessage(WM_MY_MESSAGE,0,0);   //使用PostMessage发送消?br>}</p> <p>对于<span style="COLOR: rgb(204,51,112)">消息的接收?/span>-MessageTestViewQ?br>在其MessageTestView.h中不要定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");<br>应该把这个定义放到MessageTestView.cpp中,要不会出? redefinition<br>在其MessageTestView.h中只要定义消息映函?br>protected:<br> //{{AFX_MSG(CMessageTestView)<br> afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);<br> //}}AFX_MSG<br> DECLARE_MESSAGE_MAP()<br>在其MessageTestView.cpp?先定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");<br>接着注册消息Q?br>BEGIN_MESSAGE_MAP(CMessageTestView, CEditView)<br> //{{AFX_MSG_MAP(CMessageTestView)<br>        ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage)<br> //}}AFX_MSG_MAP<br>最后添加消息响应的函数实现Q?br>LRESULT CMessageTestView::OnMyMessage(WPARAM wParam, LPARAM lParam)<br>{<br> MessageBox("OnMyMessage!");<br> return 0;<br>}<br>----------------------------------------------------------------<br>比较两种Ҏ(gu)Q只是略有不同。但也要心谨慎Q以免出现接收不到消息的情况?/p> <p>-------------------------------------------------------------------</p> <p>其他注意事项Q?/p> <p>发送消息的-MyMessageDlg.cpp前也要定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");</p> <p>接受消息?MessageTestView.cpp前也要定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");</p> <p>RegisterWindowMessage("Message")?"的内Ҏ(gu)什么不重要Q写什么都可以Q但?br>发送者与接受者必L一L内容Q例如:"Message"</p> </div> <img src ="http://www.shnenglu.com/xpzhou/aggbug/22185.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/xpzhou/" target="_blank">榕树?/a> 2007-04-18 08:52 <a href="http://www.shnenglu.com/xpzhou/archive/2007/04/18/22185.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.uniontruck.cn" target="_blank">þþƷ2020</a>| <a href="http://www.shinehall.cn" target="_blank">ݺɫþþۺ</a>| <a href="http://www.ppzof.cn" target="_blank">þó˹Ʒ</a>| <a href="http://www.jhitezpt.cn" target="_blank">ŷAŷaþ</a>| <a href="http://www.yzlxdr.cn" target="_blank">Ʒþþþþ</a>| <a href="http://www.yoliuping.cn" target="_blank">þˬˬƬAV </a>| <a href="http://www.yichengsh.com.cn" target="_blank">ഺþ</a>| <a href="http://www.hdv1p7.cn" target="_blank">޾ƷĻþò</a>| <a href="http://www.wnlv.cn" target="_blank">þþž޾Ʒ</a>| <a href="http://www.elecline.com.cn" target="_blank">ۺϾƷþ</a>| <a href="http://www.oysport.cn" target="_blank">޹Ʒþһ</a>| <a href="http://www.peizis.cn" target="_blank">һaƬþëƬ</a>| <a href="http://www.pyqf.net.cn" target="_blank">þþƷ99þ˿</a>| <a href="http://www.cnnsmi.org.cn" target="_blank">޾þһح </a>| <a href="http://www.taoxh.cn" target="_blank">鶹wwwþùƷ</a>| <a href="http://www.vnkp.cn" target="_blank">츾޾þĻ</a>| <a href="http://www.spinpizza.cn" target="_blank">þþƷ?Ļ</a>| <a href="http://www.juzijia.cn" target="_blank">޾Ʒþþþþο</a>| <a href="http://www.hhabg.com.cn" target="_blank">ŷһƷþ</a>| <a href="http://www.biaopie.cn" target="_blank">þþƷަvDz</a>| <a href="http://www.lvomb.cn" target="_blank">99þwww˳ɾƷ</a>| <a href="http://www.moonlong.cn" target="_blank">ŷһþۺ</a>| <a href="http://www.vtqqv.cn" target="_blank">þþþþëƬѿ</a>| <a href="http://www.chenghuilin.cn" target="_blank">ݺɫþۺ</a>| <a href="http://www.shangbi.com.cn" target="_blank">ŷ龫Ʒþþþþþ</a>| <a href="http://www.naoshengzhao.cn" target="_blank">99þѹػ</a>| <a href="http://www.daliandamingda.cn" target="_blank">ھƷþ</a>| <a href="http://www.lslscy.cn" target="_blank">ɫۺϺϾþۿ</a>| <a href="http://www.zhaiseng.cn" target="_blank"> þۺϾɫۺϾ99</a>| <a href="http://www.botouvr.cn" target="_blank">߳߳þþ</a>| <a href="http://www.jjzrhg.cn" target="_blank">þþþavۺϲҰ</a>| <a href="http://www.ssui1.cn" target="_blank">ۺϾþþƷ</a>| <a href="http://www.worktrotter.cn" target="_blank">Ʒһþþ</a>| <a href="http://www.u24373.cn" target="_blank">ھƷ˾þþӰԺ</a>| <a href="http://www.sfwan.cn" target="_blank">þ޹ӰԺ</a>| <a href="http://www.zenavo.cn" target="_blank">ɫ99þþþø߳ۺӰԺ</a>| <a href="http://www.zhjcys.cn" target="_blank">þþƷƷ</a>| <a href="http://www.lxldb.cn" target="_blank">þþþƵ</a>| <a href="http://www.1rizu.cn" target="_blank">޾Ʒþò</a>| <a href="http://www.lc351.cn" target="_blank">ŷպƷþ </a>| <a href="http://www.122797929.cn" target="_blank">޺ݺۺϾþѿ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>