??xml version="1.0" encoding="utf-8" standalone="yes"?>
/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>
DWORD dwStart = GetTickCount(); DWORD dwEnd = dwStart; do { dwEnd = GetTickCount()-dwStart; }while(dwEnd <50);ZGetTickCount()函数在g时或定时期间能处理其他的消息Q可以把代码改ؓQ?br>
DWORD dwStart = GetTickCount(); DWORD dwEnd = dwStart; do { MSG msg; GetMessage(&msg,NULL,0,0); TranslateMessage(&msg); DispatchMessage(&msg); dwEnd = GetTickCount()-dwStart; }while(dwEnd <50);虽然q样可以降低CPU的占有率Qƈ在g时或定时期间也能处理其他的消息,但降低了延时或定时精度?br> 方式五:与GetTickCount()函数cM的多媒体定时器函数DWORD timeGetTime(void)Q该函数定时_?wbr> 度ؓmsU,q回从Windows启动开始经q的毫秒数。微软公司在其多媒体Windows中提供了_定时器的?wbr> 层API持,利用多媒体定时器可以很精地dpȝ的当前时_q且能在非常_的时间间隔内完成一
MMRESULT timeSetEventQ?UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, WORD dwUser, UINT fuEvent Q?/pre> 该函数设|一个定时回调事Ӟ此事件可以是一个一ơ性事件或周期性事件。事件一旦被Ȁz,便调用指定的回调函数Q?wbr> 成功后返回事件的标识W代码,否则q回NULL。函数的参数说明如下Q?br>uDelayQ以毫秒指定事g的周期? UresolutionQ以毫秒指定延时的精度,数D定时器事g分L率越高。缺省gؓ1ms? LpTimeProcQ指向一个回调函数? DwUserQ存攄h供的回调数据? FuEventQ指定定时器事gcdQ? TIME_ONESHOTQuDelay毫秒后只产生一ơ事? TIME_PERIODIC Q每隔uDelay毫秒周期性地产生事g?具体应用Ӟ可以通过调用timeSetEvent()函数Q将需要周期性执行的d定义在LpTimeProc回调函数?如:定时采样、控制等)Q从而完成所需处理的事件。需要注意的是,d处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后, 应及时调用timeKillEvent()之释放?
方式七:对于_度要求更高的定时操作Q则应该使用QueryPerformanceFrequency()?wbr> QueryPerformanceCounter()函数。这两个函数是VC提供的仅供Windows 95及其后箋版本使用的精时间函敎ͼq要求计机从硬件上支持_定时器。如CZ工程中的Timer7、Timer7_1、Timer7_2、Timer7_3?br>QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型如下:
BOOL QueryPerformanceFrequency(LARGE_INTEGER QlpFrequency); BOOL QueryPerformanceCounter(LARGE_INTEGER QlpCount);数据cdARGE_INTEGER既可以是一?字节长的整型敎ͼ也可以是两个4字节长的整型数的联合l构Q?wbr> 其具体用法根据编译器是否支持64位而定。该cd的定义如下:
typedef union _LARGE_INTEGER { struct { DWORD LowPart ;// 4字节整型? LONG HighPart;// 4字节整型? }; LONGLONG QuadPart ;// 8字节整型? }LARGE_INTEGER ;在进行定时之前,先调用QueryPerformanceFrequency()函数获得机器内部定时器的旉频率Q?wbr> 然后在需要严格定时的事g发生之前和发生之后分别调用QueryPerformanceCounter()函数Q利用两ơ获得的计数之差及时钟频率,计算Z件经历的_旉。下列代码实?ms的精定Ӟ
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);其定时误差不过1微秒Q精度与CPU{机器配|有兟?下面的程序用来测试函数Sleep(100)的精持l时_
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;// 获得对应的时间|单位为秒׃Sleep()函数自n的误差,上述E序每次执行的结果都会有微小误差。下列代码实?微秒的精定Ӟ
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);其定时误差一般不过0.5微秒Q精度与CPU{机器配|有兟?br>
]]>
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;
}
CCuteFTPView
|
|
CView2
|
CView3
|
CView4
|
创徏步骤Q?
?在创Z前我们必d用AppWizard生成单文档CuteFTPQ生成的视类?CCuteFTPView.同时在增加三个视cL者从视类l承而来的派生类CView2,CView3 CView4.
?增加成员Q?/strong>
在Cmainfrm.h中我们将增加下面的代码:
CSplitterWnd wndSplitter1;
CSplitterWnd wndSplitter2;
?重蝲CMainFrame::OnCreateClient()函数Q?/strong>
BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
{ //创徏一个静态分栏窗口,分ؓ三行一?
if(m_wndSplitter1.CreateStatic(this,3,1)==NULL)
return FALSE;
//CCuteFTPViewq接??列窗g
m_wndSplitter1.CreateView(0,0,RUNTIME_CLASS(CCuteFTPView),CSize(100,100), pContext);
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)
return FALSE; //第1?列再分开1??
//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);
return TRUE;
}
2.3实现各个分割区域的通信
?strong>有文档相q的视图之间的通信
由AppWizard生成的CCuteFTPView是与文相连的,同时我们也让CView2与文档相q,因此我们需要修改CCuteFTPApp的InitInstance()函数Q我们将增加下面的部分?br>AddDocTemplate (new CMultiDocTemplate(IDR_VIEW2TYPE,
RUNTIME_CLASS(CMainDoc),
RUNTIME_CLASS(CMDIChildWnd),
RUNTIME_CLASS(CView2)));
我们现在来实现CCuteFTPView与CView2之间的通信。由于跟文档cȝq的视图c?是不能安全的与除文档cM外的其余的视囄通信的。因此我们只能让他们都与文 c通信。在文中我们设|相应的指针以用来获的各个视图。我们重?CCuteFTPView::OnOpenDocument()函数Q?
CCuteFTPView* pCuteFTPView;
CView2* pView2;
POSITION pos;
CView* pView;
while(pos!=NULL)
{
pView=GetNextView(pos);
if(pView->IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL)
pCuteFTPView=(CCuteFTPView*)pView;
else(pView->IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL)
pView2=(CView2*)pView;
}
q样我们在文类中就L了跟它相q的所有的视图的指针?br>如果需要在 CCuteFTPView中调用CView2中的一个方法DoIt()则代码如下:
CCuteFTPDoc* pDoc=GetDocument();
CView2* pView2=pDoc->pView3;
pView3.DoIt();
?strong>无文视图与文档兌视图之间的通信
CView3和CView4都是不与文档相关联的。我们现在实现CView3与CView2的通信.正如前面所_CView2只能安全的与CCuteFTPDoc通信Q因此,CView3如果需要跟CView2通信Q也必须借助于文类。因此程序的关键是如何在CView3中获得文的指针。视囄中没有这LcL员可以用来直接访问文类。但是我们知道在ȝ口类MainFrame中我们可以获得程序的LH口cȝ指针。因此我们只要获得程序主H口了的指针Q就可以解决问题了。代码实现在CView3中访问CView2中的DoIt()Ҏ(gu)?br>
CView3中的代码如下Q?
CMainFrame* MainFrame=(CMainFrame*)this->GetParent()->GetParent();
CCuteFTPDoc* Doc=(CCuteFTPDoc*)MainFrame->GetActiveDocument();
if(Doc!=NULL) Doc->DoIt();
CCuteFTPDoc中的相应的处理函数DoIt()代码如下Q?
CView2* pView2;
POSITION pos;
CView* pView;
while(pos!=NULL)
{
pView=GetNextView(pos);
if(pView->IsKindOf(RUNTIME_CLASS(CView2))==NULL)
pView2=(CView2*)pView;
}
pView2->DoIt();
?strong>无文关联视图之间的通信
以下用一个自创的对话框类(MyMessageDlg)向视囄(MessageTestView)
发送自定义消息ZQ说明这两种不同Ҏ(gu)的自定义消息?/span>
消息传递的Ҏ(gu)一Q用ON_MESSAGE
使用ON_MESSAGE响应消息Q必配合定义消?define WM_MY_MESSAGE (WM_USER+100)
对于发送消息?/span>-MyMessageDlgQ?br>在其MyMessageDlg.h中,定义#define WM_MY_MESSAGE (WM_USER+100)
在其MyMessageDlg.cpp中要先添加:Qi nclude "MainFrm.h"
因ؓ使用了CMainFrame*定义对象?br>q且要有试消息的函敎ͼ
void MyMessageDlg::OnButtonMsg()
{
// TODO: Add your control notification handler code here
CMainFrame* pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd; //先通过获取当前框架指针
CView * active = pMF->GetActiveView();//才能获取当前视类指针
if(active != NULL) //获取了当前视cL针才能发送消?br> active->PostMessage(WM_MY_MESSAGE,0,0); //使用PostMessage发送消?br>}
对于消息的接受?/span>-MessageTestViewQ?br>在其MessageTestView.h中,也要定义#define WM_MY_MESSAGE (WM_USER+100)
q定义消息映函?OnMyMessage()
protected:
//{{AFX_MSG(CMessageTestView)
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
在其MessageTestView.cpp中,
先要声明响应消息Q?br>BEGIN_MESSAGE_MAP(CMessageTestView, CEditView)
//{{AFX_MSG_MAP(CMessageTestView)
ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
//}}AFX_MSG_MAP
再添加消息响应的函数实现Q?br>LRESULT CMessageTestView::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
MessageBox("OnMyMessage!");
return 0;
}
消息传递的Ҏ(gu)二:使用ON_REGISTERED_MESSAGE
使用ON_REGISTERED_MESSAGE注册消息Q必配?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
对于消息的发送?/span>-MyMessageDlgQ?br>在其MyMessageDlg.h中,只要
定义static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
可以了?br>在其MyMessageDlg.cpp中要先添加:Qi nclude "MainFrm.h"
因ؓ使用了CMainFrame*定义对象?br>q且要有试消息的函敎ͼ
void MyMessageDlg::OnButtonMsg()
{
// TODO: Add your control notification handler code here
CMainFrame* pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd; //先通过获取当前框架指针
CView * active = pMF->GetActiveView();//才能获取当前视类指针
if(active != NULL) //获取了当前视cL针才能发送消?br> active->PostMessage(WM_MY_MESSAGE,0,0); //使用PostMessage发送消?br>}
对于消息的接收?/span>-MessageTestViewQ?br>在其MessageTestView.h中不要定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message"); ------------------------------------------------------------------- 其他注意事项Q?/p>
发送消息的-MyMessageDlg.cpp前也要定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message"); 接受消息?MessageTestView.cpp前也要定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message"); RegisterWindowMessage("Message")?"的内Ҏ(gu)什么不重要Q写什么都可以Q但?br>发送者与接受者必L一L内容Q例如:"Message"
应该把这个定义放到MessageTestView.cpp中,要不会出? redefinition
在其MessageTestView.h中只要定义消息映函?br>protected:
//{{AFX_MSG(CMessageTestView)
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
在其MessageTestView.cpp?先定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
接着注册消息Q?br>BEGIN_MESSAGE_MAP(CMessageTestView, CEditView)
//{{AFX_MSG_MAP(CMessageTestView)
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage)
//}}AFX_MSG_MAP
最后添加消息响应的函数实现Q?br>LRESULT CMessageTestView::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
MessageBox("OnMyMessage!");
return 0;
}
----------------------------------------------------------------
比较两种Ҏ(gu)Q只是略有不同。但也要心谨慎Q以免出现接收不到消息的情况?/p>
]]>