VC精华讲义2010最新.doc_第1页
VC精华讲义2010最新.doc_第2页
VC精华讲义2010最新.doc_第3页
VC精华讲义2010最新.doc_第4页
VC精华讲义2010最新.doc_第5页
已阅读5页,还剩73页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

在VC+中,对于自定义的菜单,图标,光标,对话框等都是以资源的形式进行管理的,它们的定义与描述存放在资源文件中(扩展名为.rc),资源文件是文本格式,读者可以用notepad.exe打开,阅读里面的信息。在VC+中是以“所见即所得”的方式打开资源文件的,在编辑窗口中看到的和编辑完后的结果即程序运行时的效果。对于每一个资源及资源中的子项都是用一个标识号来标识的,通常称为ID,同一个ID可以标识多个不同的资源。注意区别资源的ID号与句柄的区别,ID号是应用程序指定的,可以在资源还没在内存中产生前指定,也可在设计阶段就指定,基本上是固定的。而句柄则是资源在内存中产生时由操作系统临时安排的,每次产生的句柄可能都不一样,一个ID号标识的资源可在内存中产生多个实例句柄。资源文件中的ID标识符必须在resouce.h头文件中用宏定义成一个整数,这样程序中用到的一个ID号标识符实际上就是那个整数。LoadIcon的第二个参数是LPCTSTR类型,用goto definition功能发现它实际被定义成CONST CHAR *,是字符串常量指针,而图标的ID是一个整数。参看msdn中的提示,对于这样的情况我们需用MAKEINTRESOURCE这个宏把资源ID标识符转换为需要的LPCTSTR类型。使用goto definition功能,或在MSDN中都可以看到MAKEINTRESOURCE的定义: #define MAKEINTRESOURCE(i) (LPTSTR) (DWORD) (WORD) (i)之所以可以这样做,是因为字符串变量本身代表的就是一个字符数组的首地址,本身就是一个数字。所以字符串变量可以类型转换成整数,反之,一个整数也可以类型转换成字符串型。hCursor成员指定了这一类型窗口的光标句柄,LoadCursor函数可以加载一个光标资源到内存中并返回系统分配给该光标的句柄。除了加载的是光标外,其特点与LoadIcon函数一样。hbrBackground成员指定了这一类型窗口重画时所使用的刷子句柄。当窗口重画时会使用这里指定的刷子去刷新窗口背景。刷子是具有颜色和形状的,我们可以使用GetStockObject返回一个系统刷子,也可以直接使用msdn中提供的宏,如COLOR_WINDOWTEXT,还可以用CreateBrushIndirect函数产生具有一定形状的刷子。由于GetStockObject参数能够返回标准的刷子、笔、字体、调色板等图形设备对象,定义该函数时,是无法确定该函数到底返回的是刷子还是笔,所以该函数返回类型是HGDIOBJECT(图形设备对象的总称)。由于编译器的需要,在这里我们必须HGDIOBJECT转换成HBRUSH。顺便提示:在VC+开发Windows程序中,类型转换的频率非常高,在这有必要重点介绍一下。比如有个函数为“去叫一个人来帮忙”,定义该函数时,其返回值只能是“人”,但实际来的“人”,要么是“男人”,要么是“女人”。即使叫来的是一个“男人”,如果将该函数的返回值直接赋给一个“男人”类型的变量,编译时是没法确定返回的是“男人”,还是“女人”,将不会通过。只有我们写程序的人才知道运行时返回的是“男人”,还是“女人”,我们可以对返回值进行类型转换,以便编译器通过。在类型转换时,程序员要对转换完的后果负责,要确保在内存中存在的对象本身确实可以被看成那种要转换成的类型,如果来的是“女人”,我们将其转换成“男人”后,编译能够通过,但程序运行时将会出错。作者在编码和调试时,总是用意境的方式,仿佛看到变量或对象在内存中的真实布局和状态,以及是如何进行转换的,这样编码时比较容易一气呵成,极少犯错。lpszMenuName成员指定了这一类型窗口的菜单。可见菜单本身不是一个窗口,同图标、光标一样,是窗口的一个元素。不少的人和书都错以为菜单也是一个窗口,其实我们用Spy+实用工具的Find Window功能就能够区分出桌面上的哪些元素为窗口,哪些不是。lpszMenuName是LPCTSTR类型,需用MAKEINTRESOURCE这个宏把资源ID标识符转换为lpszMenuName需要的LPCTSTR类型。lpszClassName成员指定了这一类型窗口的名称,是字符串变量。与设计一辆新型汽车后,要为该汽车型号指定名称一样,设计了一种新型窗口后,也要为这种新型窗口起个名称。我们先将这里的名称指定成,等会我们将看到如何使用这个名称。设计完WNDCLASS后,需调用RegisterClass函数对其进行注册,以后便可以用CreateWindow函数产生这种类型的窗口窗口了。CreateWindow函数的定义如下:HWND CreateWindow( LPCTSTR lpClassName, / pointer to registered class name LPCTSTR lpWindowName, / pointer to window name DWORD dwStyle, / window style int x, / horizontal position of window int y, / vertical position of window int nWidth, / window width int nHeight, / window height HWND hWndParent, / handle to parent or owner window HMENU hMenu, / handle to menu or child-window identifier HANDLE hInstance, / handle to application instance LPVOID lpParam / pointer to window-creation data);参数lpClassName即我们刚才在WNDCLASS的lpszClassName成员指定的名称,在这里应该为,表示要产生这一类型的窗口。产生窗口的过程是由操作系统完成的,如果在调用CreateWindow函数之前,还没有用RegisterClass函数注册过名称为的窗口类型,操作系统无法得知这种窗口类型的配置信息,窗口产生过程失败。参数lpWindowName指定产生的窗口实例上显示的标题文字。参数dwStyle指定产生的窗口实例的样式,就象同一型号的汽车可以有不同的颜色一样,同一型号的窗口也可以有不同的外观样式。要注意区别WNDCLASS中的style成员与参数dwStyle,前者是针对一个大类,后者是针对个别。参数x,y,nWidth,nHeight指定了窗口左上角的x,y坐标,窗口的宽度,高度。如果x被设置成CW_USEDEFAULT,系统将窗口的左上角设置为确省值,参数y将被忽略。如果nWidth被设置成CW_USEDEFAULT,系统将窗口的大小设置为确省值,参数nHeight将被忽略。参数lpWindowName指定了窗口的父窗口句柄。窗口之间可以组合成父子关系,子窗口必须具有WS_CHILD样式,当父窗口被破坏,隐藏,移动,显示时,也会破坏,隐藏,移动,显示子窗口。当lpWindowName为NULL时,桌面就成为当前窗口的父窗口。参数lpWindowName指定了窗口的菜单或子窗口句柄。参数hInstance指定了窗口所属的应用程序的句柄。参数lpParam可以为窗口附加补充信息。如果窗口创建成功,函数将返回系统为该窗口分配的句柄,否则,返回NULL。6.消息循环通常的消息循环代码如下:MSG msg;while(GetMessage(&msg,NULL,0,0) TranslateMessage(&msg); DispatchMessage(&msg);GetMessage函数从应用程序消息队列中取走一条消息,该函数的原型如下:BOOL GetMessage( LPMSG lpMsg, / address of structure with message HWND hWnd, / handle of window UINT wMsgFilterMin, / first message UINT wMsgFilterMax / last message);参数lpMsg是接受消息的变量的指针。参数hWnd指定了接收属于哪个窗口的消息。参数wMsgFilterMin,wMsgFilterMax指定了接受某一范围内的消息。如果队列中没有满足条件的消息,该函数将一直等待,不会返回。除了WM_QUIT消息外,该函数返回非零值,对WM_QUIT消息,该函数返回零。也就是说,只有收到WM_QUIT消息,上述代码才能退出while循环,程序才有可能结束运行。TranslateMessage函数对取道的消息进行转换。用户按动一下某个键,系统将发出WM_KEYDOWN, WM_KEYUP,并且参数中提供的是该键的虚拟扫描码。但有时用户按动一下某个键, 我们想得到一条表示用户输入了某个字符的消息,并在消息补充参数中提供字符的编码。TranslateMessage能将可行的WM_KEYDOWN, WM_KEYUP消息对转换成一条WM_CHAR消息,将可行的WM_SYSKEYDOWN, or WM_SYSKEYUP消息对转换成一条WM_SYSCHAR消息,并将转换后得到的新消息投递到程序的消息队列中。转换过程不会影响原来的消息,只在消息队列中增加新消息。DispatchMessage函数将取道的消息传递到窗口的回调函数中去处理。可以理解成该函数通知操作系统,让操作系统去调用窗口的回调函数来处理收到的消息。所有Windows程序的消息处理代码基本上都是相同的,如没特殊需要,可以照搬照抄上述代码。顺便提示:从队列中取消息还有PeekMessage函数,PeekMessage函数有两种取消息的方式,第一种与GetMessage一样,从队列中直接取走消息,第二种是只取消息的一个副本,并不将消息从队列中取走。无论哪种方式,PeekMessage都不会因队列中没有满足条件的消息而阻塞,当取到满足条件的消息,该函数返回非零值反之,返回零。向队列中发送消息有PostMessage和SendMessage,PostMessage函数发送消息后立即返回,而SendMessage需等到发送的消息被处理完后才能返回。还有一个PostThreadMessage用于向线程发送消息,关于线程,请在以后的章节再学,但我们也因此想到消息不一定总是与窗口相关的,也就是说,对于某些消息,其对应的MSG结构中的hwnd可以为NULL。7.回调函数回调函数的原型为:LRESULT CALLBACK WindowProc( HWND hwnd, / handle to window UINT uMsg, / message identifier WPARAM wParam, / first message parameter LPARAM lParam / second message parameter);我们可以将函数名WindowProc改为我们喜欢的名称,如DefWndProc,该函数的四个参数对应消息的窗口句柄,消息码,消息码的两个补充参数。 在该函数内部是一个庞大的switch语句,用于对各种感兴趣的消息进行处理。我们分析程序中的代码。LRESULT CALLBACK DefWndProc( HWND hWnd,UINT Msg,WPARAM wParam, LPARAM lParam)HDC hDC;switch(Msg)case WM_CHAR:char str20;sprintf(str,the char code is %d,wParam);MessageBox(hWnd,str,,MB_OKCANCEL);break;case WM_LBUTTONDOWN:MessageBox(hWnd,mouse click,,MB_OK);hDC=GetDC(hWnd);TextOut(hDC,LOWORD(lParam),HIWORD(lParam), ,strlen();ReleaseDC(hWnd,hDC);break;case WM_CLOSE:if(IDOK=MessageBox(NULL,真的要要退出吗?,,MB_OKCANCEL|MB_ICONQUESTION)DestroyWindow(hWnd);break;case WM_PAINT:PAINTSTRUCT ps;hDC=BeginPaint(hWnd,&ps);/在WM_PAINT里必须用这个函数TextOut(hDC,0,0,,strlen();EndPaint(hWnd,&ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return(DefWindowProc(hWnd,Msg, wParam,lParam );return (0);当用户在窗口上按下一个字符键,程序将得到一条WM_CHAR消息,参看msdn,在其wParam参数中含有字符的码值。使用程序中的代码,我们可以随时获得某个字符的码值,不用为此去专门查找书籍。MessageBox函数可以弹出一个显示信息的对话框,如果我们按下BackSpace键,在这里将弹出the char code is 8消息。当用户在窗口上按下鼠标左按钮时,程序弹出一条消息框对收到的WM_LBUTTONDOWN进行响应,以证明按下鼠标左按钮动作与WM_LBUTTONDOWN消息的这种对应关系,另外程序还将在窗口上鼠标所按下的位置写上一串文字。当我们要在窗口上写字、绘图,并不直接在这些设备上操作,而是在一个称为设备描述表(Device Contexts,简称DC)的资源上操作的。使用DC,程序不用为图形的显示与打印输出分别单独处理了。无论是打印还是显示,我们都是在DC上操作,然后由DC映射到这些设备上。使用DC,我们不用担心程序在不同的硬件上执行的差异性,DC能够为我们装载合适的设备驱动程序,实现程序的图形操作与底层设备无关。GetDC函数能够返回同窗口相关连的DC的句柄。TextOut函数在当前DC上指定的位置输出一个字符串,当按下鼠标左按钮,消息WM_LBUTTONDOWN的补充参数lParam中含有鼠标位置的x,y坐标,其中的低16位含有x坐标,高16位含有y坐标,可以分别通过LOWORD,HIWORD宏获得。对于每次成功调用GetDC返回的DC句柄,在执行完所有的图形操作后,必须调用ReleaseDC释放该句柄所占用的资源。否则,会造成内存泄露。我曾经帮助一个叫王健的学员调试他的On-job项目程序,他发现他的程序所占用的内存总是以4k的增量向上增长,每运行几小时后,程序便因内存不足而崩溃了。后来发现就是因为程序在定时器中反复使用GetDC而没有使用ReleaseDC释放造成的。读者可以将例子程序中的ReleaseDC一句注释掉,编译后运行,在NT4.0/win2000下启动任务管理器,切换到进程标签,查看你的程序所使用的内存量,在程序中不断点击鼠标左按钮,程序将不断调用GetDC函数,你将发现你的程序占用的内存量不断向上增长,我们通常使用这样的方式来检测程序的内存泄露的。当用户点击窗口上的关闭按钮时,系统将给应用程序发送一条WM_CLOSE消息,如果程序不做进一步处理,窗口是不会关闭的。我们在程序中利用一个选择对话框,如果用户确认真的要退出,程序调用DestroyWindow函数将窗口关闭。窗口关闭后,系统将给应用程序发送一条WM_DESTROY消息,需要注意的是,主窗口的关闭,不代表应用程序结束,在WinMain函数中的消息循环代码中,GetMessage函数必须取到一条WM_QUIT,消息循环才能结束。要让程序正常退出,必须在WM_DESTROY消息响应代码中,调用PostQuitMessage函数向程序的消息队列中发送一条WM_QUIT消息,PostQuitMessage函数的参数值传递给WM_QUIT消息的wParam参数,通常用作WinMain函数的返回值。当窗口第一次产生,移动,改变大小,从其他窗口后面切换到前面等情况都会导致窗口的重画。重画时将使用设计窗口类时指定的刷子粉刷窗口的背景,窗口上原有的文字和图形都将被擦除掉。要想让图形和文字总显示在窗口的表面,只能是在这些图形和文字被擦除后,立即又将它们画上去。这个过程对用户来说,是感觉不到的,他们只能感觉到这些图形和文字永远都和窗口一并存在。当系统粉刷完窗口的背景后,都会发送一条WM_PAINT消息,以便通知应用程序原有的图形和文字已被擦除,如果还想保留哪些图形和文字,请在此处加入处理代码。也就是说,我们在WM_PAINT消息响应中作出的图形和文字是“永远”存在的。对于WM_PAINT消息响应代码中要获得窗口的DC,只能使用BeginPaint函数,除此之外的消息响应代码中必须用GetDC获得窗口的DC,BeginPaint获得的DC最后必须用EndPaint释放。提醒:水平或垂直改变窗口的大小时,窗口是否重画,取决于WNDCLASS结构中style成员的设置中是否包含CS_VREDRAW与CS_HREDRAW。DefWindowProc函数提供了对所有消息的缺省处理方式,对于大多数不想特殊处理的消息,程序都可以调用这个函数来处理,所以程序在switch的default语句中调用此函数进行处理。8.程序编写操作步骤与实验。1) 首先启动VC+,在菜单中选择File-New,在弹出的窗体中选择Projects标签,然后在左侧选择Windows Application, 在右侧的Project name:文本框中为新建的工程起一个名字,VC+会为新建的工程在硬盘上建一个与工程同名的文件夹,这个文件夹放在Location:指定的路径下,你可以点击Location旁边的.按钮来改变路径。接下来一定要选择Create new workspace单选按钮,并勾选Platforms:中的Win32复选框。完成后的界面如图1-1所示:2) 这一课对第一次接触Windows编程的读者来说,新的东西太多。但只要你把这些知识基本理解和掌握,学好VC+的日子离你就不太遥远了。惟有如此,你才可能精通VC+编程。第二课:C+经典知识回顾一、类的定义与应用在C语言中,我们学过结构体,用于将描述某一对象的若干变量包装成一个整体使用,但没有但没有将与该对象相关的函数包含进来。C语言中的结构体只能描述一个对象的特征(属性),不能描述一个对象的动作(方法)。在C+中,我们是通过类的定义来解决这个问题的,在类的定义中,不仅可以包含变量,还可以包含函数。我们通过一段程序来讲解类的使用。#include iostream.hclass CPointpublic:int x1;int y1;void Output();CPoint();CPoint(int x2,int y2)CPoint();private:int x2;int y2;int *pCount;/注意类和结构定义完后,一定要用;号结尾,忘记;是许多人常犯的错误。/在c+中,/.用于注释一行,/*.*/可以注释多行。void CPoint:Output()if(pCount)(*pCount)+;elsepCount=new int;*pCount=1;coutthe first point is (x1,y1)endl;coutthe second point is (x2,y2)endl;CPoint:CPoint()pCount=0;coutthe first constructor is callingx2=x2;this-y2=y2;pCount=0;coutthe second constructor is callingendl;CPoint:CPoint()if(pCount)cout你调用了Output成员函数共*pCount次endl;delete pCount;elsecout你还没有调用过Output成员函数endl;coutthe deconstructor is callingendl;void Output(CPoint pt)coutthe first point is (pt.x1,pt.y1)endl;/coutthe second point is (pt.x2,pt.y2)endl;/上面被注释的语句会造成编译错误,因为不能从类的外部访问类中的私有成员。void main()if(1=1)/限定pt变量的有效范围CPiont pt;coutpt.x1pt.y1;/pt.x2=10;/pt.y2=10;/上面被注释的语句会造成编译错误,因为不能从类的外部访问类中的私有成员。pt.Output();pt.Output();pt.Output();/故意演示Output被调用多次的情况。Output(pt);CPoint pt(10,10);pt.Output();上面的代码定义了一个类CPoint,其中包含有变量,称之为成员变量,也包含有函数的声明,称之为成员函数。在类定义之外,我们必须对成员函数进行实现,成员函数的实现格式为:返回类型类名:函数名(参数列表)函数体代码上面的代码也编写了一个名为Output的全局函数,注意与类CPoint中的Output成员函数区别。上面的代码还编写了一个main主函数,其中的代码演示了如何使用CPoint类。C+中提供了一套输入输出流方法的对象,它们是cint和cout,cerr,对应c语言中的三个文件指针stdin,stdout,stderr,分别指向终端输入、终端输出和标准出错输出(也从终端输出)。cin与一起完成输入操作,cout,cerr与成员的方式访问其它的成员,如CPoint(int x2,int y2)函数中用this-x2访问成员变量x2。在成员函数中,我们通常可以省略this-,直接访问类中的成员变量。在CPoint(int x2,int y2)函数中,由于函数参数变量x2,y2与成员CPoint中的成员变量x2,y2同名,要在该函数中访问成员变量x2,y2,可用this-x2,this-y2与参数变量x2,y2区分。小技巧:在以后的MFC编程中,如果在成员函数中想调用同类中的某个成员,可以使用VC+提供的自动列出成员函数功能,使用this-,VC+将列出该类中的所有成员,我们可以从列表中选择我们想调用的成员。自动列出成员函数功能,可以提高编写速度,减少拼写错误。特别是我们不能完全记住某个函数的完整拼写,但却能够从列表中辨别出该函数时,自动列出成员函数功能更是有用。事实上,在各种IDE编程环境中,我们通常都没有完全记住某些函数的完整拼写,只是记住其大概写法和功能,要调用该函数时都是从自动列出成员函数中选取的。这样能够大大节省我们的学习时间,我们没有花大量的时间去死记硬背许多函数,利用自动列出成员函数功能和帮助系统,却也能够在编程使顺利使用这些函数,等用的次数多了,也就在不知不觉中完全掌握了这些函数。注意比较Output全局函数与Output成员函数的差别。对Output全局函数的调用,可以理解成“输出某个pt点的坐标”,是一种谓宾关系,是面向过程(或函数)Output的。对Output成员函数的调用,可以理解成“pt这个点对象执行输出动作”,是面向对象pt的。希望通过这样的比较,能够有助于读者理解c+中关于面向对象的概念。四、类的继承与protected访问修饰符:类是可以继承的,如果类B继承了类A,我们称A为基类(也叫父类),B为派生类(也叫子类)。派生类不但拥有自己新的成员变量和成员函数,还可以拥有基类的成员变量和成员函数。派生类的定义方法是:class 派生类名:访问权限 基类名称.;要实现类B与类A的继承关系,我们在定义类B之前必须已定义了类A,并用如下的格式定义类B。class B:public或private A.;讲到类的继承后,我们再讲解另一种成员访问权限修饰符,protected。public,protected,private三种访问权限的比较:public定义的成员可以被在任何地方访问。protected定义的成员只能在该类及其子类中访问。private定义的成员只能在该类自身中访问。派生类可以用public和private两种访问权限继承基类中的成员,如果在定义派生类时没有指定如何继承访问权限,则默认为private。如果派生类以private继承基类的访问权限,基类中的成员在派生类中都变成private类型的访问权限。如果派生类以public继承基类的访问权限,基类中的成员在派生类中仍以原来的访问权限在派生类中出现。注意:基类中的private成员不能被子类访问,所以private成员不能被子类所继承。我们分析如下代码:class CAnimalpublic:void eat();void breathe();void CAnimal:eat()couteatingendl;void CAnimal:breathe()coutbreathingendl;class CFish:public CAnimalpublic:void swim();void breathe();void CFish:swim()coutswimmingendl;void CFish:breathe()CAnimal:breathe();coutbreathingbreathe();关于类的继承及类的访问特性可以参照如下表:基类的访问特性类的继承特性子类的访问特性Public Protected PrivatePublicPublic Protected No access1Public Protected PrivateProtectedProtected Protected No access1Public Protected PrivatePrivatePrivate Private No access1由于CFish继承了CAnimal,所以在main函数中用CFish定义的对象f可以将CAnimal中定义的eat()成员函数当作自己的成员函数调用。f还调用了CFish中新定义的成员函数swim()。对象f还调用了breathe()函数,大家发现在基类CAnimal和派生类CFish中都定义了breathe函数,在这种情况下调用的到底是哪个类中定义的函数呢?在这里,调用的是子类CFish中定义的函数。如果在子类与父类中都定义了同样的函数,当用子类定义的对象调用这个函数时,调用的是子类定义的函数,这就是函数的覆盖。函数的覆盖,我们可以用生活中的例子来比喻,儿子继承了父亲的许多方法,包括“结婚”这一行为,但父亲“结婚”用的是花轿,而儿子“结婚”用的却是汽车,儿子不能使用父亲“结婚”的方式。如果儿子结婚时,即要花轿,也要汽车,也就是在子类的成员函数定义中,要调用父类中定义的那个被覆盖的成员函数,其语法为,父类名:函数名(参数)。如CFish定义的breathe函数中使用的CAnimal:breathe()语句,就是调用CAnimal中的breathe函数。在程序中main函数的结尾处的代码:CAnimal *pA;pA=&f;pA-breathe();上述代码定义了一个CAnimal类型的指针pA,pA指向CFish定义的对象f的地址,用指针pA去调用breathe函数,在这种情况下调用的到底是哪个类中定义的函数呢?简单的死记硬背只能管一时,不能管一世。我们还是从类型转换的原理上寻找答案。将鱼CFish对象的首地址直接赋值给动物CAnimal类型的指针变量,是不用强制类型转换的,编译器能够自动完成这种转换,子类对象指针能够隐式转换成父类指针。这个过程好比现实生活中将一条鱼当作一个动物是没有什么问题的,但要将一个动物当作鱼来对待是存在问题的。如果某一动物确实是一条鱼,我们就可以将这个动物强制类型转换成鱼。也就是说,要将父类类型的对象转换成子类对象,在程序中必须强制类型转换,编译才能通过,但要保证内存中的对象确实是那种被转换成的类型,程序在运行时才不会有问题。我们可以这样想象类型转换,用目标类型的内存布局,去套取要类型转换的对象的首地址开始的那一段内存块(大小为目标类型的大小),套取的内容即为转换后的结果。见图x,&f转换成pA后,转换完后的内容包含的breathe是CAnimal中定义的那个。五、虚函数与多态性。如果我们在CAnimal中定义的void breathe()函数前增加virtual关键字,即改为如下定义:class CAnimalpublic:void eat();virtual void breathe();则上面的代码CAnimal *pA;pA=&f;pA-breathe();中breathe调用的是CFish中定义的那个,这就是编译器对虚函数调用的编译方式,这就是虚拟函数的多态性。如果在某个类的成员函数定义前加了virtual,这个函数就是虚函数,如果子类中有对该函数的覆盖定义,无论该覆盖定义是否有virtual关键字,都是虚拟函数。五、类的书写规范与如何解决头文件重复引用问题。操作符重载,匈牙利命名法。类继承中的构造函数调用顺序与指定父类中的构造函数。关于完整的c+语法讲解,需要厚厚的一大本书,如果读者需要深入了解,请参看相关书籍。但只要掌握了本课中介绍的关于C+的知识,基本上就能够顺利学习以后的章节了,如有特殊需求,我们将在以后章节中用到时专门讲解。我们认为抱着问题学习的效果要比泛泛而学的效果好得多,并且学到一个新知识后马上便能看到其应用更能令人记忆深刻,举一反三。实验步骤:观察构造函数与析构函数的调用时机。第三课:MFC思想学完第一课的Windows程序运行原理及第二课经典C+知识回顾,这一课我们主要来看看MFC是如何用面向对象的方式对传统的面象过程的Windows程序运行原理代码进行封装的。先看看第一课中的Winmain()代码int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)WNDCLASS wndClass;wndClass.style=CS_HREDRAW;wndClass.lpfnWndProc=(WNDPROC)DefWndProc;wndClass.cbClsExtra=0;wndClass.cbWndExtra=0; wndClass.hInstance=hInstance;wndClass.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1); wndClass.hCursor=LoadCursor(hInstance,MAKEINTRESOURCE(IDC_CURSOR1); LOGBRUSH lgbr;lgbr.lbStyle=BS_SOLID;lgbr.lbColor=RGB(192,192,0);lgbr.lbHatch=0;wndClass.hbrBackground=CreateBrushIndirect(&lgbr);wndClass.lpszMenuName=NULL; wndClass.lpszClassName=xxxxx;RegisterClass(&wndClass);HWND hWnd;hWnd=CreateWindow(xxxxx,,WS_OVERLAPPEDWIN

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论