《VisualC++程序设计》由会员分享,可在线阅读,更多相关《VisualC++程序设计(604页珍藏版)》请在金锄头文库上搜索。
1、VisualC+程序设计程序设计张张淼淼哈尔滨工业大学(威海)计算机学院哈尔滨工业大学(威海)计算机学院o课程安排n授课24学时n实验16学时o考试:n平时成绩(作业+出勤)15%n实验成绩15%n考试70%2计算机科学与技术学院张淼VisualC+到底是什么?到底是什么?3计算机科学与技术学院张淼C语言自产生以来,出现了许多语言自产生以来,出现了许多C语言的集语言的集成开发环境,如成开发环境,如TurboC、BorlandC等,等,在这些集成开发环境中,程序员可以将代在这些集成开发环境中,程序员可以将代码的编辑、编译、连接、执行和调试过程码的编辑、编译、连接、执行和调试过程全部完成。全部完成
2、。回顾回顾4计算机科学与技术学院张淼面向对象的程序设计语言面向对象的程序设计语言C+产生之后,产生之后,又出现了又出现了BorlandC+、C+Builder和和VisualC+等针对等针对C+语言的集成开语言的集成开发环境。虽然这些发环境。虽然这些C+集成开发环境是针集成开发环境是针对对C+语言的,而且增加了许多其它特性,语言的,而且增加了许多其它特性,然而单就然而单就C程序来讲,如果符合程序来讲,如果符合ANSIC的的标准,在这些集成环境中都能够很好地编译标准,在这些集成环境中都能够很好地编译和连接。和连接。5计算机科学与技术学院张淼VC+主要是用来开发主要是用来开发Windows应应用程
3、序的。用程序的。Windows程序设计不同程序设计不同于于DOSDOS下的程序设计,它是一种下的程序设计,它是一种事件驱事件驱动动的程序设计模式,主要是基于的程序设计模式,主要是基于消息消息的。的。6计算机科学与技术学院张淼VisualC+oWindows环境下最主要的应用开发系统之环境下最主要的应用开发系统之一。一。oC+语言的可视化集成开发环境。语言的可视化集成开发环境。o强大的调试功能为大型复杂软件的开发提供强大的调试功能为大型复杂软件的开发提供了有效的排错手段。了有效的排错手段。7计算机科学与技术学院张淼使用使用VC+进行进行Windows应用程序应用程序设计时,有两种方法:一是使用设
4、计时,有两种方法:一是使用PlatformSDK,另一种方法是直,另一种方法是直接使用接使用Microsoft提供的提供的MFC类库类库。8计算机科学与技术学院张淼PlatformSDK(softwaredevelopkit):使用使用C语言和语言和Win32API(ApplicationProgrammingInterface,应用程序编,应用程序编程接口程接口)函数进行编程。函数进行编程。MFC:使用使用C+语言和语言和MFC(微软基础类库微软基础类库)进行进行编程编程.9计算机科学与技术学院张淼VisualC+ProgrammingMFCProgramming10计算机科学与技术学院张淼
5、SDKMFC简单、易于理解简单、易于理解工作量大、效率低工作量大、效率低复杂,代码可读性差复杂,代码可读性差工作量小,效率高工作量小,效率高11计算机科学与技术学院张淼SDK编程方式易于理解编程方式易于理解Windows工作原理。工作原理。通过了解相对已通过了解相对已“过时过时”的的Win32SDK编编程程,有助于理解有助于理解以后的很多东西!以后的很多东西!12计算机科学与技术学院张淼C+/MFC程序设计必须跨越的四大技术障碍程序设计必须跨越的四大技术障碍o面向对象观念与C+语言oWindows程序基本观念oMicrosoftFoundationClasses(MFC)本身oVisualC+
6、集成开发环境与各种开发工具(难度不高,但需熟练)13计算机科学与技术学院张淼课程安排课程安排o学时安排学时安排n24学时学时o课程内容课程内容nWindows编程基础编程基础o3学时学时n面向对象程序设计和面向对象程序设计和C+语言基础(书语言基础(书1-3章)章)o13学时学时nMFC(MicrosoftFoundationClasses)(书)(书4-9章)章)o8学时学时14计算机科学与技术学院张淼推荐书籍推荐书籍oC+编程思想(第编程思想(第2版)版)nBruceEckel,机械工业出版社,机械工业出版社oC+Primer(第(第3版)中文版版)中文版nStanleyB.Lippman
7、,JoseeLajoie,中国电力出版社,中国电力出版社oWindows程序设计(第程序设计(第5版)版)nCharlesPetzold,北京大学出版社,北京大学出版社oMFCWindows程序设计(第程序设计(第2版)版)nJeffProsise,清华大学出版社,清华大学出版社o深入浅出深入浅出MFC(第二版)(第二版)n侯俊杰,华中科技大学出版社侯俊杰,华中科技大学出版社oVisualC+技术内幕技术内幕nGeorgeShepherd,DavidKruglinski,清华大学出版社,清华大学出版社o深入解析深入解析MFC(MFCInternals)nGeorgeShepherd,中国电力出
8、版社中国电力出版社15计算机科学与技术学院张淼第一部分第一部分Windows编程基础编程基础16计算机科学与技术学院张淼oWindows程序内部运行原理程序内部运行原理oSDK方式编写方式编写windows应用程序应用程序oWindows应用程序特性应用程序特性17计算机科学与技术学院张淼CH1.1Windows程序内部运行原理程序内部运行原理o目标:理解Windows程序的运行机制o掌握以下基本概念:n窗口nAPIn消息与消息机制n消息响应n句柄18计算机科学与技术学院张淼WindowsWindows应用程序,操作系统,计算机硬件输入输出设备应用程序,操作系统,计算机硬件输入输出设备应用程序
9、,操作系统,计算机硬件输入输出设备应用程序,操作系统,计算机硬件输入输出设备之间的相互关系之间的相互关系之间的相互关系之间的相互关系应用程序应用程序操作系统操作系统输入输出设备输入输出设备消息消息队列队列19计算机科学与技术学院张淼API操作系统所能够完成的每一个特殊功能通常都有一个函数与其对应,也就是说,操作系统把它所能够完成的功能以函数的形式提供给应用程序使用,应用程序对这些函数的调用就叫做系统调用(系统调用(Systemcall),这些函数的集合就是这些函数的集合就是Windows操作系统提操作系统提供给应用程序编程的接口供给应用程序编程的接口(ApplicationProgrammin
10、gInterface),简称简称WindowsAPI。20计算机科学与技术学院张淼APIo什么是什么是API?nApplicationProgrammingInterfaceoAPI的作用的作用n是是Windows系统与系统与Windows应用程序间的应用程序间的标准程序接口标准程序接口nWindows应用程序可以利用标准大量应用程序可以利用标准大量API函函数调用数调用系统功能系统功能o窗口管理函数窗口管理函数:实现窗口的创建、移动和修改功能:实现窗口的创建、移动和修改功能o系统服务函数系统服务函数:实现与操作系统有关的多种功能:实现与操作系统有关的多种功能o图形设备(图形设备(GDI)函数
11、)函数:实现与设备无关的图形操:实现与设备无关的图形操作功能作功能21计算机科学与技术学院张淼WindowsWindows应用程序,操作系统,计算机硬件输入输出设备应用程序,操作系统,计算机硬件输入输出设备应用程序,操作系统,计算机硬件输入输出设备应用程序,操作系统,计算机硬件输入输出设备之间的相互关系之间的相互关系之间的相互关系之间的相互关系应用程序应用程序操作系统操作系统输入输出设备输入输出设备消息消息队列队列22计算机科学与技术学院张淼消息响应消息响应操作系统能够感知输入设备的变化(事件),并且能够知道具体的事件情况,但操作系统并不决定对这一事件如何作出反应,而是将这一事件转交给应用程序
12、,由应用程序决定如何对这一事件作出反应。对事件作出反应的过程就是消消息响应息响应。23计算机科学与技术学院张淼消息消息操作系统是怎样将感知到的事件传递给应用程序的呢?这是通过消息消息机制机制(Message)来实现的。操作系统将每个事件都包装成一个称为消消息的结构体息的结构体MSG来传递给应用程序。24计算机科学与技术学院张淼消息消息MSG结构定义如下:typedefstructtagMSGHWNDhwnd;UINTmessage;WPARAMwParam;LPARAMlParam;DWORDtime;POINTpt;MSG;25计算机科学与技术学院张淼消息消息o消息结构体消息结构体MSGn主
13、消息:主消息:由事先定义好的消息名标识由事先定义好的消息名标识n附加消息:与主消息有关附加消息:与主消息有关owParamolParamtypedefstructtagMSGHWNDhwnd;/窗口句柄窗口句柄UINTmessage;/主消息主消息WPARAMwParam;/附加消息附加消息LPARAMlParam;DWORDtime;/送至队列的时间送至队列的时间POINTpt;/消息发送时屏幕光标的位置消息发送时屏幕光标的位置MSG,*PMSG;26计算机科学与技术学院张淼oWindows窗口是窗口是Windows系统的一个内系统的一个内部数据结构的实例,由一个部数据结构的实例,由一个“窗
14、口句柄窗口句柄”标标识,识,Windows系统创建它并给它分配系统系统创建它并给它分配系统资源。资源。oWindowsObject是是Windows系统的内系统的内部结构,通过一个句柄来引用;部结构,通过一个句柄来引用;27计算机科学与技术学院张淼句柄(句柄(Handle)oo句柄(HANDLE),资源的标识。oo操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源。按资源的类型,又可将句柄细分成图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄(HINSTANCE)等等各种类型的句柄。操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄。28计算
15、机科学与技术学院张淼从变量的类型区分变量的用途从变量的类型区分变量的用途intint x,yx,y; ;x=50;x=50;y=30;y=30;/x/x和和y y既可以用来表示坐标点,也可以用来表示既可以用来表示坐标点,也可以用来表示宽度和高度,还可以用来表示身高和体重等等。宽度和高度,还可以用来表示身高和体重等等。typedeftypedef intintWIDTHWIDTHtypedeftypedef intintHEIGHTHEIGHTWIDTHx;WIDTHx;HEIGHTy;HEIGHTy;/好处:我们从变量的类型上就可以知道好处:我们从变量的类型上就可以知道好处:我们从变量的类型上
16、就可以知道好处:我们从变量的类型上就可以知道x x和和和和y y是是是是用来表示宽度和高度。用来表示宽度和高度。用来表示宽度和高度。用来表示宽度和高度。29计算机科学与技术学院张淼typedefstructtagPOINTLONGx;LONGy;POINT;30计算机科学与技术学院张淼o对于MSG这个结构体来说,它里面包含的信息是相当丰富的,它包含了对于一个消息来说,它和哪一个窗口相关,这个消息本身是什么,这个消息的附加参数是什么,消息发生投递的时间是什么。我们拿到这样一个消息就像当全面了。那么我们就知道应该做什么样的处理。31计算机科学与技术学院张淼WindowsWindows应用程序,操作
17、系统,计算机硬件输入输出设备应用程序,操作系统,计算机硬件输入输出设备应用程序,操作系统,计算机硬件输入输出设备应用程序,操作系统,计算机硬件输入输出设备之间的相互关系之间的相互关系之间的相互关系之间的相互关系应用程序应用程序操作系统操作系统输入输出设备输入输出设备消息消息队列队列32计算机科学与技术学院张淼消息队列消息队列对于每一个应用程序,操作系统会给它建立一个消息队列。这个队列实际上是一个先进先出先进先出的缓冲区,通常是一个某种变量类型的数组。消息队列中的每个元素都是一条消息。操作系统将生成的每个消息按先后顺序放进消息队列中。应用程序总是依次取走队列里的第一条消息。应用程序取走消息后便能
18、够知道用户的操作和程序状态的变化,从而对特定的消息进行处理(编写代码)消息响应。33计算机科学与技术学院张淼34计算机科学与技术学院张淼CH1.2SDK方式编写方式编写windows应用程序应用程序o目标:能够用SDK(WindowsAPI+C)编写一个简单的windows应用程序,通过编写程序掌握Windows程序的运行原理及编写方式。为MFC的学习打下基础。35计算机科学与技术学院张淼程序执行的起点(入口函数)?main()WinMain()36计算机科学与技术学院张淼WinMain函数函数Windows程序的入口函数程序的入口函数intWINAPIWinMain(HINSTANCE hI
19、nstance,/handletocurrentinstanceHINSTANCE hPrevInstance,/handletopreviousinstanceLPSTR lpCmdLine,/commandlineint nCmdShow/showstate);37计算机科学与技术学院张淼匈牙利表示法匈牙利表示法o一种命名约定一种命名约定匈牙利命名法是微软推广的一种关于变量、匈牙利命名法是微软推广的一种关于变量、函数、对象、前缀、宏定义等各种类型的符函数、对象、前缀、宏定义等各种类型的符号的命名规范。匈牙利命名法的主要思想是:号的命名规范。匈牙利命名法的主要思想是:在变量和函数名中加入前缀
20、以增进人们对程在变量和函数名中加入前缀以增进人们对程序的理解。序的理解。n为纪念为纪念Microsoft程序员程序员CharlesSimonyi所使用的命名约定所使用的命名约定38计算机科学与技术学院张淼窗口的创建窗口的创建创建一个完整的窗口需要经过下面四个操作步骤:创建一个完整的窗口需要经过下面四个操作步骤:o设计一个窗口类;设计一个窗口类;o注册窗口类;注册窗口类;o创建窗口;创建窗口;o显示及更新窗口。显示及更新窗口。39计算机科学与技术学院张淼创建窗口创建窗口第一步第一步o窗口类的定义窗口类的定义WNDCLASStypedefstructtagWNDCLASSUINTstyle;/窗口
21、类风格窗口类风格WNDPROClpfnWndProc;/窗口过程函数窗口过程函数intcbClsExtra;/在类结构中预留的空间在类结构中预留的空间intcbWndExtra;/在在Windows内部预留空间内部预留空间HINSTANCEhInstance;/程序实例句柄程序实例句柄HICONhIcon;/窗口的图标窗口的图标HCURSORhCursor;/光标句柄光标句柄HBRUSHhbrBackground;/背景色背景色LPCTSTRlpszMenuName;/窗口类菜单窗口类菜单LPCTSTRlpszClassName;/窗口类名窗口类名WNDCLASS,*PWNDCLASS;40计
22、算机科学与技术学院张淼窗口类的类型窗口类的类型在我们的程序中经常要用到一类变量,这个变量里的每一位(bit)都对应某一种特性。当该变量的某位为1时,表示有该位对应的那种特性,当该位为0时,即没有该位所对应的特性。当变量中的某几位同时为1时,就表示同时具有几种特性的组合。一个变量中的哪一位代表哪种意义,不容易记忆,所以我们经常根据特征的英文拼写的大写去定义一些宏,该宏所对应的数值中仅有与该特征相对应的那一位(bit)为1,其余的bit都为0。41计算机科学与技术学院张淼如果我们希望某一变量的数值既有CS_VREDRAW特性,又有CS_HREDRAW特性,我们只需使用二进制OR(|)操作符将他们进
23、行或运算相组合,如style=CS_VREDRAW|CS_HREDRAW|CS_NOCLOSE。如果我们希望在某一变量原有的几个特征上去掉其中一个特征,用取反()之后再进行与(&)运算,就能够实现,如在刚才的style的基础上去掉CS_NOCLOSE特征,可以用style&CS_NOCLOSE实现。42计算机科学与技术学院张淼窗口过程函数窗口过程函数o窗口过程函数用来对消息进行处理窗口过程函数用来对消息进行处理第二个成员变量lpfnWndProc指定了这一类型窗口的过程函数,也称回调函数回调函数。43计算机科学与技术学院张淼回调函数回调函数 当应用程序收到给某一窗口的消息时(还记得前面讲过的消
24、息通常与窗口相关的吗?),就应该调用某一函数来处理这条消息。这一调用过程不用应用程序自己来实施,而由操而由操作系统来完成作系统来完成,但是,回调函数本身的代码必须由应用程序自己完成。44计算机科学与技术学院张淼 对于一条消息,操作系统到底调用应用程序中的哪个函数(回调函数)来处理呢?操作系统调用的就是接受消息的窗操作系统调用的就是接受消息的窗口所属的类型中的口所属的类型中的lpfnWndProclpfnWndProc成员指成员指定的函数定的函数。每一种不同类型的窗口都有自己专用的回调函数,该函数就是通过lpfnWndProc成员指定的。 45计算机科学与技术学院张淼LoadIconLoadIc
25、on的作用是在应用程序中加载一个窗口图标,的作用是在应用程序中加载一个窗口图标,其原型为:其原型为:HICON HICON LoadIconLoadIcon( (HINSTANCE HINSTANCE hInstancehInstance, ,LPCTSTR LPCTSTR lpIconNamelpIconName););图标资源名或系统图标资源名或系统预定义图标标识名预定义图标标识名图标资源所在的模块句柄,图标资源所在的模块句柄,NULLNULL则使用系统预定义图标则使用系统预定义图标46计算机科学与技术学院张淼LoadCursorLoadCursor的作用是在应用程序中加载一个窗口光标,的
26、作用是在应用程序中加载一个窗口光标,其原型为:其原型为:HCURSOR HCURSOR LoadCursorLoadCursor( (HINSTANCE HINSTANCE hInstancehInstance, ,LPCTSTR LPCTSTR lpCursorNamelpCursorName););光标资源所在的模光标资源所在的模块句柄,块句柄,NULLNULL则使则使用系统预定义光标用系统预定义光标光标资源名或系统光标资源名或系统预定义光标标识名预定义光标标识名47计算机科学与技术学院张淼GetStockObjectGetStockObject的作用是获取笔、画刷、的作用是获取笔、画刷、
27、调色板、字体的句柄。应用程序调用函数调色板、字体的句柄。应用程序调用函数GetStockObject获取系统提供的背景刷。获取系统提供的背景刷。其原型为:其原型为:HGDIOBJGetStockObject(int fnObject/typeofstockobject);48计算机科学与技术学院张淼创建窗口创建窗口第二步第二步o注册窗口类注册窗口类RegisterClassATOMRegisterClass(CONSTWNDCLASS*lpWndClass);49计算机科学与技术学院张淼创建窗口创建窗口第三步第三步o创建窗口实例创建窗口实例CreateWindowHWNDCreateWindo
28、w(LPCTSTRlpszClassName,/窗口类名窗口类名LPCTSTRlpszTitle,/窗口标题名窗口标题名DWORDdwStyle,/创建窗口的样式创建窗口的样式intx,y,/窗口左上角坐标窗口左上角坐标intnWidth,nHeight, /窗口宽度和度高窗口宽度和度高HWNDhwndParent, /该窗口的父窗口句柄该窗口的父窗口句柄HWENUhMenu,/窗口主菜单句柄窗口主菜单句柄HINSTANCEhInstance,/创建窗口的应用程序当前句柄创建窗口的应用程序当前句柄LPVOIDlpParam/指向一个传递给窗口的参数值的指针指向一个传递给窗口的参数值的指针)50
29、计算机科学与技术学院张淼窗口样式窗口样式51计算机科学与技术学院张淼创建窗口创建窗口第四步第四步o显示窗口ShowWindowBOOLShowWindow(HWNDhWnd,intnCmdShow);52计算机科学与技术学院张淼创建窗口创建窗口第五步第五步o刷新窗口UpdateWindowBOOLUpdateWindow(HWND hWnd );显示窗口后,应用程序调用显示窗口后,应用程序调用UpdateWindow更新并绘制用户区,更新并绘制用户区,并发出并发出WM_PAINT消息。消息。 UpdateWindow(hwndUpdateWindow(hwnd););53计算机科学与技术学院张
30、淼GetMessage从消息队列中读取从消息队列中读取一条消息,并将消一条消息,并将消息放在息放在MSG结构中结构中其中函数其中函数GetMessage形式为:形式为:GetMessageGetMessage( lpMSGlpMSG, , / /指向指向MSGMSG结构的指针结构的指针 hwndhwnd, , nMsgFilteMinnMsgFilteMin, /, /用于消息过滤的最小消息号值用于消息过滤的最小消息号值 nMsgFilterMaxnMsgFilterMax / /用于消息过滤的最大消息号值用于消息过滤的最大消息号值 )返回零值,即检索返回零值,即检索到到WM_QUITWM_Q
31、UIT消息,程消息,程序结束循环并退出序结束循环并退出54计算机科学与技术学院张淼o从消息队列中获取消息nGetMessageo翻译消息和派遣消息nTranslateMessagenDispatchMessage将消息传递给将消息传递给窗口过程进行窗口过程进行处理处理消消息息队队列列Windows产生的消息产生的消息55计算机科学与技术学院张淼56计算机科学与技术学院张淼case1case2case3Default应用程序应用程序WinMain()消息循环WndProc()DispatchMessage()DefWindowProc()检索到的消息GetMessage()排队消息排队消息WM_
32、KEYDOWNWM_KEYUPWM_MOUSEMOVEWM_LBUTTONDOWNWM_QUIT.非排队消息非排队消息WM_CREATEWM_DESTROYWM_SIZEWM_PAINT.应用程序的消息队列回调Windows系统系统57计算机科学与技术学院张淼窗口过程窗口过程o窗口过程函数用来对消息进行处理LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam);58计算机科学与技术学院张淼窗口函数的一般形式如下:窗口函数的一般形式如下:LRESULT CALLBACK LRESULT CALLBACK Wnd
33、ProcWndProc( ( HWND HWND hwndhwnd, ,UINT UINT messgaemessgae, , WPARAM WPARAM wParam,LPARAMwParam,LPARAM lParamlParam ) ) switch(message)switch(message) message message为标识的消息为标识的消息 case case break; break; case case WM_DESTROYWM_DESTROY: : PostQuitMessage(0);PostQuitMessage(0); default:default: retur
34、n return DefWindowProc(hwnd,message,wParam,lParamDefWindowProc(hwnd,message,wParam,lParam);); return(0);return(0); 在消息处理程序段中一般都有对在消息处理程序段中一般都有对WM_DESTROYWM_DESTROY的处理的处理,该消息是关闭窗口时发出的。它向应用该消息是关闭窗口时发出的。它向应用程序发出程序发出WM_QUITWM_QUIT消息,请求退出消息,请求退出处理函数处理函数:void void PostQuitMessage(intPostQuitMessage(int nE
35、xitCodenExitCode) ) / /nExitCodenExitCode为应用程序的退出代码为应用程序的退出代码为未定义处理过程的消息提供缺省处理为未定义处理过程的消息提供缺省处理59计算机科学与技术学院张淼程序执行流程程序执行流程否否否否进行程序初始化进行程序初始化创建窗口注册窗口函数创建窗口注册窗口函数用用GetMessage取消息取消息是是处理消息处理消息退出消息退出消息程序从程序从WinMain开始开始退出程序退出程序拦截消息拦截消息是是默认处理默认处理60计算机科学与技术学院张淼格式化字符串函数格式化字符串函数o一个常用的格式化字符串的函数个常用的格式化字符串的函数npri
36、ntfnstdio.hcharszChar20;sprintf(szChar,charis%d,wParam);61计算机科学与技术学院张淼MessageBox函数函数o用于显示信息用于显示信息int/返回用户所选按钮代表的数值返回用户所选按钮代表的数值MessageBox(HWNDhWnd,/窗口句柄窗口句柄LPCTSTRlpText,/消息框主体显示的文本消息框主体显示的文本LPCTSTRlpCaption,/消息框标题栏显示文本消息框标题栏显示文本UINTuType/代表消息框风格的常数组合代表消息框风格的常数组合);62计算机科学与技术学院张淼消息框风格o以MB_开始的常数组合代表消息
37、框的风格n多种风格之间用“|”分隔#includeintWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,PSTRszCmdLine,intiCmdShow)if(IDOK=MessageBox(NULL,是否退出本程序?是否退出本程序?,退出退出,MB_OKCANCEL|MB_ICONQUESTION)MessageBox(NULL,再见!再见!,退出退出,MB_OK);return0;63计算机科学与技术学院张淼设备描述表(设备描述表(Devicecontext)o设备描述表(设备上下文):系统内部维护设备描述表(设备上下文):
38、系统内部维护的一个数据结构,该结构包含应用程序向输的一个数据结构,该结构包含应用程序向输出设备输出时所需要的信息。是应用程序和出设备输出时所需要的信息。是应用程序和输出设备之间的桥梁。输出设备之间的桥梁。应用应用程序程序外设外设Windows系统系统不允许不允许提供提供统一的设备环境统一的设备环境DC使应用程序和设备相连使应用程序和设备相连64计算机科学与技术学院张淼应用程序每一次文字图形操作均参照设备描述表应用程序每一次文字图形操作均参照设备描述表中的属性进行。设备描述表描述了特定输出设备中的属性进行。设备描述表描述了特定输出设备状态、文本和图形的绘图参数等;包括设备上可状态、文本和图形的绘
39、图参数等;包括设备上可使用的输出区域、逻辑坐标系、选定何种绘图工使用的输出区域、逻辑坐标系、选定何种绘图工具绘图、绘图前景色、填充色、字体、字体颜色、具绘图、绘图前景色、填充色、字体、字体颜色、字的磅数等属性。字的磅数等属性。65计算机科学与技术学院张淼GDI简介简介oGDI图形设备接口图形设备接口n要在窗口的客户区绘图,可以使用要在窗口的客户区绘图,可以使用Windows的图形设备接口(的图形设备接口(GDI)函数)函数nGDI的重要部分:设备描述表(的重要部分:设备描述表(DC)oGDI内部保存的数据结构内部保存的数据结构o设备无关性设备无关性n每个每个GDI函数都需要将设备描述表句柄作为
40、函函数都需要将设备描述表句柄作为函数的第一个参数,例如数的第一个参数,例如oDrawText(HDC,LPCTSTR,int,LPRECT,UINT);oTextOut(HDC,int,int,LPCTSTR,int);66计算机科学与技术学院张淼获取设备描述表:方法一获取设备描述表:方法一o该方法适合于处理非该方法适合于处理非WM_PAINT消息消息n用用GetDC获取设备描述表句柄获取设备描述表句柄n用用ReleaseDC释放设备描述表句柄释放设备描述表句柄o这种获取设备描述表的一般方式如下这种获取设备描述表的一般方式如下hdc=GetDC(hwnd);ReleaseDC(hwnd,hdc
41、);67计算机科学与技术学院张淼WM_PAINT消息消息o什么时候向窗口过程发送什么时候向窗口过程发送WM_PAINT消消息(窗口发生重绘)息(窗口发生重绘)“无效无效”的时候的时候n调用调用UpdateWindow函数刷新窗口函数刷新窗口n窗口的全部或者部分失效的时候窗口的全部或者部分失效的时候n窗口从无到有窗口从无到有n手动刷新窗口手动刷新窗口o调用调用InvalidateRect函数函数68计算机科学与技术学院张淼qWindows系统为每一个窗口建立了一个系统为每一个窗口建立了一个PAINTSTRUCT结构。该结构中包含了包结构。该结构中包含了包围无效区域的一个最小矩形的结构围无效区域的
42、一个最小矩形的结构RECT,应用程序可以根据这个无效区域执行更新的应用程序可以根据这个无效区域执行更新的操作。操作。PAINTSTRUCT结构体不需要我结构体不需要我们维护,是系统内部维护的结构体。们维护,是系统内部维护的结构体。69计算机科学与技术学院张淼获取设备描述表:方法二o该方法只适合于处理该方法只适合于处理WM_PAINT消息消息n用用BeginPaint“使无效窗口生效使无效窗口生效”并并“返回设返回设备描述表句柄备描述表句柄”n用用EndPaint释放设备描述表句柄释放设备描述表句柄o一般处理一般处理WM_PAINT的形式如下:的形式如下:CaseWM_PAINT;hdc=Beg
43、inPaint(hwnd,&ps);EndPaint(hwnd,&ps);return0;70计算机科学与技术学院张淼与输出文本相关的几个函数与输出文本相关的几个函数o设置文本颜色设置文本颜色nSetTextColor(HDC,COLORREF);o设置文本背景色设置文本背景色nSetBkColor(HDC,COLORREF);o设置文本显示模式设置文本显示模式nSetBkMode(HDC,intiBkMode);oiBkModenOPAQUE/不透明不透明nTRANSPARENT/透明透明71计算机科学与技术学院张淼画线画线o画线画线nLineTooLineTo(HDC,int,int);n
44、例:例:LineTo(hdc,100,100);n默认情况下从默认情况下从(0,0)开始画开始画o移动画笔移动画笔nMoveToExoMoveToEx(HDC,int,int,LPPOINT);72计算机科学与技术学院张淼画其它图形画其它图形o画椭圆画椭圆nEllipse(hdc,100,100,200,200);o画圆角矩形画圆角矩形nRoundRect(hdc,);o画弧画弧nArc(hdc,);o画饼画饼nPie(hdc,);o画矩形画矩形nRectangle(HDC,int,int,int,int);73计算机科学与技术学院张淼画笔画笔HPENo创建画笔创建画笔o将画笔选入将画笔选入D
45、Co删除画笔资源删除画笔资源HPENhPen;hPen=CreatePen(PS_SOLID,2,RGB(255,0,0);/线形,线宽,颜色线形,线宽,颜色SelectObject(hdc,hPen);DeleteObject(hPen);74计算机科学与技术学院张淼画刷画刷HBRUSHo创建画刷创建画刷o将画刷选入将画刷选入DCo删除画刷资源删除画刷资源HBRUSHhBrush;hBrush=CreateSolidBrush(RGB(255,0,0);SelectObject(hdc,hBrush);DeleteObject(hBrush);75计算机科学与技术学院张淼画刷画刷o取得系统自
46、带画刷取得系统自带画刷HBRUSHhBrush;hBrush=(HBRUSH)GetStockObject(BLACK_BRUSH);/WHITE_BRUSH/GRAY_BRUSH/DKGRAY_BRUSH/76计算机科学与技术学院张淼获取设备描述表:方法三获取设备描述表:方法三o获取整个窗口的设备描述表n用GetWindowDC获取整个窗口的设备描述表句柄n用ReleaseDC释放设备描述表句柄HDChdc;Hdc=GetWindowDC(hWnd);/使用设备描述表使用设备描述表ReleaseDC(hWnd,hdc);参见工程030277计算机科学与技术学院张淼获取设备描述表:方法四获取设
47、备描述表:方法四o获取整个屏幕的设备描述表n用CreateDC获取整个屏幕的设备描述表句柄n用DeleteDC释放设备描述表句柄HDChdc;Hdc=CreateDC(DISPLAY,NULL,NULL,NULL);/使用设备描述表使用设备描述表DeleteDC(hdc);参见工程030278计算机科学与技术学院张淼常用消息常用消息oWM_CREATEn由由CreateWindow函数发出的消息函数发出的消息oWM_PAINTn窗口客户区的全部或者部分窗口客户区的全部或者部分“无效无效”时触发时触发oWM_CLOSEn关闭窗口时产生的消息关闭窗口时产生的消息oWM_DESTROYn由由Dest
48、royWiodow函数发出的消息函数发出的消息oWM_QUITn由由PostQuitMessage函数发出的消息函数发出的消息79计算机科学与技术学院张淼进队消息与不进队消息进队消息与不进队消息o进队消息进队消息n进队消息是由进队消息是由Windows放入程序的消息队列放入程序的消息队列中的中的o不进队消息不进队消息n不进队消息直接发送给窗口过程不进队消息直接发送给窗口过程o窗口过程窗口过程n窗口过程是窗口的窗口过程是窗口的“消息中心消息中心”80计算机科学与技术学院张淼函数调用约定函数调用约定o函数调用是通过栈来实现的。在调用时,将函数调用是通过栈来实现的。在调用时,将参数值和调用后的返回地
49、址压入所分配的栈参数值和调用后的返回地址压入所分配的栈空间中。函数计算结束以后,或者调用者、空间中。函数计算结束以后,或者调用者、或者函数本身修改堆栈,使堆栈恢复原装。或者函数本身修改堆栈,使堆栈恢复原装。在参数传递中,有两个很重要的问题必须得在参数传递中,有两个很重要的问题必须得到明确说明:到明确说明:n当参数个数多于一个时,按照什么顺序把参数当参数个数多于一个时,按照什么顺序把参数压入堆栈压入堆栈n函数调用后,由谁来把堆栈恢复原装(堆栈清函数调用后,由谁来把堆栈恢复原装(堆栈清除)除)81计算机科学与技术学院张淼函数调用约定函数调用约定o在高级语言中,通过函数调用约定来说明这在高级语言中,
50、通过函数调用约定来说明这两个问题。常见的调用约定有:两个问题。常见的调用约定有:nstdcallncdeclnfastcallnthiscallnnakedcall82计算机科学与技术学院张淼头文件头文件owindows.h(所有(所有windows程序都必须程序都必须载入载入windows.h)n是主要的包含文件,是给是主要的包含文件,是给Windows程序开发程序开发人员的总的接口头文件人员的总的接口头文件n其中包含如下头文件其中包含如下头文件owindef.h基本类型定义基本类型定义owinnt.h支持支持Unicode的类型定义的类型定义owinbase.h内核函数内核函数owinus
51、er.h用户接口函数用户接口函数owingdi.h图形设备接口函数图形设备接口函数o83计算机科学与技术学院张淼Windows程序分为程序分为“程序代码程序代码”和和“用户接口(用户接口(UI)资源)资源”两大部分。两大部分。程序代码使用编译器编译,用户接口资程序代码使用编译器编译,用户接口资源使用资源编译器编译,最后两者使用源使用资源编译器编译,最后两者使用连接器加上库文件可以生成可执行文件。连接器加上库文件可以生成可执行文件。84计算机科学与技术学院张淼动态链接库动态链接库o自从微软推出第一个版本的Windows操作系统以来,动态链接库(DLL)一直是Windows操作系统的基础。85计算
52、机科学与技术学院张淼o动态链接库通常都不能直接运行,也不能接收消息。它们是一些独立的文件,其中包含能被可执行程序或其它DLL调用来完成某项工作的函数。只有在其它模块调用动态链接库中的函数时,它才发挥作用。oWindowsAPI中的所有函数都包含在DLL中。其中有3个最重要的DLL,Kernel32.dll,它包含用于管理内存、进程和线程的各个函数;User32.dll,它包含用于执行用户界面任务(如窗口的创建和消息的传送)的各个函数;GDI32.dll,它包含用于画图和显示文本的各个函数。86计算机科学与技术学院张淼静态库和动态库静态库和动态库o静态库:函数和数据被编译进一个二进制文件静态库:
53、函数和数据被编译进一个二进制文件(通通常扩展名为常扩展名为.LIB)。在使用静态库的情况下,在编。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件建最终的可执行文件(.EXE文件文件)。o在使用动态库的时候,往往提供两个文件:一个引在使用动态库的时候,往往提供两个文件:一个引入库和一个入库和一个DLL。引入库包含被。引入库包含被DLL导出的函数和导出的函数和变量的符号名,变量的符号名,DLL包含实际的函数和数据。在编包含实际
54、的函数和数据。在编译链接可执行文件时,只需要链接引入库,译链接可执行文件时,只需要链接引入库,DLL中中的函数代码和数据并不复制到可执行文件中,在运的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载行的时候,再去加载DLL,访问,访问DLL中导出的函数。中导出的函数。87计算机科学与技术学院张淼用户接口(用户接口(UI)资源是指功能菜单、对话框、程)资源是指功能菜单、对话框、程序图标、光标等资源,它是序图标、光标等资源,它是Windows应用程序界面应用程序界面的重要组成部分。资源的使用极大方便了应用程序界的重要组成部分。资源的使用极大方便了应用程序界面的设计,也大大方便了应用程序
55、与用户的交互。面的设计,也大大方便了应用程序与用户的交互。这些用户资源的实际内容(二进制代码)是借助这些用户资源的实际内容(二进制代码)是借助各种工具产生的。并以各种扩展名的文件存在,如各种工具产生的。并以各种扩展名的文件存在,如.ico,.bmp,.cur等。程序员必须在一个所谓的资源描等。程序员必须在一个所谓的资源描述文档(述文档(.rc)中描述它们。)中描述它们。RC编译器读取编译器读取RC文件的文件的描述后,将所有用户接口资源文件集中制作一个描述后,将所有用户接口资源文件集中制作一个.RES文件。文件。这些资源可以使用这些资源可以使用VC+6.0提供的资源编辑器提供的资源编辑器来实现创
56、建和编辑。来实现创建和编辑。88计算机科学与技术学院张淼资源资源o资源分类资源分类n菜单菜单oWM_COMMAND消息消息nwParam低低16位传递菜单项资源位传递菜单项资源IDn对话框对话框oWM_COMMAND消息消息nwParam低低16位传递子窗口(控件)资源位传递子窗口(控件)资源IDno资源资源IDn资源的唯一标识资源的唯一标识89计算机科学与技术学院张淼oWindows应用程序加载菜单的方法:应用程序加载菜单的方法:在窗口类的定义中加载菜单资源在窗口类的定义中加载菜单资源wndcls.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);o在创建窗口时
57、加载菜单在创建窗口时加载菜单HMENUhMenu;hMenu=LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENU1)o动态加载菜单:应用程序通过调用函数动态加载菜单:应用程序通过调用函数LoadMenu获取菜单句柄后,还可通过获取菜单句柄后,还可通过SetMenu动态加载菜单。动态加载菜单。90计算机科学与技术学院张淼CH1.3windows应用程序特性应用程序特性o消息驱动机制o图形设备接口(GDI)o基于资源的程序设计o动态链接库91计算机科学与技术学院张淼总结:总结:oAPIo消息机制(消息机制(MSG)o句柄句柄oGDIo设备上下文(设备上下文(DC
58、)o动态链接库动态链接库o资源与资源资源与资源ID92计算机科学与技术学院张淼作业:作业:1、理解Windows程序设计的基本概念2、书后习题P118(7)93计算机科学与技术学院张淼第二部分第二部分面向对象程序设计和面向对象程序设计和C+语言基础语言基础94计算机科学与技术学院张淼C+语言的产生语言的产生oC+是从是从C语言发展演变而来的,首先是一语言发展演变而来的,首先是一个更好的个更好的C。o引入了类的机制,最初的引入了类的机制,最初的C+被称为被称为带类带类的的C。o1983年正式取名为年正式取名为C+。C+语言的标语言的标准化工作从准化工作从1989年开始,于年开始,于1994年制定
59、年制定了了ANSIC+标准草案。以后又经过不断标准草案。以后又经过不断完善,成为目前的完善,成为目前的C+。95计算机科学与技术学院张淼C+语言与语言与C语言的关系语言的关系C+C+语言语言语言语言C C语言语言语言语言保持与保持与保持与保持与C C语言的相兼性语言的相兼性语言的相兼性语言的相兼性 是是是是C C语言的一个超集语言的一个超集语言的一个超集语言的一个超集 使得使得使得使得C+C+不是一个纯面向不是一个纯面向不是一个纯面向不是一个纯面向 对象的程序设计语言对象的程序设计语言对象的程序设计语言对象的程序设计语言C+C+语言对语言对语言对语言对C C语言作了很语言作了很语言作了很语言作
60、了很多改进多改进多改进多改进支持面向过程支持面向过程支持面向过程支持面向过程的程序设计语的程序设计语的程序设计语的程序设计语言言言言C+C+语言与语言与语言与语言与C C语言的本质区别语言的本质区别语言的本质区别语言的本质区别C+C+语言支持面向对象的程序设计语言支持面向对象的程序设计语言支持面向对象的程序设计语言支持面向对象的程序设计C C语言仅支持面向过程的程序设计语言仅支持面向过程的程序设计语言仅支持面向过程的程序设计语言仅支持面向过程的程序设计学好学好学好学好C+C+语言的语言的语言的语言的关键关键关键关键掌握好面向对象的程序设计思想掌握好面向对象的程序设计思想掌握好面向对象的程序设计
61、思想掌握好面向对象的程序设计思想96计算机科学与技术学院张淼o打着面向对象的幌子干着面向过程的勾当!nC+编译器对C程序的兼容性造成了最底层的“过程勾当”。n实际上用C+编程的人,大部分不自己创建类,而是使用类库,这样就造成了他们把类库作为一种高级的库函数库来理解,并没有真正理解面向对象的思想。nC+给了我们第二条道路去走过程编程97计算机科学与技术学院张淼C+语言基础语言基础oC/C+语言概述语言概述(结构化程序设计部分)(结构化程序设计部分)oC+面向对象程序设计基础面向对象程序设计基础oC+面向对象程序设计进阶面向对象程序设计进阶98计算机科学与技术学院张淼控制台控制台(console)
62、应用程序应用程序oDOS-like程序。程序。o仍然可以调用部分的、不牵扯到图形使用者接口仍然可以调用部分的、不牵扯到图形使用者接口(GUI)的)的Win32API(尤其是(尤其是KERNEL.DLL模块所提供的那一部分),所以它可以使用模块所提供的那一部分),所以它可以使用Windows提供的各种高级功能,它可以产生进程,提供的各种高级功能,它可以产生进程,产生线程。甚至还可以在其中使用部分的产生线程。甚至还可以在其中使用部分的MFC类类(同样是与(同样是与GUI没有关联的),例如处理数组、链没有关联的),例如处理数组、链表等数据结构的表等数据结构的collectionclasses(CAr
63、ray,CList)、与文件有关的)、与文件有关的CFile、CStdioFile。oConsole窗口将成为其标准输入和输出装置。窗口将成为其标准输入和输出装置。o以以main函数为入口点。函数为入口点。99计算机科学与技术学院张淼第一个第一个C+程序程序HelloWorldo该程序在控制台输出一个字符串该程序在控制台输出一个字符串#includevoidmain()coutHelloWorldendl;100计算机科学与技术学院张淼第二个第二个C+程序程序还是还是HelloWorldo该程序在控制台输出一个字符串该程序在控制台输出一个字符串#includeusingnamespacestd
64、;voidmain()coutHelloWorldendl;101计算机科学与技术学院张淼分析我们的分析我们的HelloWorldo#includen预处理命令预处理命令“#”ousingnamespacestd;n引用引用std名字空间名字空间102计算机科学与技术学院张淼C+C+标准库包含了标准库包含了标准库包含了标准库包含了C C语言和针对语言和针对语言和针对语言和针对C+C+提供的新功能。提供的新功能。提供的新功能。提供的新功能。C C标准库提供的头文件,在标准库提供的头文件,在标准库提供的头文件,在标准库提供的头文件,在C+C+标准库中也提供了相标准库中也提供了相标准库中也提供了相标
65、准库中也提供了相应的头文件,文件名的约定是:把应的头文件,文件名的约定是:把应的头文件,文件名的约定是:把应的头文件,文件名的约定是:把C C标准库头文件名的标准库头文件名的标准库头文件名的标准库头文件名的.h.h去掉,然后在文件名前加一个字母去掉,然后在文件名前加一个字母去掉,然后在文件名前加一个字母去掉,然后在文件名前加一个字母c c。现在很多的现在很多的现在很多的现在很多的C+C+实现为了保证与实现为了保证与实现为了保证与实现为了保证与C C语言的兼容性,往语言的兼容性,往语言的兼容性,往语言的兼容性,往往同时提供了两套头文件。往同时提供了两套头文件。往同时提供了两套头文件。往同时提供了
66、两套头文件。值得注意的是:值得注意的是:值得注意的是:值得注意的是:C+C+标准库的标准库的标准库的标准库的程序实体是在名空间程序实体是在名空间程序实体是在名空间程序实体是在名空间stdstd中定义的,在中定义的,在中定义的,在中定义的,在C+C+程序,如果包程序,如果包程序,如果包程序,如果包含的是相应的含的是相应的含的是相应的含的是相应的C+C+的头文件,则应通过名空间的头文件,则应通过名空间的头文件,则应通过名空间的头文件,则应通过名空间stdstd来使用来使用来使用来使用这些功能。但注意:在这些功能。但注意:在这些功能。但注意:在这些功能。但注意:在VC+6.0VC+6.0的的的的C+
67、C+标准中,从标准中,从标准中,从标准中,从C C标标标标准包含进来的功能并没有在名空间准包含进来的功能并没有在名空间准包含进来的功能并没有在名空间准包含进来的功能并没有在名空间stdstd中定义。中定义。中定义。中定义。103计算机科学与技术学院张淼ovoidmain()n程序入口点程序入口点ocoutHelloWorldendl;ncout:标准输出流对象,作用相当于:标准输出流对象,作用相当于printfn:插入符,将后面的内容插入到:插入符,将后面的内容插入到cout中,中,即输出到屏幕上。即输出到屏幕上。nendl:endofline104计算机科学与技术学院张淼输出输出ocout流
68、输出流输出n格式格式ocout输出数据输出数据;o可以连续输出可以连续输出ncoutabc:提取符,将用户输入的内容保存到后面的:提取符,将用户输入的内容保存到后面的变量中。变量中。n格式格式ocin输入数据输入数据;o可以连续输入(空白符:空格、横向制表符或回车可以连续输入(空白符:空格、横向制表符或回车符作为输入数据之间的分隔符)符作为输入数据之间的分隔符)ncinijk;n功能功能o输入字符、整数、浮点数和字符串输入字符、整数、浮点数和字符串o类似类似scanf函数函数106计算机科学与技术学院张淼CH2.1C+语言概述语言概述o基本基本C+语法格式语法格式o数据类型数据类型o运算符和表
69、达式运算符和表达式o基本语句基本语句o函数函数o指针和引用指针和引用107计算机科学与技术学院张淼CH2.1.1C+基本语法oC+是严格区分大小写的是严格区分大小写的oC+是一种自由格式的语言是一种自由格式的语言用用用用C+C+语言编程时,程序的书写非常自由,语言编程时,程序的书写非常自由,语言编程时,程序的书写非常自由,语言编程时,程序的书写非常自由,甚至可以把甚至可以把整个函数体全部书写在一行上。但这样做,对人来说,整个函数体全部书写在一行上。但这样做,对人来说,如果程序稍长一点,就难理解了。如果程序稍长一点,就难理解了。书写基本原则如下:书写基本原则如下:一行一般写一条语句。长语句一行写
70、不下时可以一条写一行一般写一条语句。长语句一行写不下时可以一条写多行。分行原则是不能将一个单词分开。用双引号引用多行。分行原则是不能将一个单词分开。用双引号引用的字符串和宏定义一行写不下需要续行时需用续行符的字符串和宏定义一行写不下需要续行时需用续行符。在书写在书写C+程序时,一般采用比较美观的程序时,一般采用比较美观的“缩进缩进”格式格式来书写。来书写。108计算机科学与技术学院张淼oC+程序的注释程序的注释n作用:提高程序的可读性;调试程序作用:提高程序的可读性;调试程序分类分类分类分类C+C+型注释型注释型注释型注释双斜线双斜线双斜线双斜线“ “/”/”注释(从注释(从注释(从注释(从“
71、 “/”/”开始,本行中所有字符开始,本行中所有字符开始,本行中所有字符开始,本行中所有字符都被都被都被都被作为注释处理。)作为注释处理。)作为注释处理。)作为注释处理。)可以嵌在可以嵌在可以嵌在可以嵌在C C型注释中。型注释中。型注释中。型注释中。C C型注释型注释型注释型注释“/*”“/*”表示注释的开始,表示注释的开始,表示注释的开始,表示注释的开始,“*“*/”/”表示注释的结束。在表示注释的结束。在表示注释的结束。在表示注释的结束。在“ “/*”/*”、 “*“*/”/”之间的字符均被视作注释。之间的字符均被视作注释。之间的字符均被视作注释。之间的字符均被视作注释。主要用于大块注释。
72、主要用于大块注释。主要用于大块注释。主要用于大块注释。软件编码规范中说:软件编码规范中说:“可读性第一,效率第二可读性第一,效率第二”。在程序中必须包含适量的注释,以提高程。在程序中必须包含适量的注释,以提高程序的可读性和易维护性,程序注释一般占程序序的可读性和易维护性,程序注释一般占程序代码总量的代码总量的20%-50%。109计算机科学与技术学院张淼oC+中的标识符标识符是用来表示变量名、函数名、数组名、类名等标识符是用来表示变量名、函数名、数组名、类名等的有效字符序列。标识符命名要遵守合法性、有效性和易的有效字符序列。标识符命名要遵守合法性、有效性和易读性原则。读性原则。标识符的命名规则
73、标识符的命名规则标识符的命名规则标识符的命名规则由字母、数字和下划线组成由字母、数字和下划线组成由字母、数字和下划线组成由字母、数字和下划线组成以字母或下划线作为第一个字符,以字母或下划线作为第一个字符,以字母或下划线作为第一个字符,以字母或下划线作为第一个字符,其后跟零个或多个字母、数字、下划线。其后跟零个或多个字母、数字、下划线。其后跟零个或多个字母、数字、下划线。其后跟零个或多个字母、数字、下划线。大写字母与小写字母分别代表不同的标识符大写字母与小写字母分别代表不同的标识符大写字母与小写字母分别代表不同的标识符大写字母与小写字母分别代表不同的标识符不能与关键字相同不能与关键字相同不能与关
74、键字相同不能与关键字相同举例举例举例举例正确的正确的正确的正确的错误的错误的错误的错误的sumsumDram_Dram_rectanglrectangle_myfrie_myfriendend1_peo/1_peo/起始字符非法起始字符非法起始字符非法起始字符非法operator/operator/是关键字是关键字是关键字是关键字my$/my$/含有非法字符含有非法字符含有非法字符含有非法字符标识符的命名规则标识符的命名规则标识符的命名规则标识符的命名规则110计算机科学与技术学院张淼oC+的关键字(参见书的关键字(参见书P2)111计算机科学与技术学院张淼CH2.1.2C+数据类型oo数据是
75、程序处理的对象,在数据是程序处理的对象,在C+语言中,语言中,所有的对象都属于某种数据类型。所有的对象都属于某种数据类型。数据类型的分类数据类型的分类数据类型的分类数据类型的分类基本数据类型基本数据类型基本数据类型基本数据类型派生类型派生类型派生类型派生类型复合类型(数组、类、结构复合类型(数组、类、结构复合类型(数组、类、结构复合类型(数组、类、结构 体、共用体、枚体、共用体、枚体、共用体、枚体、共用体、枚举)举)举)举)指针指针指针指针引用引用引用引用112计算机科学与技术学院张淼基本数据类型基本数据类型基本数据类型基本数据类型整型(int)字符型(char)浮点型(实型)(float,d
76、ouble)逻辑型(布尔型)(逻辑型(布尔型)(bool)空值类型(void):用于函数和指针113计算机科学与技术学院张淼在程序中,有些数据在运行期间是不允许改变的,我们称之为在程序中,有些数据在运行期间是不允许改变的,我们称之为在程序中,有些数据在运行期间是不允许改变的,我们称之为在程序中,有些数据在运行期间是不允许改变的,我们称之为常量常量常量常量。常量的两种常量的两种常量的两种常量的两种表示形式表示形式表示形式表示形式字面常量字面常量字面常量字面常量符号常量符号常量符号常量符号常量程序中直接写出常量值的常量。程序中直接写出常量值的常量。程序中直接写出常量值的常量。程序中直接写出常量值的
77、常量。常量常量常量常量114计算机科学与技术学院张淼1.1.整型常量整型常量整型常量整型常量整型常量就是以文字形式出现的整数,包括三种形式。各种表示形式前均整型常量就是以文字形式出现的整数,包括三种形式。各种表示形式前均整型常量就是以文字形式出现的整数,包括三种形式。各种表示形式前均整型常量就是以文字形式出现的整数,包括三种形式。各种表示形式前均可加上正或负号以表示它们值的正负,正号可以省略。可加上正或负号以表示它们值的正负,正号可以省略。可加上正或负号以表示它们值的正负,正号可以省略。可加上正或负号以表示它们值的正负,正号可以省略。形式形式组成组成举例举例备注备注十进制十进制由若干个由若干个
78、0 09 9的数字组成,但的数字组成,但不能以不能以0 0开头开头19801980,-50-50L L(或(或l l)表)表示长整型,示长整型,U U(或(或u u)表)表示无符号型,示无符号型,如果后缀包如果后缀包括括L L(或(或l l)和和U U(或(或u u)则表示无符则表示无符号长整型。号长整型。八进制八进制以以0 0开头,由若干开头,由若干0 07 7的数字组的数字组成成010010,-0276-0276十六进制十六进制以以0X0X或或0x0x开头,由若干开头,由若干0 09 9的的数字及数字及A AF F(大小写均可)的(大小写均可)的字母组成字母组成0x1Fa0x1Fa-0X4
79、Ab-0X4Ab115计算机科学与技术学院张淼2.2.实型常量实型常量实型常量实型常量实型常量只能用十进制表示,共有两种表示形式实型常量只能用十进制表示,共有两种表示形式实型常量只能用十进制表示,共有两种表示形式实型常量只能用十进制表示,共有两种表示形式一般表示形式一般表示形式一般表示形式一般表示形式指数表示形式指数表示形式指数表示形式指数表示形式形式形式组成组成举例举例备注备注一般一般表示表示又称小数表示形式。使用这种表示形又称小数表示形式。使用这种表示形式时,实型常量由整数和小数两部分式时,实型常量由整数和小数两部分组成。其中的一部分在实际使用时可组成。其中的一部分在实际使用时可省略,但不
80、允许两部分同时省去。省略,但不允许两部分同时省去。10.210.2,10.10.,.2 .2默认数据类默认数据类型为型为doubledouble型,如果加型,如果加上后缀上后缀F F(或(或f f)则)则为为floatfloat型,型,加上加上L L(或(或l l)则为)则为longlongdoubledouble型。型。指数指数表示表示表示很大或很小的实数,由尾数部分、表示很大或很小的实数,由尾数部分、字母字母E E(或(或e e)、指数部分三部分组成。)、指数部分三部分组成。尾数部分的表示和一般表示形式相同,尾数部分的表示和一般表示形式相同,指数部分必须是整数,但可正可负,指数部分必须是整
81、数,但可正可负,当指数大于零时,正号可省。当指数大于零时,正号可省。1.2E201.2E20,.24e100.24e100,116计算机科学与技术学院张淼字符常量通常是指用单引号括起来的一个字符,其数据类型是字符常量通常是指用单引号括起来的一个字符,其数据类型是字符常量通常是指用单引号括起来的一个字符,其数据类型是字符常量通常是指用单引号括起来的一个字符,其数据类型是charchar。其。其。其。其中单引号只是用来说明被它括起来的字符是字符常量,它本身不是字符常量中单引号只是用来说明被它括起来的字符是字符常量,它本身不是字符常量中单引号只是用来说明被它括起来的字符是字符常量,它本身不是字符常量
82、中单引号只是用来说明被它括起来的字符是字符常量,它本身不是字符常量的内容。如:的内容。如:的内容。如:的内容。如:aa,#,GG。C+C+语言中,还有一种转义序列的表示方法可用来表示字符常量。语言中,还有一种转义序列的表示方法可用来表示字符常量。语言中,还有一种转义序列的表示方法可用来表示字符常量。语言中,还有一种转义序列的表示方法可用来表示字符常量。是用转义符号是用转义符号是用转义符号是用转义符号“ “” ”后跟一后跟一后跟一后跟一个字符或一个个字符或一个个字符或一个个字符或一个ASCIIASCII码来表码来表码来表码来表示一个单一字符。若示一个单一字符。若示一个单一字符。若示一个单一字符。
83、若“ “” ”后跟一个后跟一个后跟一个后跟一个ASCIIASCII码,则表示码,则表示码,则表示码,则表示的是该的是该的是该的是该ASCIIASCII码所代表的字码所代表的字码所代表的字码所代表的字符。符。符。符。在这里在这里在这里在这里ASCIIASCII码用八码用八码用八码用八进制或十六进制表示,这进制或十六进制表示,这进制或十六进制表示,这进制或十六进制表示,这里八进制和十六进制的表里八进制和十六进制的表里八进制和十六进制的表里八进制和十六进制的表示与前面表示整型常量的示与前面表示整型常量的示与前面表示整型常量的示与前面表示整型常量的方式不同,应无第一个方式不同,应无第一个方式不同,应无
84、第一个方式不同,应无第一个“ “0”0”。例如。例如。例如。例如 X62X62就就就就表示字符表示字符表示字符表示字符bb。3.3.字符常量字符常量字符常量字符常量117计算机科学与技术学院张淼3.3.字符常量字符常量字符常量字符常量在书写字符常量时,可显示字符通常用字符本身来书写,在书写字符常量时,可显示字符通常用字符本身来书写,而不可显示字符(控制字符)和有专门用途的字符用转而不可显示字符(控制字符)和有专门用途的字符用转义序列表示。另外,对于下面的字符要特别注意:义序列表示。另外,对于下面的字符要特别注意:反斜杠(反斜杠()应写成)应写成单引号(单引号()应写成)应写成双引号(双引号(“
85、)应写成)应写成”或或”118计算机科学与技术学院张淼4.4.字符串常量字符串常量字符串常量字符串常量字符串常量又称字符串或串常量,是用一对双引号括起来的字符序列。字符串常量又称字符串或串常量,是用一对双引号括起来的字符序列。字符串常量又称字符串或串常量,是用一对双引号括起来的字符序列。字符串常量又称字符串或串常量,是用一对双引号括起来的字符序列。例如:例如:例如:例如:xyz,Iamastudentxyz,Iamastudent,ThisisastringThisisastring都是字符串。都是字符串。都是字符串。都是字符串。由于双引号在字符串中用做定界符,所以,若字符串中需要出现由于双引
86、号在字符串中用做定界符,所以,若字符串中需要出现由于双引号在字符串中用做定界符,所以,若字符串中需要出现由于双引号在字符串中用做定界符,所以,若字符串中需要出现双引号时,则必须采用转义序列。双引号时,则必须采用转义序列。双引号时,则必须采用转义序列。双引号时,则必须采用转义序列。注注注注 II0 0C+C+语言中字符串的存储与字符不同,它在内存中的存放并不是简单地按串语言中字符串的存储与字符不同,它在内存中的存放并不是简单地按串语言中字符串的存储与字符不同,它在内存中的存放并不是简单地按串语言中字符串的存储与字符不同,它在内存中的存放并不是简单地按串中字符的顺序排放,而是在末尾加上一个中字符的
87、顺序排放,而是在末尾加上一个中字符的顺序排放,而是在末尾加上一个中字符的顺序排放,而是在末尾加上一个 00,表示字符串的结束。,表示字符串的结束。,表示字符串的结束。,表示字符串的结束。字符串、字符及与其对应的存储形式字符串、字符及与其对应的存储形式字符串、字符及与其对应的存储形式字符串、字符及与其对应的存储形式IIIII I119计算机科学与技术学院张淼字符串和宏定义一行写不下需要续行时需用续行符字符串和宏定义一行写不下需要续行时需用续行符。“thisisastring!mnp”#defineCONTAINING_RECORD(address,type,field)(type*)(PCHAR
88、)(address)-(UINT_PTR)(&(type*)0)-field)120计算机科学与技术学院张淼符号常量是指有名字的变量。在程序中使用常量时,除了采用字面常量形式外,还可以首先通过常量定义给常量取一个名字,并指定一个类型,然后,在程序中通过常量名来使用这些常量。符号常量符号常量符号常量符号常量121计算机科学与技术学院张淼用用constconst声明符号常量声明符号常量用用#define#define声明符号常量声明符号常量解释解释C+C+语言中广泛采用的声明符号常语言中广泛采用的声明符号常量的方法量的方法C C语言中声明符号常量的方法。语言中声明符号常量的方法。其中其中#defi
89、ne#define是预处理指令。是预处理指令。缺点是不能显式声明常量的类缺点是不能显式声明常量的类型。型。形式形式constconst数据类型数据类型常量名常量名= =常量值;常量值;或:或:数据类型数据类型 constconst常量名常量名= =常量值;常量值;正确正确声明声明constconst doubledouble pi=3.1415926;pi=3.1415926;#definepi3.1415926#definepi3.1415926错误错误声明声明constdoublepi;/constdoublepi;/错误错误pi=3.1415926;/pi=3.1415926;/错误错误
90、最后不允许加最后不允许加最后不允许加最后不允许加“ “;” ”两种声明符号常量的方法两种声明符号常量的方法122计算机科学与技术学院张淼const定义的符号常量可以看作是一个定义的符号常量可以看作是一个只读变量,只读变量,不可在程序中修改它的值不可在程序中修改它的值。定义时必须初始化定义时必须初始化。注意注意注意注意bool类型的值true和false可以看成是C+语言预定义的两个符号常量,它们的值分别为1和0。123计算机科学与技术学院张淼有些数据在程序运行过程中是可以改变的,我们称之为有些数据在程序运行过程中是可以改变的,我们称之为有些数据在程序运行过程中是可以改变的,我们称之为有些数据在
91、程序运行过程中是可以改变的,我们称之为变量变量变量变量。一个变量对应着计算机中的一组内存单元,这组内存单元在一个变量对应着计算机中的一组内存单元,这组内存单元在一个变量对应着计算机中的一组内存单元,这组内存单元在一个变量对应着计算机中的一组内存单元,这组内存单元在C+C+语言中用一个标识符来标识,即语言中用一个标识符来标识,即语言中用一个标识符来标识,即语言中用一个标识符来标识,即变量名变量名变量名变量名。变量变量变量变量124计算机科学与技术学院张淼任何一个变量在被引用之前必须定义。与任何一个变量在被引用之前必须定义。与C语言不同的是语言不同的是C+可以在程序中随时定义变量,不必集中在执行语
92、句可以在程序中随时定义变量,不必集中在执行语句之前。之前。定义格式:定义格式: ;一、变量的定义一、变量的定义数据类型是指数据类型是指数据类型是指数据类型是指C+C+语言中的任一合法类型,每个变量都必须属于一种语言中的任一合法类型,每个变量都必须属于一种语言中的任一合法类型,每个变量都必须属于一种语言中的任一合法类型,每个变量都必须属于一种类型。变量名的命名应遵照类型。变量名的命名应遵照类型。变量名的命名应遵照类型。变量名的命名应遵照标识符的命名规则标识符的命名规则标识符的命名规则标识符的命名规则。在定义变量时,必须注意变量类型的选择。应该保证该变量在定义变量时,必须注意变量类型的选择。应该保
93、证该变量在定义变量时,必须注意变量类型的选择。应该保证该变量在定义变量时,必须注意变量类型的选择。应该保证该变量中将要存储的值不突破该变量类型所能表示的最大值。中将要存储的值不突破该变量类型所能表示的最大值。中将要存储的值不突破该变量类型所能表示的最大值。中将要存储的值不突破该变量类型所能表示的最大值。125计算机科学与技术学院张淼程序中常需要对一些变量预先设置初值,这一过程称为初程序中常需要对一些变量预先设置初值,这一过程称为初始化。在始化。在C/C+C/C+中,可以在定义变量时同时使变量初始化。中,可以在定义变量时同时使变量初始化。C+C+变量的初始化还有另外一种形式,它与变量的初始化还有
94、另外一种形式,它与C C语言不同。例语言不同。例如:如: intint nX(1), nY(3); nX(1), nY(3);表示表示nX和和nY是整型变量,它们的初值分别为是整型变量,它们的初值分别为1和和3。 二、变量的初始化二、变量的初始化126计算机科学与技术学院张淼o注意字符数组存储字符串o数组的越界数组数组127计算机科学与技术学院张淼结构体结构体o结构体是一种复合类型,结构体中可包含多结构体是一种复合类型,结构体中可包含多个类型不同的数据成员个类型不同的数据成员structstudentintnumber;charname10;intage;nC+的结构体中允许有成员函数128计
95、算机科学与技术学院张淼共用体共用体o共用体是将多个数据成员组织为一个整体,共用体是将多个数据成员组织为一个整体,它们在内存中占用同一段存储单元它们在内存中占用同一段存储单元unionabinta;doublcb;nC+的公用体中允许有成员函数129计算机科学与技术学院张淼枚举类型枚举类型o枚举类型是将变量的值一一列举出来,变量枚举类型是将变量的值一一列举出来,变量的值只限于列举出来的值的范围内的值只限于列举出来的值的范围内enumweekdaysun,mon,tue,wed,thu,fri,sat;作用:增强程序代码的可读性。作用:增强程序代码的可读性。130计算机科学与技术学院张淼用用typ
96、edef定义类型定义类型使用关键字使用关键字typedeftypedef可以将已有的类型名用新的类型名来代替。可以将已有的类型名用新的类型名来代替。格式:格式:typedef; 131计算机科学与技术学院张淼CH2.1.3运算符和表达式运算符和表达式132计算机科学与技术学院张淼运算是指对数据的求值计算,如:加、减运算等。运算符给出了计算的运算是指对数据的求值计算,如:加、减运算等。运算符给出了计算的运算是指对数据的求值计算,如:加、减运算等。运算符给出了计算的运算是指对数据的求值计算,如:加、减运算等。运算符给出了计算的类型,而参与运算的数据叫操作数(变量、常量)。类型,而参与运算的数据叫操
97、作数(变量、常量)。类型,而参与运算的数据叫操作数(变量、常量)。类型,而参与运算的数据叫操作数(变量、常量)。运运运运算算算算符符符符的的的的分分分分类类类类按所要求的操作数的多少按所要求的操作数的多少按所要求的操作数的多少按所要求的操作数的多少一元运算符一元运算符一元运算符一元运算符二元运算符二元运算符二元运算符二元运算符三元运算符三元运算符三元运算符三元运算符需要需要需要需要1 1个操作数个操作数个操作数个操作数需要需要需要需要2 2个操作数个操作数个操作数个操作数需要需要需要需要3 3个操作数个操作数个操作数个操作数运算符具有优先级与结合性。运算符具有优先级与结合性。运算符具有优先级与
98、结合性。运算符具有优先级与结合性。运算符运算符运算符运算符运算性质分运算性质分运算性质分运算性质分算术运算符算术运算符算术运算符算术运算符关系运算符关系运算符关系运算符关系运算符逻辑运算符逻辑运算符逻辑运算符逻辑运算符133计算机科学与技术学院张淼当一个表达式中含有多个运算符时,先进行优先级高的运算,当一个表达式中含有多个运算符时,先进行优先级高的运算,当一个表达式中含有多个运算符时,先进行优先级高的运算,当一个表达式中含有多个运算符时,先进行优先级高的运算,后作优先级低的运算。如果表达式中出现了多个相同优先级后作优先级低的运算。如果表达式中出现了多个相同优先级后作优先级低的运算。如果表达式中
99、出现了多个相同优先级后作优先级低的运算。如果表达式中出现了多个相同优先级的运算时,运算的顺序就要看运算符的结合性了。的运算时,运算的顺序就要看运算符的结合性了。的运算时,运算的顺序就要看运算符的结合性了。的运算时,运算的顺序就要看运算符的结合性了。结合性结合性结合性结合性是指当一个操作数左右两边的运算符优先级相同时,是指当一个操作数左右两边的运算符优先级相同时,是指当一个操作数左右两边的运算符优先级相同时,是指当一个操作数左右两边的运算符优先级相同时,按什么顺序进行运算,是自左向右,还是自右向左。按什么顺序进行运算,是自左向右,还是自右向左。按什么顺序进行运算,是自左向右,还是自右向左。按什么
100、顺序进行运算,是自左向右,还是自右向左。134计算机科学与技术学院张淼(1 1)基本算术运算符)基本算术运算符)基本算术运算符)基本算术运算符C+C+语言中的算术运算符包括语言中的算术运算符包括语言中的算术运算符包括语言中的算术运算符包括基本算术运算符基本算术运算符基本算术运算符基本算术运算符和和和和增增增增1 1、减、减、减、减1 1运算符运算符运算符运算符。一元运算符:一元运算符:一元运算符:一元运算符:二元运算符:二元运算符:二元运算符:二元运算符:+ +(取正)、(取正)、(取正)、(取正)、- -(取负)(取负)(取负)(取负)+ +(或加)、(或加)、(或加)、(或加)、- -(或
101、减)、(或减)、(或减)、(或减)、* *(乘)、(乘)、(乘)、(乘)、/ /(除)、(除)、(除)、(除)、%(取余)(取余)(取余)(取余)1、算术运算符、算术运算符 1)1)两个整数相除,将保留整数部分,不是四舍五入;进行浮点数除法,两个整数相除,将保留整数部分,不是四舍五入;进行浮点数除法,结果是浮点型。如结果是浮点型。如7/5.0、7.0/5、7.0/5.0的结果都是的结果都是1.4。2) 2) 求余运算要求参与运算的两个操作数都是整型,其结果是两个数相除的求余运算要求参与运算的两个操作数都是整型,其结果是两个数相除的余数。例如余数。例如40%540%5的结果是的结果是0 0,40
102、%1140%11的结果是的结果是7 7。要理解负值的求余运算,例。要理解负值的求余运算,例如如40%-1140%-11结果是结果是7 7,-40%11-40%11结果是结果是-7-7,-40%-11-40%-11结果也是结果也是-7-7。注意注意注意注意135计算机科学与技术学院张淼增增增增1 1、减、减、减、减1 1运算符都是一元运算符,这两个运算符都有前置和后置两种形式。运算符都是一元运算符,这两个运算符都有前置和后置两种形式。运算符都是一元运算符,这两个运算符都有前置和后置两种形式。运算符都是一元运算符,这两个运算符都有前置和后置两种形式。前置形式是指运算符在操作数的前面,后置是指运算符
103、在操作数的后面。前置形式是指运算符在操作数的前面,后置是指运算符在操作数的后面。前置形式是指运算符在操作数的前面,后置是指运算符在操作数的后面。前置形式是指运算符在操作数的前面,后置是指运算符在操作数的后面。例如:例如:例如:例如:I+I+;/+/+后置后置后置后置-J-J;/-/-前置前置前置前置(2 2)增)增1 1、减、减1 1运算符运算符注意:只能操作变量,不能操作常量。前置和后置的区别。注意注意注意注意136计算机科学与技术学院张淼操作数的类型转换操作数的类型转换如果两个操作数的类型不同,系统将自动地把其中操作数类型低的转换成如果两个操作数的类型不同,系统将自动地把其中操作数类型低的
104、转换成如果两个操作数的类型不同,系统将自动地把其中操作数类型低的转换成如果两个操作数的类型不同,系统将自动地把其中操作数类型低的转换成和另一个相同。和另一个相同。和另一个相同。和另一个相同。类型转换方式类型转换方式类型转换方式类型转换方式隐含转换隐含转换隐含转换隐含转换强制转换强制转换强制转换强制转换各种类型的高低顺序如下:各种类型的高低顺序如下:各种类型的高低顺序如下:各种类型的高低顺序如下:intintunsignedunsignedlonglongunsignedunsigned longlongdoubledoublecharchar、shortshortfloatfloat char
105、char、shortshort类型自动转换成类型自动转换成类型自动转换成类型自动转换成intint,floatfloat类型自动转换成类型自动转换成类型自动转换成类型自动转换成doubledouble型。型。型。型。 两个操作数中有一个为两个操作数中有一个为两个操作数中有一个为两个操作数中有一个为longdoublelongdouble类型,另一个将也转换成类型,另一个将也转换成类型,另一个将也转换成类型,另一个将也转换成longdoublelongdouble类类类类型;否则,如果其中有一个为型;否则,如果其中有一个为型;否则,如果其中有一个为型;否则,如果其中有一个为doubledoubl
106、e类型,另一个将也转换成类型,另一个将也转换成类型,另一个将也转换成类型,另一个将也转换成doubledouble型;型;型;型;,如上顺序从低向高转换。,如上顺序从低向高转换。,如上顺序从低向高转换。,如上顺序从低向高转换。1).1).隐含转换隐含转换137计算机科学与技术学院张淼隐式转换的方向隐式转换的方向隐式转换的方向隐式转换的方向就是将一个取值范围较小的类型向取值范围较大的类型转就是将一个取值范围较小的类型向取值范围较大的类型转就是将一个取值范围较小的类型向取值范围较大的类型转就是将一个取值范围较小的类型向取值范围较大的类型转换。它能确保在转换过程中数据不受损失。换。它能确保在转换过程
107、中数据不受损失。换。它能确保在转换过程中数据不受损失。换。它能确保在转换过程中数据不受损失。注注注注类型的转换类型的转换类型的转换类型的转换并不实际改变操作数并不实际改变操作数并不实际改变操作数并不实际改变操作数的数据类型。它只是在计算表达式的数据类型。它只是在计算表达式的数据类型。它只是在计算表达式的数据类型。它只是在计算表达式值的时候,将操作数的值值的时候,将操作数的值值的时候,将操作数的值值的时候,将操作数的值临时做了转换临时做了转换临时做了转换临时做了转换。计算后,操作数仍保持原有的。计算后,操作数仍保持原有的。计算后,操作数仍保持原有的。计算后,操作数仍保持原有的数据类型。数据类型。
108、数据类型。数据类型。138计算机科学与技术学院张淼强制类型转换的强制类型转换的强制类型转换的强制类型转换的作用作用作用作用是将某种类型强制地转换成指定的类型。是将某种类型强制地转换成指定的类型。是将某种类型强制地转换成指定的类型。是将某种类型强制地转换成指定的类型。强制类型转换是通过强制转换运算符来实现的,具体表示形式如下:强制类型转换是通过强制转换运算符来实现的,具体表示形式如下:强制类型转换是通过强制转换运算符来实现的,具体表示形式如下:强制类型转换是通过强制转换运算符来实现的,具体表示形式如下: 类型说明符(操作数)类型说明符(操作数)类型说明符(操作数)类型说明符(操作数)或或或或(类
109、型说明符类型说明符类型说明符类型说明符)操作数操作数操作数操作数意义为把表达式的数据类型强制转换成类型说明符所指定的类型。意义为把表达式的数据类型强制转换成类型说明符所指定的类型。意义为把表达式的数据类型强制转换成类型说明符所指定的类型。意义为把表达式的数据类型强制转换成类型说明符所指定的类型。2).2).强制类型转换强制类型转换139计算机科学与技术学院张淼C+C+语言中,关系运算符都是二元运算符,共有语言中,关系运算符都是二元运算符,共有语言中,关系运算符都是二元运算符,共有语言中,关系运算符都是二元运算符,共有6 6个:个:个:个: (大于)、(大于)、(大于)、(大于)、=(大于或等于
110、)、(大于或等于)、(大于或等于)、(大于或等于)、=(等于)、(等于)、(等于)、(等于)、!=!=(不等于)。(不等于)。(不等于)。(不等于)。2、关系运算符、关系运算符 其比较的结果是一个其比较的结果是一个其比较的结果是一个其比较的结果是一个boolbool型的值。当两个操作数满足关系运算符指定型的值。当两个操作数满足关系运算符指定型的值。当两个操作数满足关系运算符指定型的值。当两个操作数满足关系运算符指定的关系时,表达式的值为的关系时,表达式的值为的关系时,表达式的值为的关系时,表达式的值为truetrue,否则为,否则为,否则为,否则为falsefalse。truetrue等于等于
111、等于等于1 1,falsefalse等于等于等于等于0 0。在在在在C+C+编译系统中,任何不为编译系统中,任何不为编译系统中,任何不为编译系统中,任何不为0 0的数被认为是的数被认为是的数被认为是的数被认为是“ “真真真真” ”,0 0被认为是被认为是被认为是被认为是“ “假假假假” ”。应避免对浮点数进行应避免对浮点数进行应避免对浮点数进行应避免对浮点数进行=和和和和!=!=比较运比较运比较运比较运算,如果需要,可采用判断两者的算,如果需要,可采用判断两者的算,如果需要,可采用判断两者的算,如果需要,可采用判断两者的 差的绝对值是否小于某个很小的数差的绝对值是否小于某个很小的数差的绝对值是
112、否小于某个很小的数差的绝对值是否小于某个很小的数来实现。来实现。来实现。来实现。x=yx=yfabs(x-yfabs(x-y)1e-6)1e-6)1e-6intinti=-10;i=-10;unsignedunsignedintintj=1;j=1;ij?ij?140计算机科学与技术学院张淼一元运算符:一元运算符:一元运算符:一元运算符:二元运算符二元运算符二元运算符二元运算符!(逻辑求反)!(逻辑求反)!(逻辑求反)!(逻辑求反)&(逻辑与)(逻辑与)(逻辑与)(逻辑与)| |(逻辑或)(逻辑或)(逻辑或)(逻辑或)若其操作数为若其操作数为若其操作数为若其操作数为0 0(falsefalse
113、),运算结果),运算结果),运算结果),运算结果为为为为true(1)true(1),否则为,否则为,否则为,否则为false(0)false(0)。只要两个操作数中有一个为只要两个操作数中有一个为只要两个操作数中有一个为只要两个操作数中有一个为0 0(falsefalse),),),),运算结果就为运算结果就为运算结果就为运算结果就为false(0)false(0),否则为,否则为,否则为,否则为true(1)true(1)。只要两个操作数中有一个不为只要两个操作数中有一个不为只要两个操作数中有一个不为只要两个操作数中有一个不为0 0(falsefalse),),),),运算结果为运算结果为
114、运算结果为运算结果为ture(1)ture(1),否则为,否则为,否则为,否则为false(0)false(0)。3、逻辑运算符、逻辑运算符 短路求值短路求值短路求值短路求值: :true|xtrue|xfalse&xfalse&x141计算机科学与技术学院张淼位运算符是对其操作数按其二进制形式逐位进行运算,参与运算的操作位运算符是对其操作数按其二进制形式逐位进行运算,参与运算的操作位运算符是对其操作数按其二进制形式逐位进行运算,参与运算的操作位运算符是对其操作数按其二进制形式逐位进行运算,参与运算的操作数应为整数。数应为整数。数应为整数。数应为整数。一元运算符:一元运算符:一元运算符:一元运
115、算符:二元运算符二元运算符二元运算符二元运算符(按位求反)(按位求反)(按位求反)(按位求反) &(按位与)(按位与)(按位与)(按位与) | |(按位或)(按位或)(按位或)(按位或) (按位异或)(按位异或)(按位异或)(按位异或) (右移位)(右移位)(右移位)(右移位)位运算符位运算符4、位运算符、位运算符 位运算的结果就是位运算表达式的值,参与运算的操作数的值位运算的结果就是位运算表达式的值,参与运算的操作数的值位运算的结果就是位运算表达式的值,参与运算的操作数的值位运算的结果就是位运算表达式的值,参与运算的操作数的值并没有变化。并没有变化。并没有变化。并没有变化。注注注注142计算
116、机科学与技术学院张淼5、sizeof运算符运算符 sizeofsizeof运算符用于计算某类型的数据占用的内存大小(字节数)。它是运算符用于计算某类型的数据占用的内存大小(字节数)。它是运算符用于计算某类型的数据占用的内存大小(字节数)。它是运算符用于计算某类型的数据占用的内存大小(字节数)。它是一个一元运算符,操作数可以是一个一元运算符,操作数可以是一个一元运算符,操作数可以是一个一元运算符,操作数可以是C+C+语言中任一合法的数据类型。语言中任一合法的数据类型。语言中任一合法的数据类型。语言中任一合法的数据类型。该运算符的使用形式如下:该运算符的使用形式如下:该运算符的使用形式如下:该运算
117、符的使用形式如下:sizeofsizeof(数据类型);(数据类型);(数据类型);(数据类型);sizeofsizeof(表达式);(表达式);(表达式);(表达式);143计算机科学与技术学院张淼复合赋值复合赋值 10种复合赋值运算符:+=,-=,*=,/=,%=,&=,|=,=,= 注意:注意: (1)(1)在复合赋值运算符之间不能有空格。(2) (2) 复合运算符的优先级和赋值符的优先级一样,在C/C+的所有运算符中只高于逗号运算符,而且复合赋值运算符的结合性也是从右至左的。 多重赋值多重赋值 多重赋值是指在一个赋值表达式中出现两个或更多的赋值符(“=”) 例如:例如:nNum1 =
118、nNum2 = nNum3 = 100;6、赋值运算符、赋值运算符 当赋值操作的两个操作数类型不同时,编译程序将按赋值当赋值操作的两个操作数类型不同时,编译程序将按赋值转换规则进行隐式类型转换,即右边操作数转换成左边的转换规则进行隐式类型转换,即右边操作数转换成左边的操作数类型。操作数类型。144计算机科学与技术学院张淼唯一的三目运算符是条件运算符。唯一的三目运算符是条件运算符。格式:格式:?:7、条件运算符、条件运算符 145计算机科学与技术学院张淼逗号运算符是优先级最低的运算符,它可以使多个表达式放在一行上。计算时,从左至右逐个计算每个表达式,最终整个表达式的结果是最后计算的那个表达式的类
119、型和值。例如:例如:j = ( i = 12 , i + 8);式中,i = 12 ,i + 8 是含逗号运算符的表达式,计算次序是先计算表达式i = 12,然后再计算i + 8,整个表达式的值是最后一个表达式的值,即i + 8的值20, 从而j的结果是20。 8、逗号运算符、逗号运算符 146计算机科学与技术学院张淼CH2.1.4基本语句基本语句147计算机科学与技术学院张淼语句可用于计算表达式的值、控制程序执行的顺序,有时语句也可能不作语句可用于计算表达式的值、控制程序执行的顺序,有时语句也可能不作语句可用于计算表达式的值、控制程序执行的顺序,有时语句也可能不作语句可用于计算表达式的值、控
120、制程序执行的顺序,有时语句也可能不作任何操作(空语句)。任何操作(空语句)。任何操作(空语句)。任何操作(空语句)。分类分类分类分类简单语句简单语句结构语句结构语句表达式语句表达式语句转移语句转移语句空语句空语句gotogoto语句语句breakbreak语句语句continuecontinue语句语句returnreturn语句语句复合语句复合语句选择语句选择语句循环语句循环语句ifif语句语句switchswitch语句语句switchswitch语句语句whilewhile语句语句do-whiledo-while语句语句forfor语句语句148计算机科学与技术学院张淼CH2.1.5函数
121、函数函数是一个能完成某一独立功能的子程序,也就是程序模函数是一个能完成某一独立功能的子程序,也就是程序模函数是一个能完成某一独立功能的子程序,也就是程序模函数是一个能完成某一独立功能的子程序,也就是程序模块。每个块。每个块。每个块。每个C+C+程序至少包含一个函数,即程序至少包含一个函数,即程序至少包含一个函数,即程序至少包含一个函数,即mainmain函数(主函数)。函数(主函数)。函数(主函数)。函数(主函数)。在在在在面向过程的程序设计面向过程的程序设计面向过程的程序设计面向过程的程序设计中,一个较为复杂的程序一般通过模块中,一个较为复杂的程序一般通过模块中,一个较为复杂的程序一般通过模
122、块中,一个较为复杂的程序一般通过模块化,分解成主模块与若干子模块的组合,即一个主函数与若干化,分解成主模块与若干子模块的组合,即一个主函数与若干化,分解成主模块与若干子模块的组合,即一个主函数与若干化,分解成主模块与若干子模块的组合,即一个主函数与若干子函数。程序是以函数为单位,由一个或多个函数组成的。子函数。程序是以函数为单位,由一个或多个函数组成的。子函数。程序是以函数为单位,由一个或多个函数组成的。子函数。程序是以函数为单位,由一个或多个函数组成的。在面向对象的程序设计中,一个在面向对象的程序设计中,一个在面向对象的程序设计中,一个在面向对象的程序设计中,一个C+C+程序是由类的实例程序
123、是由类的实例程序是由类的实例程序是由类的实例(对象)构成。函数主要用于定义对象的操作接口。(对象)构成。函数主要用于定义对象的操作接口。(对象)构成。函数主要用于定义对象的操作接口。(对象)构成。函数主要用于定义对象的操作接口。本部分介绍有关函数的一些基本知识,如:函数的定义及本部分介绍有关函数的一些基本知识,如:函数的定义及本部分介绍有关函数的一些基本知识,如:函数的定义及本部分介绍有关函数的一些基本知识,如:函数的定义及调用等。这些知识虽然大部分是建立在面向过程的程序设计方调用等。这些知识虽然大部分是建立在面向过程的程序设计方调用等。这些知识虽然大部分是建立在面向过程的程序设计方调用等。这
124、些知识虽然大部分是建立在面向过程的程序设计方法的基础上,但它们也是我们学习面向对象程序设计的基础。法的基础上,但它们也是我们学习面向对象程序设计的基础。法的基础上,但它们也是我们学习面向对象程序设计的基础。法的基础上,但它们也是我们学习面向对象程序设计的基础。149计算机科学与技术学院张淼在面向过程的程序设计中,一个在面向过程的程序设计中,一个在面向过程的程序设计中,一个在面向过程的程序设计中,一个C+C+程序由一个或程序由一个或程序由一个或程序由一个或多个函数组成。当程序开始运行时,系统自动调用主多个函数组成。当程序开始运行时,系统自动调用主多个函数组成。当程序开始运行时,系统自动调用主多个
125、函数组成。当程序开始运行时,系统自动调用主函数。主函数可以调用子函数,子函数还可以调用其函数。主函数可以调用子函数,子函数还可以调用其函数。主函数可以调用子函数,子函数还可以调用其函数。主函数可以调用子函数,子函数还可以调用其他子函数。他子函数。他子函数。他子函数。调用其他函数的函数称为主调函数,被其他函数调用调用其他函数的函数称为主调函数,被其他函数调用调用其他函数的函数称为主调函数,被其他函数调用调用其他函数的函数称为主调函数,被其他函数调用的函数称为被调函数。的函数称为被调函数。的函数称为被调函数。的函数称为被调函数。150计算机科学与技术学院张淼151计算机科学与技术学院张淼函数的定义
126、函数的定义函数的定义函数的定义在在在在C+C+程序中,定义一个函数的格式如下:程序中,定义一个函数的格式如下:程序中,定义一个函数的格式如下:程序中,定义一个函数的格式如下:类型类型类型类型 函数名(形式参数表)函数名(形式参数表)函数名(形式参数表)函数名(形式参数表) 语句序列语句序列语句序列语句序列 该函数的类型,即该该函数的类型,即该该函数的类型,即该该函数的类型,即该函数返回值的类型。函数返回值的类型。函数返回值的类型。函数返回值的类型。函数体:可以有函数体:可以有函数体:可以有函数体:可以有0 0条、条、条、条、1 1条或多条语句。条或多条语句。条或多条语句。条或多条语句。当是当是
127、当是当是0 0条语句时,该函数称作空函数。条语句时,该函数称作空函数。条语句时,该函数称作空函数。条语句时,该函数称作空函数。152计算机科学与技术学院张淼函数的返回值是需要返回给主调函数处理的结果,由函数的返回值是需要返回给主调函数处理的结果,由函数的返回值是需要返回给主调函数处理的结果,由函数的返回值是需要返回给主调函数处理的结果,由returnreturn语句给出。当该语句给出。当该语句给出。当该语句给出。当该函数没有返回值时,函数的类型为函数没有返回值时,函数的类型为函数没有返回值时,函数的类型为函数没有返回值时,函数的类型为voidvoid,可不写,可不写,可不写,可不写return
128、return语句。语句。语句。语句。每个函数每个函数每个函数每个函数都有类型都有类型都有类型都有类型,如果没有明确指定,则类型为,如果没有明确指定,则类型为,如果没有明确指定,则类型为,如果没有明确指定,则类型为intint。returnreturnreturnreturn语句的一般格式如下:语句的一般格式如下:语句的一般格式如下:语句的一般格式如下: return return return return 表达式;表达式;表达式;表达式;情况分类情况分类情况分类情况分类没有没有没有没有returnreturn语句:函数在被调用时,程序执行完函数体的最后语句:函数在被调用时,程序执行完函数体的
129、最后语句:函数在被调用时,程序执行完函数体的最后语句:函数在被调用时,程序执行完函数体的最后 一条语句后,自动返回主调函数。一条语句后,自动返回主调函数。一条语句后,自动返回主调函数。一条语句后,自动返回主调函数。有有有有returnreturn语句:语句:语句:语句:这时的这时的这时的这时的returnreturn语句应表示为:语句应表示为:语句应表示为:语句应表示为:returnreturn;对于没有返回值的函数,对于没有返回值的函数,对于没有返回值的函数,对于没有返回值的函数,returnreturnreturnreturn语句可有可无。语句可有可无。语句可有可无。语句可有可无。注注注注
130、一个函数中允许出现一个函数中允许出现一个函数中允许出现一个函数中允许出现多个多个多个多个returnreturnreturnreturn语句语句语句语句,分别用于不同条件下的函数返回。,分别用于不同条件下的函数返回。,分别用于不同条件下的函数返回。,分别用于不同条件下的函数返回。153计算机科学与技术学院张淼形式参数形式参数形式参数形式参数又称形参,将函数需要处理的数据、影响函数功能的因素和函数又称形参,将函数需要处理的数据、影响函数功能的因素和函数又称形参,将函数需要处理的数据、影响函数功能的因素和函数又称形参,将函数需要处理的数据、影响函数功能的因素和函数处理的结果作为形参,实现主调函数与
131、被调函数之间的联系。处理的结果作为形参,实现主调函数与被调函数之间的联系。处理的结果作为形参,实现主调函数与被调函数之间的联系。处理的结果作为形参,实现主调函数与被调函数之间的联系。没有形参没有形参没有形参没有形参的的的的函数,可以在形参表的位置填上函数,可以在形参表的位置填上函数,可以在形参表的位置填上函数,可以在形参表的位置填上voidvoid或或或或保留空白保留空白保留空白保留空白,但形参表两边的,但形参表两边的,但形参表两边的,但形参表两边的圆括号圆括号圆括号圆括号不可省略不可省略不可省略不可省略。形式参数表由形式参数表由形式参数表由形式参数表由0 0个、个、个、个、1 1个或多个参数
132、组成,内容如下:个或多个参数组成,内容如下:个或多个参数组成,内容如下:个或多个参数组成,内容如下:类型类型类型类型1 1 形式参数名形式参数名形式参数名形式参数名1 1,类型类型类型类型2 2 形式参数名形式参数名形式参数名形式参数名2 2,类型类型类型类型n n 形式参数名形式参数名形式参数名形式参数名n n说明了对应形式参说明了对应形式参说明了对应形式参说明了对应形式参数的数据类型。数的数据类型。数的数据类型。数的数据类型。是一个标识符。是一个标识符。是一个标识符。是一个标识符。154计算机科学与技术学院张淼函数的定义函数的定义函数的定义函数的定义doubledoublerectangl
133、earea(doublerectanglearea(double a,doublea,doubleb)b) doubles;doubles;s=a*b;s=a*b;returns;returns; 155计算机科学与技术学院张淼每个函数都是一个功能独立的模块,绝对不允每个函数都是一个功能独立的模块,绝对不允许在一个函数体内定义另一个函数。许在一个函数体内定义另一个函数。156计算机科学与技术学院张淼声明函数,一般采用声明函数原型。声明函数,一般采用声明函数原型。声明函数,一般采用声明函数原型。声明函数,一般采用声明函数原型。形式如下:形式如下:形式如下:形式如下:类型类型类型类型 函数名(形式
134、参数表);函数名(形式参数表);函数名(形式参数表);函数名(形式参数表);函数原型中的函数原型中的函数原型中的函数原型中的类型、函数名和形参表类型、函数名和形参表类型、函数名和形参表类型、函数名和形参表必须与定义该函数时必须与定义该函数时必须与定义该函数时必须与定义该函数时完全一致完全一致完全一致完全一致,但函数,但函数,但函数,但函数原型中可以原型中可以原型中可以原型中可以不包含不包含不包含不包含参数名,而参数名,而参数名,而参数名,而只包含只包含只包含只包含形参的类型。形参的类型。形参的类型。形参的类型。例如:例如:例如:例如: double double double double r
135、ectanglearea(doublerectanglearea(doublerectanglearea(doublerectanglearea(double a,doublea,doublea,doublea,double b) b) b) b); double double double double rectanglearea(doublerectanglearea(doublerectanglearea(doublerectanglearea(double,double)double)double)double);必须以分号结尾。必须以分号结尾。必须以分号结尾。必须以分号结尾。函数的声
136、明函数的声明函数的声明函数的声明157计算机科学与技术学院张淼除除除除主函数主函数主函数主函数mainmainmainmain由系统自动调用外,其他函数都由主函数直接或间接调用的。由系统自动调用外,其他函数都由主函数直接或间接调用的。由系统自动调用外,其他函数都由主函数直接或间接调用的。由系统自动调用外,其他函数都由主函数直接或间接调用的。函数的调用函数的调用函数的调用函数的调用函数的调用的一般形式如下:函数的调用的一般形式如下:函数的调用的一般形式如下:函数的调用的一般形式如下: 函数名(实际参数表)函数名(实际参数表)函数名(实际参数表)函数名(实际参数表)程序中调用的所有函数都要有定义,
137、如果函数定义在其程序中调用的所有函数都要有定义,如果函数定义在其他文件中(如他文件中(如C+的标准库)或定义在本源文件使用点的标准库)或定义在本源文件使用点之后,则在调用前需要对被调用的函数进行声明。之后,则在调用前需要对被调用的函数进行声明。158计算机科学与技术学院张淼main()调fun()结束fun()返回保存:返回地址当前现场恢复:主调程序现场返回地址159计算机科学与技术学院张淼使用值调用使用值调用使用值调用使用值调用时,系统首先为形参分配内存空间,并将实参的值按位置时,系统首先为形参分配内存空间,并将实参的值按位置时,系统首先为形参分配内存空间,并将实参的值按位置时,系统首先为形
138、参分配内存空间,并将实参的值按位置一一一一一对应一对应一对应一对应赋给形参。在被调用函数中形参值的任何改变都不会影响到实参。赋给形参。在被调用函数中形参值的任何改变都不会影响到实参。赋给形参。在被调用函数中形参值的任何改变都不会影响到实参。赋给形参。在被调用函数中形参值的任何改变都不会影响到实参。函数调用时,如果被调用函数带有形参,系统需要首先给它的形参函数调用时,如果被调用函数带有形参,系统需要首先给它的形参函数调用时,如果被调用函数带有形参,系统需要首先给它的形参函数调用时,如果被调用函数带有形参,系统需要首先给它的形参分配内存空间,并用调用表达式中的实参初始化形参。分配内存空间,并用调用
139、表达式中的实参初始化形参。分配内存空间,并用调用表达式中的实参初始化形参。分配内存空间,并用调用表达式中的实参初始化形参。函数调用时的参数传递函数调用时的参数传递函数调用时的参数传递函数调用时的参数传递指的就是实参与形参结合过程。指的就是实参与形参结合过程。指的就是实参与形参结合过程。指的就是实参与形参结合过程。实参与形参结合方法实参与形参结合方法实参与形参结合方法实参与形参结合方法传值调用传值调用传值调用传值调用: :传址调用传址调用传址调用传址调用引用调用引用调用引用调用引用调用简称值调用(默认)。简称值调用(默认)。简称值调用(默认)。简称值调用(默认)。160计算机科学与技术学院张淼X
140、N被调函数:被调函数:主调函数:主调函数:32.5AD=power(A,3)2.53doublepower(doubleX,intN)161计算机科学与技术学院张淼例:例:输入两输入两整数交换后输出整数交换后输出#includevoid Swap(int a, int b);int main( )int x(5), y(10);coutx=x y=yendl;Swap(x,y);coutx=x y=yendl;return 0;162计算机科学与技术学院张淼void Swap(int a, int b)int t;t=a;a=b;b=t;运行结果运行结果:x=5y=10x=5y=10163计算
141、机科学与技术学院张淼数组作为函数参数数组作为函数参数o数组元素作实参,与单个变量一样。数组元素作实参,与单个变量一样。o数组名作参数,形、实参数都应是数组名,数组名作参数,形、实参数都应是数组名,类型要一样,传送的是数组首地址。对形参类型要一样,传送的是数组首地址。对形参数组的改变会直接影响到实参数组。数组的改变会直接影响到实参数组。164计算机科学与技术学院张淼嵌套调用嵌套调用main调fun1()结束fun1()调fun2()返回fun2()返回165计算机科学与技术学院张淼例例输入两个整数,求平方和。输入两个整数,求平方和。#include #include void void main
142、(voidmain(void) ) intint a,ba,b; ; intint fun1(int fun1(int x,intx,int y); y); cincinab;ab; coutcoutaa、b b的的平平方方和和: fun1(a,b)fun1(a,b)endlendl; ; 166计算机科学与技术学院张淼intint fun1(int fun1(int x,intx,int y) y) intint fun2(int m); fun2(int m); return ( return (fun2(x)fun2(x)+ +fun2(y)fun2(y);); intint fun2(
143、int m)fun2(int m) return (m*m); return (m*m); 运行结果:运行结果:3 43 4a a、b b的平方和:的平方和:2525167计算机科学与技术学院张淼递归调用递归调用o函数直接或间接地调用自身,称为递归调用。o递归过程的两个阶段:n递推:递推:4!=43!3!=32!2!=21!1!=10!0!=1未知未知已知已知n回归:回归:4!=43!=243!=32!=62!=21!=21!=10!=10!=1未知已知168计算机科学与技术学院张淼例例求求n!分析:计算n!的公式如下:这是一个递归形式的公式,应该用递归函数实现。169计算机科学与技术学院张淼
144、#include #include long long facfac(int(int n) n) long f; long f; if (n0) if (n0) coutcoutn0,data error!n0,data error!endlendl; ; else if (n=0) f=1; else if (n=0) f=1; else f= else f=facfac(n-1)*n;(n-1)*n; return(freturn(f);); 170计算机科学与技术学院张淼void mainvoid main( ) long long fac(intfac(int n); n); inti
145、nt n; n; long y; long y; coutcoutEnter a positive integer:;n;n; y= y=facfac(n(n);); coutcoutn!=yn!=yendlendl; ; 运行结果:运行结果:Enter a positive integer:8Enter a positive integer:88!=403208!=40320171计算机科学与技术学院张淼程程序序的的执执行行过过程程中中,调调用用函函数数时时先先要要保保存存主主调调函函数数的的现现场场和和返返回回地地址址,然然后后程程序序转转移移到到被被调调函函数数的的起起始始地地址址继继续
146、续执执行行。被被调调函函数数执执行行结结束束后后,先先恢恢复复主主调调函函数数的的现现场场,取取出出返返回回地地址址并并将将返返回回值值赋赋给给函函数数调调用用本本身身,最最后后在在返返回回地地址址处处开开始始继继续续执执行行。当当函函数数体体比比较较小小时时,且且执执行行的的功功能能比比较较简简单时,这种函数调用方式的系统开销相对较大。单时,这种函数调用方式的系统开销相对较大。172计算机科学与技术学院张淼内联函数内联函数内联函数内联函数在程序编译时,编译系统将程序中出现内联函在程序编译时,编译系统将程序中出现内联函数调用的地方用函数体进行替换。由于在编译数调用的地方用函数体进行替换。由于在
147、编译时将函数体中的代码被替代到程序中,因此会时将函数体中的代码被替代到程序中,因此会增加目标程序代码量增加目标程序代码量,进而增加空间开销,而,进而增加空间开销,而在时间开销上不象函数调用时那么大,可见它在时间开销上不象函数调用时那么大,可见它是以目标代码的增加为代价来换取时间的节省。是以目标代码的增加为代价来换取时间的节省。内联函数的使用会增加程序的代码量。内联函数的使用会增加程序的代码量。内联函数的使用会增加程序的代码量。内联函数的使用会增加程序的代码量。注注注注内联函数一般来说仅适用于只有一、两条语句的小函数。内联函数一般来说仅适用于只有一、两条语句的小函数。内联函数一般来说仅适用于只有
148、一、两条语句的小函数。内联函数一般来说仅适用于只有一、两条语句的小函数。173计算机科学与技术学院张淼内联函数的定义:在函数定义时,在函数的类型前增加关内联函数的定义:在函数定义时,在函数的类型前增加关键字键字inline。形式如下:形式如下:形式如下:形式如下:inlineinline类型类型类型类型 函数名(形参函数名(形参函数名(形参函数名(形参表)表)表)表) ././函数体函数体函数体函数体 说明:仅在声明函数原型时加说明:仅在声明函数原型时加说明:仅在声明函数原型时加说明:仅在声明函数原型时加上关键字上关键字上关键字上关键字inlineinline,并不能达到,并不能达到,并不能达
149、到,并不能达到内联效果。内联效果。内联效果。内联效果。174计算机科学与技术学院张淼#includeinline double CalArea(double radius)return 3.14*radius*radius;int main( )double r(3.0);double area;area=CalArea(r);coutareaendl;return 0;175计算机科学与技术学院张淼(1)(1)内联函数的定义必须出现在内联函数第一次被内联函数的定义必须出现在内联函数第一次被调用之前。内联函数只能先定义后使用,不存在调用之前。内联函数只能先定义后使用,不存在先声明再使用。先声明
150、再使用。(2) (2) 内联函数名具有文件作用域内联函数名具有文件作用域 ,在一个文件中,在一个文件中定义的内联函数对于另一个文件是不可见的,因定义的内联函数对于另一个文件是不可见的,因此调用内联函数时一定要见到内联函数的定义。此调用内联函数时一定要见到内联函数的定义。对于一个多文件结构的程序,如果在一个源文件对于一个多文件结构的程序,如果在一个源文件中定义了一个内联函数,而在另一个源文件中对中定义了一个内联函数,而在另一个源文件中对其声明并使用,这将导致程序连接时刻的错误。其声明并使用,这将导致程序连接时刻的错误。注注注注176计算机科学与技术学院张淼o在一个函数中,要求通过函数来实现一种不
151、太复杂的功能,并且要求加快执行速度,选用()合适。A.内联函数B.重载函数C.递归调用 D.嵌套调用177计算机科学与技术学院张淼(3)(3)需要定义成的内联函数不能含有循环、switch和复杂嵌套的if语句。(4)(4)递归函数是不能被用来做内联函数的。(5) (5) 把成员函数的定义放在类定义中是建议编译程把成员函数的定义放在类定义中是建议编译程序按内联函数处理它们。序按内联函数处理它们。 编译器是否将用户定义成的内联函数作为真正的内联函数处理由它自行决定。 注注注注178计算机科学与技术学院张淼全局变量与局部变量全局变量与局部变量全局变量与局部变量全局变量与局部变量在在C+中,根据变量的
152、定义位置,中,根据变量的定义位置,把变量分为全局变量和局部变量。把变量分为全局变量和局部变量。全局变全局变量是指定义在函数外部的变量,它能被所量是指定义在函数外部的变量,它能被所有函数使用。局部变量是指在复合语句有函数使用。局部变量是指在复合语句(函数)中定义的变量,它们只能在定义(函数)中定义的变量,它们只能在定义它们的复合语句(包括内层的复合语句)它们的复合语句(包括内层的复合语句)中使用。中使用。179计算机科学与技术学院张淼180计算机科学与技术学院张淼全局变量可以定义在函数外的任何地方,如果在全局变量可以定义在函数外的任何地方,如果在使用一个全局变量时未见到它的定义,则在使用使用一个
153、全局变量时未见到它的定义,则在使用前需要对该全局变量进行声明。前需要对该全局变量进行声明。变量声明格式:extern;变量定义要给变量分配空间,变量声明则否。在整个程序中,一个变量的定义只有一个,而该变量的声明可以有多个。181计算机科学与技术学院张淼局部变量也可以放在复合语句的任何位置,但是,局部变量也可以放在复合语句的任何位置,但是,在复合语句中局部变量定义在复合语句中局部变量定义之前不能使用他们。之前不能使用他们。intmain()x/errorintx;x/ok182计算机科学与技术学院张淼函数的形参也可看成局部变量,它们函数的形参也可看成局部变量,它们只能在相应的函数中使用。只能在相
154、应的函数中使用。183计算机科学与技术学院张淼变量是变量是内存空间内存空间的一种抽象,程序中定义的每个的一种抽象,程序中定义的每个变量在程序运行时刻都有与之对应的变量在程序运行时刻都有与之对应的内存空间内存空间。但是,何时给变量分配空间以及相应空间分配在但是,何时给变量分配空间以及相应空间分配在哪里?这要视变量的性质而定。通常把程序运行哪里?这要视变量的性质而定。通常把程序运行时一个变量占有内存空间的时间段称为该时一个变量占有内存空间的时间段称为该变量的变量的生存期生存期。变量的存储分配(生存期)变量的存储分配(生存期)184计算机科学与技术学院张淼静态静态内存空间从程序开始执行就进行分配,直
155、到程序结束才收回。全局变量具有静态生存期全局变量具有静态生存期。自动自动内存空间在程序执行到它们所在的复合语句(函数)时才分配,当定义它们的复合语句执行结束时,它们的空间将会收回。局部变量和函数的参数一般一般具有自动生存期。动态动态内存空间用new操作分配、用delete操作收回。变量的三种生存期变量的三种生存期185计算机科学与技术学院张淼另外,在定义另外,在定义局部变量局部变量时,可以为它们加上时,可以为它们加上存储类型存储类型修饰符修饰符auto、static或或register来指定它们的生存期。来指定它们的生存期。局部变量的默认存储类型为局部变量的默认存储类型为auto,即定义局部变
156、量时,即定义局部变量时,如果未指定存储类,则其存储类为如果未指定存储类,则其存储类为auto。定义为。定义为auto存储类存储类的局部变量具有自动生存期;的局部变量具有自动生存期;定义为定义为static存储类的局部变量存储类的局部变量具有静态生存期;具有静态生存期;定义为定义为register存储类的局部变量也具有存储类的局部变量也具有自动生存期。它与自动生存期。它与auto存储类的局部变量的区别是:存储类的局部变量的区别是:register存储类是存储类是建议建议编译程序把相应的局部变量的空间分编译程序把相应的局部变量的空间分配在配在CPU的寄存器中,目的是为了提高对局部变量的访问效的寄存
157、器中,目的是为了提高对局部变量的访问效率。率。static存储类的局部变量的作用是它能在函数调用时获存储类的局部变量的作用是它能在函数调用时获得上次调用结束时该局部变量的值。得上次调用结束时该局部变量的值。186计算机科学与技术学院张淼#includeintz=0;voidf()intx=0;staticinty=0;x+;y+;z+;cout“x=“x“,y=”y“,z=”zendl;voidmain()f();z+;f();187计算机科学与技术学院张淼当一个程序准备运行时,当一个程序准备运行时,操作系统将为其分配一块操作系统将为其分配一块内存空间,其中包括四个内存空间,其中包括四个部分:
158、部分:静态数据区静态数据区(static codestatic code)、代码)、代码区(区(codecode)、栈区)、栈区(stackstack)和堆区()和堆区(heap heap , ,或称自由存储区或称自由存储区,free ,free storestore)。静态数据区静态数据区代码区代码区栈区栈区堆区堆区程序内存分配示意图188计算机科学与技术学院张淼静态数据区用于全局变量、静态数据区用于全局变量、static存储类的局部变量以存储类的局部变量以及常量的内存分配。及常量的内存分配。代码区用于存放程序的指令,对代码区用于存放程序的指令,对C+程序而言,代码区程序而言,代码区存放的是
159、所有函数代码;存放的是所有函数代码;栈区用于栈区用于auto存储类的局部变量、函数的形式参数以及存储类的局部变量、函数的形式参数以及函数调用时的有关信息(如函数返回地址等)的内存分函数调用时的有关信息(如函数返回地址等)的内存分配;配;堆区用于动态变量的内存分配。堆区用于动态变量的内存分配。静态数据区静态数据区代码区代码区栈区栈区堆区堆区189计算机科学与技术学院张淼o全局变量、static存储类的局部变量(存放在静态数据区的变量)在变量定义时有默认值。int型为0,浮点型为0.0,char型为空。oauto存储类的局部变量在定义时没有值,此时是一个不可预料的值,因此我们必须在使用前对它进行赋
160、值或初始化。190计算机科学与技术学院张淼全局变量,是在全局变量,是在main()函数执行前就分配好了的。函数执行前就分配好了的。其实,在其实,在main()函数中的显示代码执行之前,会函数中的显示代码执行之前,会调用一个由编译器生成的调用一个由编译器生成的_main()函数,而函数,而_main()函数会进行所有全局变量的构造及初始化工作。而函数会进行所有全局变量的构造及初始化工作。而在在main()函数结束之前,会调用由编译器生成的函数结束之前,会调用由编译器生成的exit函数,来释放所有的全局变量。比如下面的代函数,来释放所有的全局变量。比如下面的代码:码:191计算机科学与技术学院张淼
161、voidmain(void)/显式代码voidmain(void)_main();/隐式代码,由编译器产生,用以构造所有全局变量/显式代码exit();/隐式代码,由编译器产生,用以释放所有全局变量192计算机科学与技术学院张淼C+C+程序的多模块结构程序的多模块结构程序的多模块结构程序的多模块结构逻辑上,一个逻辑上,一个C+程序由一些全局函数(区别于类程序由一些全局函数(区别于类定义中的成员函数)、全局常量、全局变量定义中的成员函数)、全局常量、全局变量/对象以及类对象以及类的定义构成,其中必须有且仅有一个的定义构成,其中必须有且仅有一个main的全局函数。的全局函数。函数内部还可以包含形参
162、、局部常量、局部变量函数内部还可以包含形参、局部常量、局部变量/对象的对象的定义以及语句。定义以及语句。C+函数内部不能再定义函数。函数内部不能再定义函数。193计算机科学与技术学院张淼为了便于组织、管理和理解为了便于组织、管理和理解C+程序,在物理上我们通常程序,在物理上我们通常可以按照某种规则对构成可以按照某种规则对构成C+程序的若干逻辑单位(全局程序的若干逻辑单位(全局函数、全局常量、全局变量函数、全局常量、全局变量/对象、类等)进行分组,分别对象、类等)进行分组,分别把它们放到若干源文件中。编译程序对每个源文件分别进行把它们放到若干源文件中。编译程序对每个源文件分别进行编译。编译。分组
163、的原则是按照模块进行,一个模块一般包含两部分:接分组的原则是按照模块进行,一个模块一般包含两部分:接口和实现。接口给出在本模块中定义的、提供给其他模块使口和实现。接口给出在本模块中定义的、提供给其他模块使用的一些程序实体(如函数、全局变量等)的声明;模块的用的一些程序实体(如函数、全局变量等)的声明;模块的实现给出了模块中实体的定义。实现给出了模块中实体的定义。在在C+中,一个模块通常由两个源文件构成,一个是中,一个模块通常由两个源文件构成,一个是.h文文件,用于存放模块接口的定义;另一个是件,用于存放模块接口的定义;另一个是.cpp文件用于存放文件用于存放模块的实现。在一个模块中要用到另一个
164、模块中定义的程序模块的实现。在一个模块中要用到另一个模块中定义的程序实体时,需要在前者的实体时,需要在前者的.cpp文件中用文件包含命令把后者的文件中用文件包含命令把后者的.h文件包含进来。文件包含进来。194计算机科学与技术学院张淼在编译前,用命令中的文件名所指定的文件内容替换该命令。在编译前,用命令中的文件名所指定的文件内容替换该命令。#include#include“文件名文件名”在系统指定的目录下寻找指定文件;在系统指定的目录下寻找指定文件;“”先在包含先在包含#include命令的源文件所在目录下查找指定文命令的源文件所在目录下查找指定文件,然后再在系统指定的目录下寻找指定的文件。件
165、,然后再在系统指定的目录下寻找指定的文件。编译预处理命令编译预处理命令文件包含文件包含195计算机科学与技术学院张淼VC+程序编译链接原理与过程程序编译链接原理与过程Animal.cppFish.cppmain.cppAnimal.hFish.h翻译单元1翻译单元2翻译单元3Animal.objFish.objmain.obj.libC+的标准库函数标准类库.exe可执行文件编译(Compile)预处理链接(Link)#include#include196计算机科学与技术学院张淼标识符的作用域标识符的作用域C+根据程序的结构和标识符定义的位置,为每一根据程序的结构和标识符定义的位置,为每一个定
166、义了的标识符规定了一个作用域。标识符的作用域个定义了的标识符规定了一个作用域。标识符的作用域是指一个定义了标识符的有效范围,即该标识符所标识是指一个定义了标识符的有效范围,即该标识符所标识的程序实体能的程序实体能被访问被访问的程序段。的程序段。C+把标识符的作用域分成若干类,其中包括:把标识符的作用域分成若干类,其中包括:局局部作用域、全局作用域、文件作用域、函数作用域、函部作用域、全局作用域、文件作用域、函数作用域、函数原型作用域、类作用域和名空间作用域数原型作用域、类作用域和名空间作用域。当标识符的作用域完全相同时,当标识符的作用域完全相同时,不允许出现相同的标识符名。而不允许出现相同的标
167、识符名。而当标识符具有不同的作用域时,当标识符具有不同的作用域时,允许标识符同名。允许标识符同名。197计算机科学与技术学院张淼局部作用域(块作用域)局部作用域(块作用域)局部作用域指在函数定义或复合语句中,从局部作用域指在函数定义或复合语句中,从标识符的定义点开始到函数定义或复合语句结束标识符的定义点开始到函数定义或复合语句结束之间的程序段。之间的程序段。C+中的中的局部常量名、局部变量名局部常量名、局部变量名/对象名对象名以及函数的形参名以及函数的形参名具有局部作用域。具有局部作用域。198计算机科学与技术学院张淼如果一个标识符的局部作用域中包含其它如果一个标识符的局部作用域中包含其它复合
168、语句(内层复合语句),并且在该内层复复合语句(内层复合语句),并且在该内层复合语句中定义了一个同名的不同实体,则外层合语句中定义了一个同名的不同实体,则外层定义的标识符的作用域应该是从其作用域中扣定义的标识符的作用域应该是从其作用域中扣除内层同名标识符的作用域之后得到的作用域。除内层同名标识符的作用域之后得到的作用域。局部实体定义前可以有语句,但这些语句局部实体定义前可以有语句,但这些语句不在相应标识符的作用域内,从而不能使用后不在相应标识符的作用域内,从而不能使用后面定义的标识符。面定义的标识符。199计算机科学与技术学院张淼全局作用域全局作用域全局作用域指构成全局作用域指构成C+程序的所有
169、源程序的所有源文件,具有全局作用域的标识符称为全局文件,具有全局作用域的标识符称为全局标识符。标识符。全局变量名全局变量名/对象名、全局函数名和全对象名、全局函数名和全局类名的作用域一般具有全局作用域。它局类名的作用域一般具有全局作用域。它们在整个程序中可用。们在整个程序中可用。200计算机科学与技术学院张淼如果某个局部作用域中定义了与某个全局标如果某个局部作用域中定义了与某个全局标识符同名的标识符,则该全局标识符的作用域应识符同名的标识符,则该全局标识符的作用域应扣掉与之同名的局部标识符作用域。扣掉与之同名的局部标识符作用域。在局部标识符的作用域中若要使用与其同名在局部标识符的作用域中若要使
170、用与其同名的全局标识符,则需要用的全局标识符,则需要用全局选择符(全局选择符(:)对对全局标识符进行修饰(受限)。全局标识符进行修饰(受限)。201计算机科学与技术学院张淼使用全局标识符时,若该标识符的定义点在其他使用全局标识符时,若该标识符的定义点在其他源文件中或在本源文件中使用点之后,则在使用源文件中或在本源文件中使用点之后,则在使用前需要声明它。前需要声明它。通常,把全局标识符的声明放在某个通常,把全局标识符的声明放在某个.h文件中,文件中,在需要使用这些全局标识符的源文件中用在需要使用这些全局标识符的源文件中用#include编译预处理命令把声明文件包含进来。编译预处理命令把声明文件包
171、含进来。202计算机科学与技术学院张淼文件作用域文件作用域文件作用域指单独的源文件。文件作用域指单独的源文件。在全局标识符的定义中加上在全局标识符的定义中加上static修饰符,修饰符,则该全局标识符就成了具有文件作用域的标识符,则该全局标识符就成了具有文件作用域的标识符,它们只能在定义它们的源文件中使用。它们只能在定义它们的源文件中使用。在函数外用在函数外用const定义的常量名具有文件定义的常量名具有文件作用域。作用域。用编译预处理命令用编译预处理命令#define定义的标识符不定义的标识符不属于作用域要考虑的范畴,因为它们在编译前属于作用域要考虑的范畴,因为它们在编译前将被替换成所定义的
172、内容。将被替换成所定义的内容。203计算机科学与技术学院张淼C+中的关键词中的关键词static有两个不有两个不同的含义。在局部变量的定义中,同的含义。在局部变量的定义中,static修饰符用于指定局部变量修饰符用于指定局部变量采用静态存储分配;而在全局标识采用静态存储分配;而在全局标识符的定义中,符的定义中,static修饰符用于修饰符用于把全局标识符的作用域改为文件作把全局标识符的作用域改为文件作用域。用域。204计算机科学与技术学院张淼函数作用域函数作用域函数作用域是指由整个函数定义所构成的程函数作用域是指由整个函数定义所构成的程序段。序段。语句标号是唯一具有函数作用域的标识符,语句标号
173、是唯一具有函数作用域的标识符,可以在定义它们的函数体的任何地方访问它们。可以在定义它们的函数体的任何地方访问它们。205计算机科学与技术学院张淼函数作用域与局部作用域的区别函数作用域与局部作用域的区别函数作用域包括整个函数,而局部作用域是函数作用域包括整个函数,而局部作用域是从定义点开始到函数定义或复合语句结束。从定义点开始到函数定义或复合语句结束。在函数体中一个语句标号只能定义一次,即在函数体中一个语句标号只能定义一次,即使在内层的复合语句中,也不能再定义与外层使在内层的复合语句中,也不能再定义与外层相同的语句标号。相同的语句标号。C+把语句标号作为一种特殊的标识符看待,把语句标号作为一种特
174、殊的标识符看待,它与其他种类的标识符属于不同的范畴,因此,它与其他种类的标识符属于不同的范畴,因此,语句标号的作用域可以和同名的其它标识符的语句标号的作用域可以和同名的其它标识符的作用域重叠。作用域重叠。206计算机科学与技术学院张淼函数原型作用域函数原型作用域函数原型作用域是指用于函数声明的函数原型,函数原型作用域是指用于函数声明的函数原型,其中的形参名(如果给出)的作用域从函数原型其中的形参名(如果给出)的作用域从函数原型开始到函数原型结束,即开始到函数原型结束,即在函数原型声明中的左、在函数原型声明中的左、右括号之间。右括号之间。在函数原型中声明的标识符可以与函数定在函数原型中声明的标识
175、符可以与函数定义中说明的标识符名称不同。义中说明的标识符名称不同。207计算机科学与技术学院张淼下列的标识符中,()是函数作用域的。A.函数形参B.语句标号C.外部静态类标识符D.自动类标识符208计算机科学与技术学院张淼file1.cppvoidf()file2.cppvoidf()Main.cppintmain()f();f();实现打印实现屏幕输出实现打印实现屏幕输出209计算机科学与技术学院张淼名空间(名空间(namespace)名空间是给一组程序实体的定义取一个名字使之构成一个作名空间是给一组程序实体的定义取一个名字使之构成一个作用域用域名空间作用域。名空间作用域。namespace
176、Aintx=1;voidf()voidg()210计算机科学与技术学院张淼在一个名空间中定义的全局标识符,其作用域为该名空在一个名空间中定义的全局标识符,其作用域为该名空间。当在一个名空间外部需要使用该名空间中定义的全间。当在一个名空间外部需要使用该名空间中定义的全局标识符时,可用该名空间的名字来修饰或受限。局标识符时,可用该名空间的名字来修饰或受限。如:如:A:f();当使用某个名空间上的程序实体时,如果这些程序实当使用某个名空间上的程序实体时,如果这些程序实体的名与其它全局程序实体的名不冲突,则可在使用体的名与其它全局程序实体的名不冲突,则可在使用前写一个前写一个using指示项,使得今后
177、使用相指示项,使得今后使用相应名空间中的程序实体时不必用空间名受限。应名空间中的程序实体时不必用空间名受限。211计算机科学与技术学院张淼voidprint(intvalue,intbase);print(x,10);print(x,2);题目:以某种进制形式输出整数。题目:以某种进制形式输出整数。212计算机科学与技术学院张淼带默认形参值的函数带默认形参值的函数在在C+中,允许在定义或声明函数时,为函数中,允许在定义或声明函数时,为函数的某些参数指定默认值。当调用这些函数时没的某些参数指定默认值。当调用这些函数时没有提供相应的实参时,则相应的形参采用指定有提供相应的实参时,则相应的形参采用指
178、定的默认值,否则相应的形参采用调用者提供的的默认值,否则相应的形参采用调用者提供的实参值。实参值。voidprint(intvalue,intbase=10);print(x);print(x,2);213计算机科学与技术学院张淼intadd(intx=5,inty=6)returnx+y;voidmain(void)add(10,20);/10+20add(10);/10+6add();/5+6214计算机科学与技术学院张淼o一个函数中有多个默认参数时,则形参分布中,一个函数中有多个默认参数时,则形参分布中,默认参数应从右到左逐渐定义(所有默认参数默认参数应从右到左逐渐定义(所有默认参数必须
179、放在参数表的最后,即在一个指定了默认必须放在参数表的最后,即在一个指定了默认值的参数的右边,不能出现没有指定默认值的值的参数的右边,不能出现没有指定默认值的参数)。参数)。215计算机科学与技术学院张淼int add(int x,int y=5,int z=6); /正确正确int add(int x=1,int y=5,int z); /错误错误int add(int x=1,int y,int z=6); /错误错误216计算机科学与技术学院张淼o在相同的作用域内,缺省形参值的声明应保持唯一,但如果在不同的作用域内,允许说明不同的缺省形参。217计算机科学与技术学院张淼int add(in
180、t x=1,int y=2);void main(void) int add(int x=3,int y=4); add( ); /使用局部缺省形参值(实现3+4)void fun(void) . add( ); /使用全局缺省形参值(实现1+2)218计算机科学与技术学院张淼/file.cppvoidf(inta,intb,intc)/函数f的定义/file1.cppvoidf(inta,intb,intc=2);/file2.cppvoidf(inta,intb=1,intc=0);219计算机科学与技术学院张淼oC+允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。方便使
181、用,便于记忆。o重载的要求:形参的个数不同或类型不同。函数重载形参类型不同intadd(intx,inty);floatadd(floatx,floaty);形参个数不同intadd(intx,inty);intadd(intx,inty,intz);220计算机科学与技术学院张淼重载函数的重载函数的重载函数的重载函数的返回类型返回类型返回类型返回类型,即函数类型可以相同,也可以不同。如果仅仅是,即函数类型可以相同,也可以不同。如果仅仅是,即函数类型可以相同,也可以不同。如果仅仅是,即函数类型可以相同,也可以不同。如果仅仅是返返返返回类型不同,而函数名相同、形参表也相同回类型不同,而函数名相同
182、、形参表也相同回类型不同,而函数名相同、形参表也相同回类型不同,而函数名相同、形参表也相同,则是,则是,则是,则是非法的非法的非法的非法的。例如:例如:例如:例如: intint fun(intfun(int a,inta,intb);b);longlongfun(intfun(int a,inta,intb);b);例如:例如:例如:例如: intint fun(intfun(int a,inta,intb);b);intint fun(intfun(int x,intx,inty);y);函数重载又称函数重载又称函数重载又称函数重载又称函数的多态性函数的多态性函数的多态性函数的多态性。它通
183、过改变形参的个数或类型使多个函数共。它通过改变形参的个数或类型使多个函数共。它通过改变形参的个数或类型使多个函数共。它通过改变形参的个数或类型使多个函数共用一个函数名。用一个函数名。用一个函数名。用一个函数名。不合法的不合法的不合法的不合法的说明:合法的。但说明:合法的。但说明:合法的。但说明:合法的。但不是重载。不是重载。不是重载。不是重载。它只是对同它只是对同它只是对同它只是对同一函数原型的多次声明。一函数原型的多次声明。一函数原型的多次声明。一函数原型的多次声明。221计算机科学与技术学院张淼当重载的函数带有默认参数时,应该注意避免二义性。当重载的函数带有默认参数时,应该注意避免二义性。
184、当重载的函数带有默认参数时,应该注意避免二义性。当重载的函数带有默认参数时,应该注意避免二义性。例如:例如:例如:例如: intint fun(intfun(int a,inta,intb=0);b=0);intint fun(intfun(inta);a);说明:遇到说明:遇到说明:遇到说明:遇到fun(2)fun(2)的函数调用时,编译的函数调用时,编译的函数调用时,编译的函数调用时,编译器将无法准确地确定应调用哪个函数。器将无法准确地确定应调用哪个函数。器将无法准确地确定应调用哪个函数。器将无法准确地确定应调用哪个函数。222计算机科学与技术学院张淼下面的函数声明中,()是”voidma
185、x(inta,intb);”的重载函数?A.intmax(inta,intb);B.voidmax(inta,charb);C.floatmax(inta,intb,intc=0);D.voidmax(inta,intb=0);223计算机科学与技术学院张淼定义定义定义定义:C+C+编译系统本身定义了几百个在编程时可能经常用到的函数。编译系统本身定义了几百个在编程时可能经常用到的函数。编译系统本身定义了几百个在编程时可能经常用到的函数。编译系统本身定义了几百个在编程时可能经常用到的函数。在使用某一系统函数前需要知道它的函数原型在哪个头文件中。这也可以在使用某一系统函数前需要知道它的函数原型在哪
186、个头文件中。这也可以在使用某一系统函数前需要知道它的函数原型在哪个头文件中。这也可以在使用某一系统函数前需要知道它的函数原型在哪个头文件中。这也可以通过通过通过通过库函数手册或联机帮助库函数手册或联机帮助库函数手册或联机帮助库函数手册或联机帮助查到。在使用某个系统函数前查到。在使用某个系统函数前查到。在使用某个系统函数前查到。在使用某个系统函数前所需要所需要所需要所需要做的就是做的就是做的就是做的就是用用用用includeinclude指令指令指令指令在程序中嵌入相应的头文件,然后便可以和调用自己定义的在程序中嵌入相应的头文件,然后便可以和调用自己定义的在程序中嵌入相应的头文件,然后便可以和调
187、用自己定义的在程序中嵌入相应的头文件,然后便可以和调用自己定义的函数一样使用系统函数。函数一样使用系统函数。函数一样使用系统函数。函数一样使用系统函数。C+C+语言的系统函数语言的系统函数语言的系统函数语言的系统函数224计算机科学与技术学院张淼CH2.1.6指针和引用指针和引用225计算机科学与技术学院张淼指针o指针变量的定义 *,*,.o类型为指针所指向的变量的类型,即指针类型。指针类型不是指针本身数据值的类型,任何一个指针本身的数据值都是unsignedlongint型。226计算机科学与技术学院张淼变量的地址变量的地址取地址符取地址符&来获得一个变量的地址。来获得一个变量的地址。对于数
188、组和函数,它们的内存首地址可以不用对于数组和函数,它们的内存首地址可以不用&来获得,来获得,数组变量名和函数名本身就表示它们在内存中的首地址。数组变量名和函数名本身就表示它们在内存中的首地址。对于常量0,它除了表示一个整型常量外,还可以表示一个空指针空指针。空指针不代表任何内存空间的地址,它属于所有空指针不代表任何内存空间的地址,它属于所有的指针类型。的指针类型。在C+的标准头文件cstdio或stdio.h中,定义了一个符号常量NULL,用于表示空指针。227计算机科学与技术学院张淼指针赋值o对于一个指针变量只能把在定义该指针变量时所指定类型的变量的地址赋给它。o在使用指针变量前,一定要对其
189、进行初始化或使其有确定的地址数值。o任何类型的指针都可以赋给void*类型的指针。228计算机科学与技术学院张淼间接访问操作*与-o对于一个指针变量可以通过间接访问操作符*来访问它所指向的变量。o对于一个指向结构体类型变量的指针,如果通过该指针变量来访问相应结构体变量的成员,则可写成:指针变量-结构成员(*指针变量).结构成员229计算机科学与技术学院张淼指针的输出o指针输出操作有一个例外:当输出字符指针(char*)时,输出的不是指针值,而是该指针所指向的字符串。charstr=“ABCD”;char*p=str;coutp;/输出:ABCDcout*p;/输出:A230计算机科学与技术学院
190、张淼指针作为形参类型地址调用o把指针作为形参的类型可以产生两个效果:n提高参数传递效率。n通过形参改变实参的值。o指向常量的指针nconst*;nconst的含义是不能改变所指向的数据的值。n指向常量的指针变量可以指向const常量也可指向变量,只不过不能通过它来改变所指向的变量值而已。n对于一个指向变量的指针变量,不允许它指向一个常量。231计算机科学与技术学院张淼constint*p;constintx;p=&x;*p=1;/errorinty;p=&y;*p=1;/errorY=1;/ok232计算机科学与技术学院张淼constintx=0;int*p;p=&x;/error233计算机
191、科学与技术学院张淼o不要将指向常量的指针类型与指针类型的常量混淆了。指针类型的常量必须初始化。intx,y;int*constp=&x;*p=1;p=&y;/错误,p是一个常量其值不能改变。234计算机科学与技术学院张淼inta=0;constint*p;说明()。A.不能修改p指针的值。B.不能通过p修改p所指向的变量的值。C.p=&a;是错误的。D.上述B、C二者。235计算机科学与技术学院张淼o已知intx;int*constp=&x;执行语句*p=1;会发生错误。()oWindowsAPI中的所有函数都包含在DLL中。()236计算机科学与技术学院张淼函数指针与返回指针值的函数o函数指
192、针:C+中可以定义一个指针变量,使它指向一个函数。(*)()double(*f)(int);o返回指针值的函数:返回值类型是一个指针类型。int*max(constintx,intnum)237计算机科学与技术学院张淼指针和数组238计算机科学与技术学院张淼指针与动态变量指针与动态变量动态变量:从静态的程序中无法确定它们的存在,动态变量:从静态的程序中无法确定它们的存在,只有当程序运行起来,随着程序的运行,它们根只有当程序运行起来,随着程序的运行,它们根据程序的需要动态产生和消亡。其内存分配在堆据程序的需要动态产生和消亡。其内存分配在堆区。动态变量没有名字,因此对动态变量的访问区。动态变量没有
193、名字,因此对动态变量的访问需要通过指向动态变量的指针变量来进行。需要通过指向动态变量的指针变量来进行。239计算机科学与技术学院张淼动态变量的创建onew类型(初值);onew类型第1维的大小第n维的大小;ovoid*malloc(unsignedintsize);o例:nint*p=newint;*p=1;nint*p=newint(100);nchar*p=newchar10;nint(*q)4=newint54;nint*p=(int*)malloc(sizeof(int);240计算机科学与技术学院张淼o在C+程序运行期间,动态变量不会自动消亡,在一个函数调用中创建的动态变量,函数返回
194、后仍然存在(可以使用)。如果不再需要这个动态变量了,则应该显式使之消亡。o用delete释放用new动态分配的内存空间ndelete指针变量ndelete指针变量o用free释放用malloc动态分配的内存空间nvoidfree(void*p)o注意事项nnew和delete应成对出现,malloc和free成对出现动态变量的撤消241计算机科学与技术学院张淼new和delete示例o开辟空间用来存放结构体变量#includestructstudentcharname10;intnum;intage;voidmain()student*p=newstudent;strcpy(p-name,张三
195、张三);p-num=10123;p-age=20;deletep;242计算机科学与技术学院张淼new和malloc比较o使用方便性nmalloc需要计算内存空间大小,通常需要与sizeof函数配合使用nmalloc的返回值为void*,赋值给某一类型的变量时需要进行强制类型转换ostudent*s=(student*)malloc(sizeof(student);nnew运算符自动计算内存空间大小,而且返回的就是具体的数据类型,不需要进行转换o程序执行效率nnew和delete是运算符,执行效率高nmalloc和free是函数,执行效率相对较低243计算机科学与技术学院张淼用用delete或
196、或free撤撤消消动动态态变变量量后后,C+编编译译程程序序一一般般不不会会把把指指向向它它的的指指针针变变量量的的值值赋赋为为NULL,这这时时就就会会出出现现“悬悬浮浮指指针针”(danglingpointer),它它指指向向一一个个无无效效空空间间。这这时时如如果果再再通通过过这这个个“悬悬浮浮指指针针”来来使使用用相相应应的的动态变量会导致程序的语义错误。动态变量会导致程序的语义错误。对对于于一一个个动动态态变变量量,如如果果没没有有撤撤消消它它,而而仅仅仅仅是是把把指指向向它它的的指指针针变变量量指指向向了了别别处处,或或指指向向它它的的指指针针变变量量的的生生存存期期结结束束了了,
197、这这个个动动态态变变量量就就会会变变成成一一个个“孤孤儿儿”,这这种种现现象象称称为为内内存存泄泄露露。程程序序中中再再也也访访问问不不到到它它,而它却一直占据内存空间,从而导致内存空间的浪费。而它却一直占据内存空间,从而导致内存空间的浪费。244计算机科学与技术学院张淼堆内存堆内存22000p栈内存栈内存voidf()int*p=newint(2);245计算机科学与技术学院张淼下面程序中的变量p,数字2,变量a,b,c分别被分配在()内存区。/xxx.cpp#includestaticintc=5;voidf()int*p=newint(2);voidmain()staticinta=0;
198、intb=3;f();coutabcendl;246计算机科学与技术学院张淼A.c为静态数据区;a,b,p为栈区,2为堆区B.c为静态数据区;a,b为栈区,2,p为堆区C.a,c为静态数据区;b为栈区,2,p为堆区D.a,c为静态数据区;p,b为栈区,2为堆区247计算机科学与技术学院张淼o什么是引用?什么是引用?n引用是引用是C+中针对变量的一种别名机制中针对变量的一种别名机制n引用不能单独存在,它的存在的前提是它所代引用不能单独存在,它的存在的前提是它所代表的变量首先存在表的变量首先存在o引用定义引用定义n类型类型&引用引用=变量名变量名o定义一个引用定义一个引用n例如:例如:inta;i
199、nt&b=a;引用引用248计算机科学与技术学院张淼249计算机科学与技术学院张淼引用示例引用示例o定义引用并使用引用定义引用并使用引用#includeusingnamespacestd;voidmain()inta=50;int&b=a;a=100;couta=aendl;coutb=bendl;250计算机科学与技术学院张淼引用的限制引用的限制o引用不能单独使用,必须进行初始化。引用不能单独使用,必须进行初始化。nint&a;/错误,没有初始化引用错误,没有初始化引用o引用变量定义后,它不能再引用其它变量引用变量定义后,它不能再引用其它变量o当引用类型变量的初始化值是常数时,则必须将当引用
200、类型变量的初始化值是常数时,则必须将该引用定义成该引用定义成const类型。类型。nintconsta=50;nconstint&b=a;251计算机科学与技术学院张淼o引用与其所引用的变量必须具有相同的类型引用与其所引用的变量必须具有相同的类型ninta=50;nfloat&b=a;/错误,引用与变量错误,引用与变量类型不一致类型不一致o可以对指针引用,因为指针也是变量可以对指针引用,因为指针也是变量ninta=50;nint*b=&a;nint*&c=b;/c是对指针变量是对指针变量b的引用的引用252计算机科学与技术学院张淼函数的参数传递(1)o值传递voidswap(inta,intb
201、)inttemp;temp=a;a=b;b=temp;voidmain()intm=3,n=5;swap(m,n);coutm=mn=nendl;253计算机科学与技术学院张淼函数的参数传递(2)o地址传递voidswap(int*a,int*b)inttemp;temp=*a;*a=*b;*b=temp;voidmain()intm=3,n=5;swap(&m,&n);coutm=mn=nendl;254计算机科学与技术学院张淼函数的参数传递(3)o引用传递voidswap(int&a,int&b)inttemp;temp=a;a=b;b=temp;voidmain()intm=3,n=5;
202、swap(m,n);coutm=mn=nendl;255计算机科学与技术学院张淼voidf(constint&x);voidmain()inta=3;f(a);256计算机科学与技术学院张淼引用作为函数返回值类型int&max(intx,intnum)inti,j;j=0;for(i=1;ixj)j=i;returnxj;inta10;coutmax(a,10)endl;max(a,10)+=1;257计算机科学与技术学院张淼CH2.2C+面向对象程序设计基础面向对象程序设计基础面向对象程序设计模拟自然界认识和处面向对象程序设计模拟自然界认识和处理事物的方法,将理事物的方法,将数据和对数据的操
203、作数据和对数据的操作方法放在一起方法放在一起,形成一个相对独立的整,形成一个相对独立的整体体对象(对象(object)面向对象的程面向对象的程序设计就是由这些对象构造程序序设计就是由这些对象构造程序,同,同类对象还可抽象出类对象还可抽象出共性共性,形成,形成类类(class )。一个类中的数据通常只能。一个类中的数据通常只能通过本类提供的方法进行处理,这些方通过本类提供的方法进行处理,这些方法成为该类与外部的接口。对象之间通法成为该类与外部的接口。对象之间通过过消息(消息(message)进行通讯。进行通讯。258计算机科学与技术学院张淼在面向过程的程序设计方法中,问题被看作一系列将在面向过程
204、的程序设计方法中,问题被看作一系列将被完成的任务,如读、计算和打印。许多函数用于完被完成的任务,如读、计算和打印。许多函数用于完成这些任务。问题的焦点集中于函数。成这些任务。问题的焦点集中于函数。259计算机科学与技术学院张淼面向过程程序设计的基本任务是编写计算机执面向过程程序设计的基本任务是编写计算机执行的指令序列,并把这些指令以函数的方式组织起行的指令序列,并把这些指令以函数的方式组织起来。通常我们使用流程图组织这些行为来。通常我们使用流程图组织这些行为(action),并描述从一个行为到另一个行为的),并描述从一个行为到另一个行为的控制流。控制流。当我们集中精力开发函数的时候,很少会去注
205、当我们集中精力开发函数的时候,很少会去注意那些被多个函数使用的数据(意那些被多个函数使用的数据(data)。在这些)。在这些数据身上发生了什么事情?那些使用这些数据的函数据身上发生了什么事情?那些使用这些数据的函数又对它们产生了什么影响?数又对它们产生了什么影响?在多函数(在多函数(multi-function)程序中,许多)程序中,许多重要的数据被放置在全局数据区,这样它们可以被重要的数据被放置在全局数据区,这样它们可以被所有的函数访问。每个函数都可以具有它们自己的所有的函数访问。每个函数都可以具有它们自己的局部数据。局部数据。260计算机科学与技术学院张淼261计算机科学与技术学院张淼面向
206、对象程序设计方法的主要出发点是弥补面向对象程序设计方法的主要出发点是弥补面向过程程序设计方法中的一些缺点。面向对象面向过程程序设计方法中的一些缺点。面向对象的设计思想力图使在计算机语言中对事物的描述的设计思想力图使在计算机语言中对事物的描述与现实世界中该事物的本来面目尽可能地一致。与现实世界中该事物的本来面目尽可能地一致。OOP把数据看作程序开发中的基本元素,并且不把数据看作程序开发中的基本元素,并且不允许它们在系统中自由流动。它将数据和操作这允许它们在系统中自由流动。它将数据和操作这些数据的函数紧密的连结在一起,并保护数据不些数据的函数紧密的连结在一起,并保护数据不会被外界的函数意外的改变。
207、会被外界的函数意外的改变。OOP允许我们将问允许我们将问题分解为一系列实体题分解为一系列实体这些实体被称为对象这些实体被称为对象(object),然后围绕这些实体建立数据和函数。),然后围绕这些实体建立数据和函数。262计算机科学与技术学院张淼263计算机科学与技术学院张淼面向对象的程序设计面向对象的程序设计1基基本本概概念念2 “面向对象面向对象”程序设计的特点程序设计的特点264计算机科学与技术学院张淼1基本概念对对对对 象(象(象(象(objectobject)类(类(类(类(classclass)消消消消 息(息(息(息(messagemessage)265计算机科学与技术学院张淼1基
208、本概念行为行为属性属性表针旋钮其他机械机构调节旋钮对 象266计算机科学与技术学院张淼1基本概念类是一个抽象的概念,用来描述某一类对象所共有的、类是一个抽象的概念,用来描述某一类对象所共有的、本质的属性和行为。本质的属性和行为。 类类 对象对象描述这类对象共有的、本质的属性和行为描述这类对象共有的、本质的属性和行为类的一个具体实现,称为实例类的一个具体实现,称为实例手表手表 一块手表一块手表手表共有的属性(表针、旋钮、内部结构)手表共有的属性(表针、旋钮、内部结构)和行为(调节旋钮)和行为(调节旋钮)具体到一只圆形的或方形的手表具体到一只圆形的或方形的手表类类267计算机科学与技术学院张淼1基
209、本概念我们把对象之间产生相互作用所传递的信息称做消息。我们把对象之间产生相互作用所传递的信息称做消息。 消消 息息启启 动动发送消息发送消息接收并响应消息接收并响应消息268计算机科学与技术学院张淼消消 息息1基本概念我们把对象之间产生相互作用所传递的信息称做消息。我们把对象之间产生相互作用所传递的信息称做消息。 发送消息发送消息接收并响应消息接收并响应消息转转 向向269计算机科学与技术学院张淼2“面向对象”程序设计的特点(1)封装性封装性(2) 继承与派生性继承与派生性(3) 多态性多态性270计算机科学与技术学院张淼2“面向对象”程序设计的特点封装性封装性内内外外机机械械零零件件动动作作
210、调调节节旋旋钮钮读读表表盘盘C+通过建立数据类型通过建立数据类型类来支持类来支持封装和数据隐藏。封装性增加了对象的封装和数据隐藏。封装性增加了对象的独立性,从而保证了数据的可靠性。一独立性,从而保证了数据的可靠性。一个定义完好的类可以作为独立模块使用。个定义完好的类可以作为独立模块使用。 对象是一个封装体,在其中封装了该对象是一个封装体,在其中封装了该对象的属性和操作。通过限制对属性和操对象的属性和操作。通过限制对属性和操作的访问权限,可以将属性作的访问权限,可以将属性“隐藏隐藏”在对在对象内部,对外提供一定的接口,在对象之象内部,对外提供一定的接口,在对象之外只能通过接口对对象进行操作。外只
211、能通过接口对对象进行操作。271计算机科学与技术学院张淼汽车汽车客车客车货车货车小轿车小轿车大客车大客车载货载人小,速度快大,速度慢2“面向对象”程序设计的特点继承与派生继承与派生以汽车为例看客观世界描述事物的方式:以汽车为例看客观世界描述事物的方式:当定义了一个类后,又需定义一个新当定义了一个类后,又需定义一个新类,这个新类与原来的类相比,只是增类,这个新类与原来的类相比,只是增加或修改了部分属性和操作,这时可以加或修改了部分属性和操作,这时可以用原来的类派生出新类,新类中只需描用原来的类派生出新类,新类中只需描述自己所特有的属性和操作。述自己所特有的属性和操作。面向对象程序设计提供了类似的
212、机制:面向对象程序设计提供了类似的机制:继承性大大简化了对问题的描述,大大提高了程序的可重用性,从而继承性大大简化了对问题的描述,大大提高了程序的可重用性,从而提高了程序设计、修改、扩充的效率。提高了程序设计、修改、扩充的效率。新类称为子类或派生类,原来的类称为基类。派生可以一直进行下去,新类称为子类或派生类,原来的类称为基类。派生可以一直进行下去,形成一个派生树。形成一个派生树。272计算机科学与技术学院张淼2“面向对象”程序设计的特点语文、数学、英语、政治、语文、数学、英语、政治、物理、化学、生物物理、化学、生物多态性多态性多态性指,同一个消息被不同对象接收时,产生不同多态性指,同一个消息
213、被不同对象接收时,产生不同结果,即实现同一接口,不同方法。结果,即实现同一接口,不同方法。高中生计计 算算平均成绩平均成绩273计算机科学与技术学院张淼2“面向对象”程序设计的特点多态性多态性多态性指,同一个消息被不同对象接收时,产生不同多态性指,同一个消息被不同对象接收时,产生不同结果,即实现同一接口,不同方法。结果,即实现同一接口,不同方法。计计 算算平均成绩平均成绩大学生高数、英语、计算机、线高数、英语、计算机、线性代数性代数274计算机科学与技术学院张淼类和对象类和对象275计算机科学与技术学院张淼类类o类的定义类的定义class类名类名;说明:说明:1、类名代表所定义的类的名字,用标
214、识符表示。、类名代表所定义的类的名字,用标识符表示。2、成员描述给出该类的对象所有的成员的说明,它、成员描述给出该类的对象所有的成员的说明,它包括成员函数和数据成员。包括成员函数和数据成员。3、在类定义的成员描述中还包含对成员的访问控制。、在类定义的成员描述中还包含对成员的访问控制。276计算机科学与技术学院张淼memsetoSetsbufferstoaspecifiedcharacter.ovoid*memset(void*dest,intc,size_tcount);ndest:Pointertodestinationnc:Charactertosetncount:Numberofchar
215、acters277计算机科学与技术学院张淼一个类中的方法可以直接一个类中的方法可以直接访问同类中的任何成员。访问同类中的任何成员。278计算机科学与技术学院张淼类的定义示例o定义一个Student类classStudentprivate:/访问控制说明访问控制说明intnumber,score;public:/访问控制说明访问控制说明voidinit()number=1001;score=100;voidshow()coutnumberendlscore数据成员名数据成员名n对象指针对象指针-成员函数名成员函数名(实参列表实参列表)n对象指针对象指针-成员名成员名等价:等价:n(*对象指针对象
216、指针)成员名成员名291计算机科学与技术学院张淼o在C+定义中,可以用访问控制修饰符public、private或protected来描述对类成员的访问限制。npublic:public成员的访问不受限制,在程序中的任何地方都可以访问一个类的public成员。nprivate:private成员只能在本类(本类的成员函数)和友元友元中访问。nprotected:protected成员只能在本类、派生派生类和友元类和友元中访问。成员的访问控制:信息隐藏292计算机科学与技术学院张淼o在类定义中可以有多个public、private和protected访问控制说明,它们出现的先后顺序无关。C+的默
217、认访问控制是private。o一般情况下,类的数据成员和在类内部使用的成员函数应该指定为private,只有提供给外界使用的成员函数才指定为public。指定为public的成员构成了类与外界的一种接口。操作一个对象时,只能通过访问对象类中的public成员实现。293计算机科学与技术学院张淼o间接方式间接创建和标识对象是指在程序运行时刻,通过new操作来创建对象。所创建的对象称为动态对象,其内存空间在程序的堆区中。动态对象用delete操作撤消(即使之消亡)。动态对象需要通过指针变量来标识。对象的创建和标识294计算机科学与技术学院张淼o单个动态对象的创建与撤消。A*p;p=newA;del
218、etep;A*p;p=(A*)malloc(sizeof(A);free(p);295计算机科学与技术学院张淼o动态对象数组的创建与撤消A*p;p=newA100;deletep;A*p;p=(A*)malloc(sizeof(A)*100);free(p);296计算机科学与技术学院张淼类作用域o类定义构成一个作用域:类作用域,其中的类定义构成一个作用域:类作用域,其中的标识符局部于类定义,它们可以与类定义外标识符局部于类定义,它们可以与类定义外的全局标识符或其他类定义中的标识符相同。的全局标识符或其他类定义中的标识符相同。在类定义外使用类定义中的在类定义外使用类定义中的标识符标识符时,需通
219、时,需通过对象名受限或类名受限。过对象名受限或类名受限。在类定义中使用在类定义中使用与局部标识符同名的全局标识符时,需要在与局部标识符同名的全局标识符时,需要在全局标识符前面加上全局域分辨符(全局标识符前面加上全局域分辨符(:)来)来实现。实现。297计算机科学与技术学院张淼classStudentprivate:intnumber;intscore;public:voidinit(intnumber,intscore)Student:number=number;Student:score=score;voidmain()Students1;s1.init();298计算机科学与技术学院张淼应
220、在下列程序划线处填入的正确语句是()。voidinit();classStudentprivate:intnumber;public:voidinit(intnumber);voidf();voidStudent:init(intnumber)_=number;voidStudent:f()_/调用全局函数init299计算机科学与技术学院张淼A.this-number;,:init();B.this:number;,:init();C.Student:number;,init();D.student-number;,init();300计算机科学与技术学院张淼classApublic:voi
221、df();voidg(inti)x=i;f();private:intx,y,z;aba.xa.ya.zb.xb.yb.zAa,b;g(inti)301计算机科学与技术学院张淼this指针指针每个成员函数都有一个隐藏的指针类型的形参每个成员函数都有一个隐藏的指针类型的形参this,其类,其类型为:型为:*constthis;成员函数中对类成员的访成员函数中对类成员的访问都是通过问都是通过this指针进行的。指针进行的。voidg(A*constthis,inti)this-x=i;this-f();voidg(inti)x=i;f();a.g(3);A:g(&a,3);302计算机科学与技术学
222、院张淼classStudentprivate:intnumber;intscore;public:voidinit(intnumber,intscore)this-number=number;this-score=score;voidmain()Students1;s1.init();303计算机科学与技术学院张淼voidfunc(A*p)classAintx;public:voidf()func(?);voidg(inti)x=i;f();Aa,b;a.f();b.f();要求:调用a.f()时,在A:f中调用func(&a);调用b.f()时,在A:f中调用func(&b);304计算机科
223、学与技术学院张淼小技巧:在以后的小技巧:在以后的MFC编程中,如果在成员函数中想调用同编程中,如果在成员函数中想调用同类中的某个成员,可以使用类中的某个成员,可以使用VC+提供的自动列出成员函数提供的自动列出成员函数功能,使用功能,使用this-,VC+将列出该类中的所有成员,我们可将列出该类中的所有成员,我们可以从列表中选择我们想调用的成员。以从列表中选择我们想调用的成员。自动列出成员函数功能,可以提高编写速度,减少拼写错误。自动列出成员函数功能,可以提高编写速度,减少拼写错误。我们经常不能完全记住某个函数的完整拼写,但却能够从列我们经常不能完全记住某个函数的完整拼写,但却能够从列表中辨别出
224、该函数,自动列出成员函数的功能在这时就显得表中辨别出该函数,自动列出成员函数的功能在这时就显得更加有用了。事实上,在各种更加有用了。事实上,在各种IDE编程环境中,我们通常都编程环境中,我们通常都不可能记住也没有必要记住所有的函数,只要将常用的函数不可能记住也没有必要记住所有的函数,只要将常用的函数记住,其他不常用的函数只要记住其大概的写法和功能,在记住,其他不常用的函数只要记住其大概的写法和功能,在调用该函数时可以从自动列出成员函数中选取,这样可以大调用该函数时可以从自动列出成员函数中选取,这样可以大大节省我们的学习时间。我们不用花费大量的时间去死记硬大节省我们的学习时间。我们不用花费大量的
225、时间去死记硬背许多函数,利用自动列出成员函数功能和帮助系统,就能背许多函数,利用自动列出成员函数功能和帮助系统,就能够在编程时顺利地使用这些函数,等用的次数多了,也就在够在编程时顺利地使用这些函数,等用的次数多了,也就在不知不觉中完全掌握了这些函数。不知不觉中完全掌握了这些函数。305计算机科学与技术学院张淼构造函数构造函数o什么是构造函数什么是构造函数n构造函数最重要的作用是创建对象本身构造函数最重要的作用是创建对象本身。n构造函数是一种特殊的成员函数,它主要用构造函数是一种特殊的成员函数,它主要用于为于为对象分配存储空间对象分配存储空间并对其成员进行并对其成员进行初始初始化化.nC+规定,
226、每个类必须有一个构造函数,没规定,每个类必须有一个构造函数,没有构造函数,就不能创建任何对象。有构造函数,就不能创建任何对象。306计算机科学与技术学院张淼nC+又规定,如果一个类没有提供任何的构又规定,如果一个类没有提供任何的构造函数,则造函数,则C+提供一个默认的构造函数(由提供一个默认的构造函数(由C+编译器提供),这个默认的构造函数是一编译器提供),这个默认的构造函数是一个不带参数的构造函数,该构造函数的函数体为个不带参数的构造函数,该构造函数的函数体为空,它只负责创建对象,而不做任何的初始化工空,它只负责创建对象,而不做任何的初始化工作。作。n只要一个类定义了一个构造函数,不管这个构
227、只要一个类定义了一个构造函数,不管这个构造函数是否是带参数的构造函数,造函数是否是带参数的构造函数,C+就不再就不再提供默认的构造函数。也就是说,如果为一个类提供默认的构造函数。也就是说,如果为一个类定义了一个带参数的构造函数,还想要无参数的定义了一个带参数的构造函数,还想要无参数的构造函数,则必须自己定义。构造函数,则必须自己定义。307计算机科学与技术学院张淼o构造函数的特点构造函数的特点n构造函数的名称必须与类名相同构造函数的名称必须与类名相同n构造函数构造函数没有返回值没有返回值,可以有参数可以有参数,可以重载可以重载n构造函数一般是构造函数一般是public的,但有时也把构造函的,但
228、有时也把构造函数声明为私有的(数声明为私有的(private),其作用是限制创),其作用是限制创建该类对象的范围,这时只能在本类和友元类中建该类对象的范围,这时只能在本类和友元类中创建该对象。创建该对象。n程序中不能直接调用构造函数,在创建对象时系程序中不能直接调用构造函数,在创建对象时系统自动调用构造函数。统自动调用构造函数。308计算机科学与技术学院张淼设计模式设计模式设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。设计模式就象经典的棋谱,不同的棋局,我们用不同的棋谱,免得自己再去思考和摸索。Singleton模式是做为全局变量的替代品出现的。所以它
229、具有全局变量的特点:全局可见、贯穿应用程序的整个生命期,它也具有全局变量不具备的性质:同类型的对象实例只可能有一个同类型的对象实例只可能有一个。小知识小知识309计算机科学与技术学院张淼构造函数示例构造函数示例o把把Student类中的函数类中的函数init改成构造函数改成构造函数classStudentprivate:intnumber;intscore;public:Student(intnumber,intscore)Student:number=number;Student:score=score;voidmain()Students1(1002,90);/创建一个学号为创建一个学号为
230、1002成绩为成绩为90的学生的学生Students2;/错误,类中没有无参构造函数错误,类中没有无参构造函数u构造函数也可以构造函数也可以“类内声类内声明,类外定义明,类外定义”310计算机科学与技术学院张淼在创建一个对象时,对象类的构造函数会在创建一个对象时,对象类的构造函数会被自动调用来对该对象进行初始化。至于被自动调用来对该对象进行初始化。至于调用对象类的哪个构造函数,这可以在创调用对象类的哪个构造函数,这可以在创建对象的时候指定。建对象的时候指定。311计算机科学与技术学院张淼ClassApublic:A();A(inti);A(char*p);Aa1;或Aa1=A();Aa2(1)
231、;或Aa2=A(1);或Aa2=1;Aa3(“abcd”);或Aa2=A(“abcd”);或Aa2=“abcd”;Aa4;Ab5=A(),A(1),A(“abcd”),2,”xyz”;A*p1=newA;A*p2=newA(2);A*p3=newA(“xyz”);A*p4=newA20;Aa1();312计算机科学与技术学院张淼析构函数o什么是析构函数n当一个对象生命周期结束时,其所占有的内存空间就要被回收,这个工作就由析构函数来完成。n析构函数是“反向”的构造函数,析构函数不允许有返回值,更重要的是析构函数不允许带参数,并且一个类中只能有一个析构函数.n析构函数的作用正好与构造函数相反,对象
232、超出其作用范围,对应的内存空间被系统收回或被程序用delete删除时,析构函数被调用.313计算机科学与技术学院张淼n根据析构函数的这种特点,我们可以在构造函数中初始化对象的某些成员变量,给其分配内存空间(堆内存),在析构函数中释放对象运行期间所申请的资源.314计算机科学与技术学院张淼o析构函数的特点析构函数的特点n析构函数的名称与类名相同,前面加上析构函数的名称与类名相同,前面加上“”n析构函数析构函数没有返回值没有返回值,没有参数没有参数,不能重载不能重载n析构函数不能被显式调用析构函数不能被显式调用n当对象被撤销时,系统自动调用析构函数当对象被撤销时,系统自动调用析构函数n类中未定义析
233、构函数,系统会自动生成默认的类中未定义析构函数,系统会自动生成默认的函数体为空的析构函数函数体为空的析构函数315计算机科学与技术学院张淼析构函数示例o在构造函数申请空间,析构函数释放空间classStudentprivate:char*name;intnumber;intscore;public:Student(char*name,intnumber,intscore)this-name=newcharstrlen(name)+1;strcpy(this-name,name);this-number=number;this-score=score;Student()deletename;u析
234、构函数同样可以析构函数同样可以“类内类内声明,类外定义声明,类外定义”316计算机科学与技术学院张淼拷贝构造函数o什么是拷贝构造函数n拷贝构造函数是一种特殊的构造函数,它的功能是用一个已知的对象来初始化一个被创建的同类对象。n拷贝构造函数实际上也是构造函数,具有一般构造函数的所有特性,它是在初始化时被调用来将一个已知对象的数据成员的值逐值拷贝给正在创建的一个同类的对象。n默认情况下系统自动创建拷贝构造函数317计算机科学与技术学院张淼如果在类定义中没有给出拷贝构造函数,则编译如果在类定义中没有给出拷贝构造函数,则编译系统将会隐式地为其提供一个拷贝构造函数,该系统将会隐式地为其提供一个拷贝构造函
235、数,该拷贝构造函数的行为是:逐个成员拷贝初始化。拷贝构造函数的行为是:逐个成员拷贝初始化。对于普通成员,它采用通常的初始化操作;对于对于普通成员,它采用通常的初始化操作;对于成员对象,则调用成员对象类的拷贝构造函数来成员对象,则调用成员对象类的拷贝构造函数来实现成员对象的初始化。实现成员对象的初始化。318计算机科学与技术学院张淼o拷贝构造函数的定义类名类名(const类名类名&object)319计算机科学与技术学院张淼o在在Student类中添加拷贝构造函数类中添加拷贝构造函数classStudentprivate:intnumber;intscore;public:Student(con
236、stStudent&student)number=student.number;score=student.score;320计算机科学与技术学院张淼以下三种情况将调用拷贝构造函数o定义对象时Aa1;Aa2(a1);Aa2=a1;Aa2=A(a1);o把对象作为值参数传给函数voidf(Ax);Aa;f(a);/调用时将创建形参对象x,并调用拷贝构造函数(用对象a)对其初始化。o把对象作为返回值321计算机科学与技术学院张淼Af()Aa;returna;/创建一个创建一个A类临时对象,并调用拷贝构类临时对象,并调用拷贝构造函数(用对象造函数(用对象a)对其初始化。)对其初始化。voidmain
237、()Ab;b=f();322计算机科学与技术学院张淼classStudentprivate:char*name;intnumber;intscore;public:Student(char*name,intnumber,intscore)this-name=newcharstrlen(name)+1;strcpy(this-name,name);this-number=number;this-score=score;Student()deletename;323计算机科学与技术学院张淼Studentstu1(“zhangsan”,101,90);Studentstu2(stu1);324计算机
238、科学与技术学院张淼深拷贝和潜拷贝问题深拷贝和潜拷贝问题o类体内的成员需要动态开辟内存的时我们应类体内的成员需要动态开辟内存的时我们应自定义拷贝构造函进行深拷贝,以防止潜拷贝自定义拷贝构造函进行深拷贝,以防止潜拷贝带来的堆内存的所属权产生混乱,从而造成析带来的堆内存的所属权产生混乱,从而造成析构错误构错误s1s2张三S2=S1*namenumberscore*namenumberscore栈空间栈空间堆空间堆空间325计算机科学与技术学院张淼voidf(Students)Aa;f(a);326计算机科学与技术学院张淼classStudentprivate:char*name;intnumber;
239、intscore;public:Student(char*name,intnumber,intscore)this-name=newcharstrlen(name)+1;strcpy(this-name,name);this-number=number;this-score=score;Student()deletename;Student(constStudent&a)number=a.number;score=a.score;name=newcharstrlen(a.name)+1;strcpy(name,a.name);327计算机科学与技术学院张淼const常量、引用的初始化问题?32
240、8计算机科学与技术学院张淼ClassAintx;constinty=1;/errorint&z=x;/errorpublic:A()x=0;y=1;/error,y是常量成员,其值不能改变是常量成员,其值不能改变;329计算机科学与技术学院张淼成员初始化表成员初始化表classAintx;constinty;int&z;public:A():z(x),y(1)x=0;330计算机科学与技术学院张淼classAintx;constinty;int&z;public:A():z(x),y(1),x(0);331计算机科学与技术学院张淼成员初始化表中成员初始化的书写次序并不决定成员初始化表中成员初始
241、化的书写次序并不决定它们的初始化次序,数据成员的初始化次序由它它们的初始化次序,数据成员的初始化次序由它们在类定义中的说明次序来决定。们在类定义中的说明次序来决定。当类中有常量数据成员或引用数据成员时,如果当类中有常量数据成员或引用数据成员时,如果类中定义了构造函数,则一定要在定义的构造函类中定义了构造函数,则一定要在定义的构造函数的成员初始化表中对它们进行初始化,数的成员初始化表中对它们进行初始化,如果类如果类中没有定义构造函数,则编译程序不会给该类生中没有定义构造函数,则编译程序不会给该类生成一个默认构造函数成一个默认构造函数。因此,这样的类程序是不。因此,这样的类程序是不能用于创建对象的
242、。能用于创建对象的。332计算机科学与技术学院张淼o系统提供的隐式拷贝构造函数会去调用成员对象的拷贝构造函数。自定义的拷贝构造函数不会去调用成员对象的拷贝构造函数,必须要在成员初始化列表中显示地指出。333计算机科学与技术学院张淼classA;classBintz;Aa;public:B();B(constB&b):a(b.a)z=b.z;334计算机科学与技术学院张淼程序运行的某个时刻,一个对象的所有数据成员程序运行的某个时刻,一个对象的所有数据成员的值反映了这个对象在该时刻的状态。在不同时的值反映了这个对象在该时刻的状态。在不同时刻,对象的状态可能是不一样的,对象状态的改刻,对象的状态可能
243、是不一样的,对象状态的改变往往是由于对象处理了一条消息(某个成员函变往往是由于对象处理了一条消息(某个成员函数被调用)。但是并不是每条消息都会导致对象数被调用)。但是并不是每条消息都会导致对象状态的变化。有些消息只是获取对象在某时刻的状态的变化。有些消息只是获取对象在某时刻的状态。状态。335计算机科学与技术学院张淼o在定义一个成员函数时,可以给它加上一个const说明,表示它是一个获取对象状态的成员函数。例如:classAvoidf()const;o在const成员函数体中不能修改数据成员的值。const成员函数成员函数336计算机科学与技术学院张淼classAintx;char*p;pub
244、lic:voidf()constx=10;/errorp=newchar20;/errorclassAintx;char*p;public:voidf()conststrcpy(p,”abcd”);*p=A;337计算机科学与技术学院张淼o只有常成员函数才有资格操作常对象。classAintx,y;public:voidf()constvoidg();constAa;a.f();/OKa.g();/error338计算机科学与技术学院张淼类成员是其它类的对象类成员是其它类的对象成员对象成员对象o一个类的成员可以是另外一个类的对象一个类的成员可以是另外一个类的对象参见工程0101aclassSt
245、udentprivate:char*name;intnumber;intscore;Teacherteacher;classTeacherprivate:char*name;339计算机科学与技术学院张淼成员对象的初始化o对于类中的数据成员,其类型可以是另一个类,也就是说一个对象可以包含另一个对象(称为成员对象)。classAintm;public:A()m=0;A(intm1)m=m1;classBintn;Aa;public:B()n=0;B(intn1)n=n1;Bb1,b2(1);340计算机科学与技术学院张淼在创建包含成员对象的对象时,在创建包含成员对象的对象时,对成员对象的初始化是
246、由成员对对成员对象的初始化是由成员对象类的构造函数来实现的。默认象类的构造函数来实现的。默认情况下,成员对象由成员对象类情况下,成员对象由成员对象类的的默认构造函数默认构造函数进行初始化。进行初始化。341计算机科学与技术学院张淼classAintm;public:A()m=0;A(intm1)m=m1;classBintn;Aa;public:B()n=0;B(intn1)n=n1;Bb1,b2(1);342计算机科学与技术学院张淼如需要调用成员对象的非默认构造函如需要调用成员对象的非默认构造函数对成员对象进行初始化,则要在包数对成员对象进行初始化,则要在包含成员对象的类的构造函数成员初始含
247、成员对象的类的构造函数成员初始化表指出。化表指出。343计算机科学与技术学院张淼classAintm;public:A()m=0;A(intm1)m=m1;classBintn;Aa;public:B()n=0;B(intn1):a(n1)n=n1;Bb1,b2(1);344计算机科学与技术学院张淼classAintm;public:A(intm1)m=m1;classBintn;Aa;public:B():a(0)n=0;B(intn1):a(n1)n=n1;Bb1,b2(1);345计算机科学与技术学院张淼同一个类的不同对象需要共享数据,怎么办?全局变量?静态成员346计算机科学与技术学院
248、张淼o静态数据成员静态数据成员的初始化必须在类的外部进行。数据类型类名:静态数据成员名=值;classAstaticintshared;/声明intx,y;public:A()x=y=0;voidincrease_all();intA:shared=0;/定义Aa1,a2;0shared:0000a1a2a1.xa1.ya2.xa2.y347计算机科学与技术学院张淼o静态数据成员具有静态生存期,不属于任何一个对象。o类的静态成员与该类的对象存在与否没有关系.348计算机科学与技术学院张淼o静态成员函数静态成员函数只能访问静态成员。349计算机科学与技术学院张淼classApublic:stat
249、icvoidf();private:intx;voidA:f()coutx;/error350计算机科学与技术学院张淼classApublic:staticvoidf(Aa);private:intx;voidA:f(Aa)coutx;/errorcouta.x;351计算机科学与技术学院张淼o静态成员函数没有隐藏的形式参数this.352计算机科学与技术学院张淼o静态成员的使用静态成员的使用除了在类中访问静态成员外,还可以在类的外除了在类中访问静态成员外,还可以在类的外部访问部访问public静态成员,这时有两种访问方式:静态成员,这时有两种访问方式:通过对象访问。通过对象访问。通过类名访问
250、。通过类名访问。类的静态成员与该类的对象存在与否没有关系。类的静态成员与该类的对象存在与否没有关系。353计算机科学与技术学院张淼友元(friend)o为什么需要友元n为了让类外的普通函数和其它类的成员函数能够对类中的保护和私有数据进行操作,C+提供了一种称为友元的信任机制o友元的分类n友元函数(普通函数)n友元成员(类的成员函数)n友元类o声明友元的关键字nfriend354计算机科学与技术学院张淼classAfriendvoidfunc();/友元函数友元函数friendclassB;/友元类友元类friendvoidC:f();/友元类成员函数友元类成员函数;355计算机科学与技术学院张
251、淼友元函数o在类里声明声明一个普通函数,在前面加上friend修饰,那么这个函数就成了该类的友元,可以访问该类的一切成员o一个普通函数可以是多个类的友元函数356计算机科学与技术学院张淼使用友元函数计算两点距离#include#includeclassPointpublic:/外部接口Point(intxx=0,intyy=0)X=xx;Y=yy;intGetX()returnX;intGetY()returnY;friendfloatDistance(Point&a,Point&b);private:/私有数据成员intX,Y;357计算机科学与技术学院张淼doubleDistance(Po
252、int&a,Point&b)doubledx=a.X-b.X;doubledy=a.Y-b.Y;returnsqrt(dx*dx+dy*dy);intmain()Pointp1(3.0,5.0),p2(4.0,6.0);doubled=Distance(p1,p2);coutThedistanceisdendl;return0;358计算机科学与技术学院张淼友元成员o一个类的成员函数也可以是另一个类的友元,从而可以使得一个类的成员函数可以操作另一个类的数据成员359计算机科学与技术学院张淼友元类o整个类也可以是另一个类的友元,该友元称为友元类o友元类的每个成员函数都可以访问另一个类的所有成员3
253、60计算机科学与技术学院张淼友元类举例class A friend class B; public: void Display() coutxendl; private: int x;class B public: void Set(int i); void Display(); private: A a;361计算机科学与技术学院张淼void B:Set(int i) a.x=i;void B:Display() a.Display();362计算机科学与技术学院张淼o友元不具有传递性,即假设B是A的友员,C是B的友员,如果没有显示指出的友员,如果没有显示指出C是是A的友员,的友员,则则C不
254、是不是A的友元。的友元。o一个类的友元可以访问该类的所有成员。363计算机科学与技术学院张淼继承和派生继承和派生364计算机科学与技术学院张淼类的继承与派生o保持已有类的特性而构造新类的过程称为继承。o在已有类的基础上新增自己的特性而产生新类的过程称为派生。o被继承的已有类称为基类(或父类)。o派生出的新类称为派生类。365计算机科学与技术学院张淼继承与派生问题举例366计算机科学与技术学院张淼继承与派生问题举例367计算机科学与技术学院张淼继承与派生问题举例368计算机科学与技术学院张淼继承与派生问题举例369计算机科学与技术学院张淼继承与派生的目的o继承的目的:实现代码重用。o派生的目的:
255、当新的问题出现,原有程序无法解决(或不能完全解决)时,需要对原有程序进行改造。370计算机科学与技术学院张淼ABCXYZ单继承多继承371计算机科学与技术学院张淼o单继承n派生类只从一个基类派生。o多继承n派生类从多个基类派生。o多重派生n由一个基类派生出多个不同的派生类。o多层派生n派生类又作为基类,继续派生新的类。372计算机科学与技术学院张淼单继承单继承o单继承的定义单继承的定义o继承方式继承方式n公有派生(公有派生(public)n私有派生(私有派生(private)n保护派生(保护派生(protected)class派生类名派生类名:继承方式继承方式基类名基类名派生类新定义成员派生类
256、新定义成员373计算机科学与技术学院张淼o派生类除了拥有基类所有的成员(基类的构造函数、析构函数和赋值操作符重载函数除外)外,也可以具有新的成员。374计算机科学与技术学院张淼classAintx,y;public:voidf();voidg();classB:publicAintz;public:voidh();Bb;b.f();b.g();b.h();b.xb.yb.zb375计算机科学与技术学院张淼o派生类中可以给出新的成员,也可以对基类的成员进行重定义。如果在派生类中对基类的某个成员进行了重定义,则在派生类中对该成员的访问是针对派生类中重定义的成员。376计算机科学与技术学院张淼cla
257、ssAintx,y;public:voidf();voidg();classB:publicAintz;public:voidf();voidh();Bb;b.f();/B类中的类中的fb.g();b.h();377计算机科学与技术学院张淼o派生类成员名的作用域嵌套在基类作用域中。对于基类的一个成员,如果派生类中没有定义与其同名的成员,则该成员名在派生类的作用域内可见。否则,该成员名在派生类的作用域内不可见,如果使用,必须用基类名受限。o即使派生类定义了与基类同名但参数不同的成员函数,基类的同名函数在派生类的作用域也是不可见的。378计算机科学与技术学院张淼classAintx,y;publi
258、c:voidf();voidg();classB:publicAintz;public:voidf();voidh()A:f();f();Bb;b.f();b.A:f();379计算机科学与技术学院张淼classAintx,y;public:voidf();voidg();classB:publicAintz;public:voidf(int);voidh()f(1);f();/errorA:f();Bb;b.f(1);b.f();/errorb.A:f();380计算机科学与技术学院张淼o定义派生类时一定要见到基类的定义,否则编译程序无法确定派生类对象需要占多大内存空间以及派生类中对基类成员
259、的访问是否合法。o派生类不能直接访问基类的私有成员,必须通过基类的非私有成员访问基类的私有成员。381计算机科学与技术学院张淼一个类可以创建对象,也可以用来定义派生类,一个类可以创建对象,也可以用来定义派生类,即一个类有两种用户:实例用户和派生类。即一个类有两种用户:实例用户和派生类。classA;classB:publicAvoidf()Aa;382计算机科学与技术学院张淼o在C+中通过引进protected成员访问控制,可以使派生类使用protected成员,但是protected成员不能被基类的实例用户使用。o这样,一个类就存在两个对外接口,一个接口由类的public成员构成,它提供给实
260、例用户使用;另一个接口由类的public和protected成员构成,该接口提供给派生类使用。383计算机科学与技术学院张淼在在C+中,派生类拥有基类的所有成员。中,派生类拥有基类的所有成员。那么基类的成员变成派生类的什么成员呢那么基类的成员变成派生类的什么成员呢?public,private还是还是protected?即即基类的成员对派生类的用户具有何种访问基类的成员对派生类的用户具有何种访问控制?这是由基类成员的访问控制和派生控制?这是由基类成员的访问控制和派生类的继承方式共同决定的。类的继承方式共同决定的。384计算机科学与技术学院张淼继承方式基类特性派生类特性公有继承publicpub
261、lic publicprotectedprotectedprivate不可访问私有继承privatepublic privateprotectedprivateprivate 不可访问保护继承protectedpublic protectedprotectedprotectedprivate 不可访问385计算机科学与技术学院张淼classApublic:voidf();protected:voidg();private:voidh();classB:protectedApublic:voidq();/q对A类成员的访问不受B的继承方式影响,除了h,其他都能访问。;classC:publicB
262、public:voidr()q();/okf();/okg();/okh();/error;Bb;b.q();/okb.f();/error,f是B的protected成员b.g();/error,g是B的protected成员b.h();/error,h是B的不可直接访问成员386计算机科学与技术学院张淼继承方式决定了派生类的实例(对象)用继承方式决定了派生类的实例(对象)用户和派生类对基类成员的访问限制。户和派生类对基类成员的访问限制。387计算机科学与技术学院张淼继承方式的调整o在任何继承方式中,除了基类的private成员,都可以在派生类中分别调整其访问控制。调整时采用:public:
263、|protected:|private:;388计算机科学与技术学院张淼classApublic:voidf1();voidf2();voidf3();protected:voidg1();voidg2();voidg3();classB:privateApublic:A:f1;A:g1;protected:A:f2;A:g2;private:A:f3;A:g3;Bb;b.f1();b.g1();/okb.f2();b.g2();b.f3();b.g3();/error389计算机科学与技术学院张淼o谁来初始化派生类对象?390计算机科学与技术学院张淼o派生类对象的初始化由基类和派生类共同完成
264、:基类的数据成员由基类的构造函数初始化,派生类的数据成员由派生类的构造函数初始化。o在创建派生类的对象时,派生类的构造函数在进入其函数体之前会调用基类的构造函数。默认情况下是调用基类的默认构造函数,如果要调用基类的非默认构造函数,则必须在派生类构造函数的成员初始化表中指出。参见工程0103391计算机科学与技术学院张淼classAintx;public:A()x=0;A(inti)x=i;classB:publicAinty;public:B()y=0;B(inti)y=i;B(inti,intj):A(i)y=j;Bb;/A:A(),B:B()Bb2(1);/A:A(),B:B(int)Bb
265、3(1,2);/A:A(int),B:B(int,int)派生类构造函数派生类构造函数(参数表参数表):基类构造函数基类构造函数(参数表参数表)392计算机科学与技术学院张淼o对于析构函数,先执行派生类的析构函数,而后执行基类的析构函数。o基类的构造函数和析构函数不能被派生类继承。393计算机科学与技术学院张淼o派生类构造函数和析构函数的执行顺序派生类构造函数和析构函数的执行顺序基类的构造函数基类的构造函数派生类的构造函数派生类的构造函数派生类的析构函数派生类的析构函数基类的析构函数基类的析构函数394计算机科学与技术学院张淼一般情况下,类定义及函数原型一般情况下,类定义及函数原型的声明放在头
266、文件(的声明放在头文件(.h)中,类)中,类中成员函数的实现则放在源文件中成员函数的实现则放在源文件(.cpp)中。)中。395计算机科学与技术学院张淼C+源程序结构o三个组成部分n类的定义及函数原型的声明n类中成员函数的实现n类的使用文件o存储和管理方式n类的定义及函数原型的声明(.h)o包括数据成员和成员函数的声明n类中成员函数的实现(.cpp)o成员函数的实现n类的使用文件o主函数参见工程0101396计算机科学与技术学院张淼o定义一个类时,在定义中加入条件编译指令防止重复包含。#ifndefstudent_H_H#definestudent_H_HclassStudentpublic:
267、voidinit(intnumber,intscore);voidshow();private:intnumber;intscore;#endif397计算机科学与技术学院张淼多继承多继承o什么是多继承什么是多继承nC+允许为一个派生类指定多个基类,这样的允许为一个派生类指定多个基类,这样的继承结构称为多继承继承结构称为多继承o多继承的声明多继承的声明class派生类名派生类名:继承方式继承方式1基类名基类名1,继承方式继承方式n基类名基类名n398计算机科学与技术学院张淼多重继承的构造函数和析构函数多重继承的构造函数和析构函数o构造函数的执行顺序构造函数的执行顺序n基类构造函数基类构造函数n
268、派生类构造函数派生类构造函数n在多个基类之间按照按照它们被继承时声明的在多个基类之间按照按照它们被继承时声明的顺序(从左向右)执行。顺序(从左向右)执行。o析构函数的执行顺序析构函数的执行顺序n析构函数的执行顺序与构造函数相反析构函数的执行顺序与构造函数相反399计算机科学与技术学院张淼classApublic:voidf();voidg();classBpublic:voidf();voidh();classc:publicA,publicBpublic:voidfunc()f();Cc;c.f();400计算机科学与技术学院张淼classApublic:voidf();voidg();cl
269、assBpublic:voidf();voidh();classc:publicA,publicBpublic:voidfunc()A:f();B:f();Cc;c.A:f();c.B:f();401计算机科学与技术学院张淼二义性问题举例classBpublic:intb;classB1:publicBprivate:intb1;classB2:publicBprivate:intb2;classC:publicB1,publicB2public:intf();private:intd;BB1B2C402计算机科学与技术学院张淼下面的访问是二义性的:Cc;c.bc.B:b下面是正确的:c.B1
270、:bc.B2:b403计算机科学与技术学院张淼派生类C的对象的存储结构示意图:bb1bb2dB类成员B类成员B1类成员B2类成员C类对象404计算机科学与技术学院张淼虚基类o虚基类的引入n用于有共同基类的场合o声明n以virtual修饰说明基类例:classB1:virtualpublicBo作用n主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题.n为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝o注意:n在第一级继承时就要将共同基类设计为虚基类。405计算机科学与技术学院张淼虚基类举例classBprivate:intb;classB1:virtualpublicBp
271、rivate:intb1;classB2:virtualpublicBprivate:intb2;classC:publicB1,publicB2private:floatd;下面的访问是正确的:Ccobj;cobj.b;406计算机科学与技术学院张淼虚基类的派生类对象存储结构示意图:BB1B2Cb1b2dB1类成员B2类成员C类对象bB类成员407计算机科学与技术学院张淼o虚基类的构造函数由最新派生出的类的构造函数调用。o虚基类的构造函数优先非虚基类的构造函数执行。408计算机科学与技术学院张淼o对于全局对象,程序一开始,其构造函数就先被函数执行。程序即将结束前其析构函数执行。(MFCapp
272、licationobject)o对于局部对象,当对象诞生时,其构造函数被函数执行。程序流程将离开该对象的存活范围(以致对象将毁灭)时,其析构函数执行。o对于静态对象,当对象诞生时其构造函数被函数执行。当程序将结束时(此对象因而遭致毁灭)其析构函数被执行,但比全局对象的析构函数早一步执行。o对于以new方式产生出来的局部对象,当对象诞生时其构造函数被函数执行。析构函数则在对象被delete时执行。409计算机科学与技术学院张淼o在C+中,有四种方法可以产生一个对象:n堆栈(stack)中n在堆(heap)中n产生一个全局对象n产生一个局部静态对象410计算机科学与技术学院张淼CH2.3C+面向对
273、象程序设计进阶面向对象程序设计进阶q多态和虚函数多态和虚函数q运算符重载运算符重载q输入输出流输入输出流q模板模板411计算机科学与技术学院张淼CH2.3.1多态和虚函数o赋值兼容规则:需要基类对象的任何地方都可以使用公有派生类的对象来替代.替代包括:n派生类的对象可以赋值给基类对象.n派生类的对象可以初始化基类的引用.n派生类的地址可以赋给指向基类的指针.412计算机科学与技术学院张淼student对象内存布局对象内存布局person对象内存student继承部分this指针student对象的内存图 student对象内存布局413计算机科学与技术学院张淼o联编:将一个函数的调用与相应的函
274、数体的代码相连接称为函数联编。o静态联编:在编译根据CShape*pShape6的静态类型类决定pShapei-display()属于哪一个类。由于pShapei的静态类型是CShape*,所以确定display()是CShape:shout.o动态联编:在运行时,根据pShapei实际指向的对象类型来确定display()属于哪一个类。C+规定动态联编是在虚函数的支持下实现的。414计算机科学与技术学院张淼虚函数o虚函数是成员函数而且是非static的成员函数。说明虚函数的方法如下:virtual类型说明函数说明(参数表)o一旦在基类中指定某成员为虚函数,那么不管在派生类中是否给出virtu
275、al声明,派生类(以及派生类的派生类,依次类推)中对其重定义的成员函数均为虚函数。o重定义指对派生类中定义的成员函数,其函数名、重定义指对派生类中定义的成员函数,其函数名、参数个数和类型以及返回值类型与基类的虚成员函参数个数和类型以及返回值类型与基类的虚成员函数相同。数相同。(当基类虚函数返回值类型是某个类或其指针或引用时,派生类中重定义的成员函数的返回值也可以是子类型,vc+不支持)。415计算机科学与技术学院张淼o使用虚函数的注意事项使用虚函数的注意事项n只有类的成员函数才能说明为虚函数只有类的成员函数才能说明为虚函数n静态成员函数不能是虚函数静态成员函数不能是虚函数n内联内联(inlin
276、e)函数不能是虚函数函数不能是虚函数n构造函数不能是虚函数构造函数不能是虚函数n析构函数可以是虚函数析构函数可以是虚函数,而且通常声名为虚函数而且通常声名为虚函数参见工程0106416计算机科学与技术学院张淼多态性多态性o什么是多态性什么是多态性n不同对象收到相同消息时产生不同的动作不同对象收到相同消息时产生不同的动作n多态性的实现与函数联编有关多态性的实现与函数联编有关o将一个函数的调用与相应的函数体的代码相连接称将一个函数的调用与相应的函数体的代码相连接称为函数联编为函数联编o编译时的多态性编译时的多态性n静态联编所支持的多态性称为编译时的多态性静态联编所支持的多态性称为编译时的多态性n通
277、过函数重载或运算符重载实现通过函数重载或运算符重载实现o运行时的多态性运行时的多态性n动态联编所支持的多态性称为运行时的多态性动态联编所支持的多态性称为运行时的多态性n通过虚函数的继承实现通过虚函数的继承实现417计算机科学与技术学院张淼运行时的多态性需要满足三个条件:运行时的多态性需要满足三个条件:首先,类之间应该满足赋值兼容规则。首先,类之间应该满足赋值兼容规则。其二,要声明虚函数。其二,要声明虚函数。第三,要由成员函数来调用或者通过指针、第三,要由成员函数来调用或者通过指针、引用来访问虚函数。引用来访问虚函数。如果使用对象名来访问虚函数,则联编在编如果使用对象名来访问虚函数,则联编在编译
278、过程中就可以进行,而无需在运行过程中译过程中就可以进行,而无需在运行过程中进行。进行。418计算机科学与技术学院张淼classApublic:A()f();A()virtualvoidf();voidg();voidh()f();g();classB:publicApublic:B()voidf();voidg();Aa;/A:A()和A:fa.f();/A:fa.g();/A:ga.h();/A:h,A:f,A:gBb;/B:B(),A:A()和A:fb.f();/B:fb.g();/B:gb.h();/A:h,B:f,A:g419计算机科学与技术学院张淼classApublic:A()f(
279、);A()virtualvoidf();voidg();voidh()f();g();classB:publicApublic:B()voidf();voidg();A*p;p=&a;p-f();/A:fp-g();/A:gp-h();/A:h,A:f,A:gp=&b;p-f();/B:fp-A:f();/A:fp-g();/A:gp-h();/A:h,B:f,A:gp=newB;/B:B(),A:A()和A:fdeletep;/A:A()420计算机科学与技术学院张淼基类构造函数中对虚函数的调用不采用动态基类构造函数中对虚函数的调用不采用动态绑定。绑定。421计算机科学与技术学院张淼纯虚函数
280、和抽象类o什么是纯虚函数n纯虚函数只有函数的声明,函数的定义必须在其派生类中完成n声明纯虚函数的类不能实例化o什么是抽象类n声明有纯虚函数的类称为抽象类o纯虚函数的声明virtual返回值类型返回值类型函数名函数名()=0;参见工程0108422计算机科学与技术学院张淼o抽象类的主要作用是通过它为一个类族建立一个公共的接口,使他们能够更有效的发挥多态特性。o抽象类派生出新类后,如果派生类没有给出全部纯虚函数的实现,这时的派生类仍然是一个抽象类。o抽象类不能实例化,但可以声明一个抽象类的指针和引用。通过指针或引用,我们就可以指向并访问派生类对象,进而访问派生类的成员,这种访问是具有多态特征的。4
281、23计算机科学与技术学院张淼classB0public:virtualvoiddisplay()=0;classB1:publicB0public:voiddisplay()cout“B1:display”;classD1:publicB1public:voiddisplay()coutdisplay();voidmain()B0*p;B1b1;D1d1;p=&b1;fun(p);/B1:displayp=&d1;fun(p);/D1:display424计算机科学与技术学院张淼关于纯虚函数和抽象类的描述中,()是错误的。A.纯虚函数是一种特殊的虚函数,它没有具体的实现。B.抽象类是指具有纯虚
282、函数的类。C.一个基类中说明有纯虚函数,该基类的派生类一定不再是抽象类。D.抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。425计算机科学与技术学院张淼o下列各类函数中,()不是类的成员函数。A.构造函数B.析构函数C.拷贝初始化构造函数D.友元函数426计算机科学与技术学院张淼CH2.3.2运算符重载o例:实现复数的表示及其加法操作。nC+语言没有提供复数类型。为了使程序中能够表示和处理复数,我们用一个复数类来实现它。n为了能实现复数加法操作,可以在复数类的定义中定义一个成员函数add,它把调用它的复数对象和参数指定的复数对象相加,返回相加之后得到的复数对象。427计算机科学与技术
283、学院张淼classComplexdoublereal,imag;public:Complex()real=0;imag=0;Complex(doubler,doublei)real=r;imag=i;Complexadd(constComplex&x)constComplextemp;temp.real=real+x.real;temp.imag=imag+x.imag;returntemp;Complexa(1,2),b(3,4),c;c=a.add(b);Complexa(1,2),b(3,4),c;c=a+b;428计算机科学与技术学院张淼classComplexdoublereal,i
284、mag;public:Complex()real=0;imag=0;Complex(doubler,doublei)real=r;imag=i;Complexoperator+(constComplex&x)constComplextemp;temp.real=real+x.real;temp.imag=imag+x.imag;returntemp;429计算机科学与技术学院张淼classComplexdoublereal,imag;public:;Complexoperator+(constComplex&c1,constComplex&c2)Complextemp;temp.real=c1
285、.real+c2.real;temp.imag=c1.imag+c2.imag;returntemp;friendComplexoperator+(constComplex&c1,constComplex&c2)430计算机科学与技术学院张淼运算符重载是对已有的运算符赋予多重含义。它运算符重载是对已有的运算符赋予多重含义。它运算符重载是对已有的运算符赋予多重含义。它运算符重载是对已有的运算符赋予多重含义。它的主要优点之一就是用户自定义的数据类型可使的主要优点之一就是用户自定义的数据类型可使的主要优点之一就是用户自定义的数据类型可使的主要优点之一就是用户自定义的数据类型可使用编译系统预定义的运算
286、符。用编译系统预定义的运算符。用编译系统预定义的运算符。用编译系统预定义的运算符。431计算机科学与技术学院张淼两种形式o重载为类成员函数。o重载为友元函数。432计算机科学与技术学院张淼o定义形式函数类型operator运算符(形参).o重载为类成员函数时参数个数=原操作数个数-1 (后置+、-除外)o重载为友元函数时参数个数=原操作数个数,且至少应该有一个自定义类型的形参。433计算机科学与技术学院张淼作为成员函数重载o双目操作符重载函数的声明格式classoperator#();o双目操作符重载函数的定义格式:operator#()434计算机科学与技术学院张淼o双目操作符重载函数的使用
287、格式a;b;a#b;或a.operator#(b);435计算机科学与技术学院张淼o单目操作符重载函数的声明格式classoperator#();o单目操作符重载函数的定义格式:operator#()436计算机科学与技术学院张淼o单目操作符重载函数的使用格式a;#a;或a.operator#();o对于单目操作符,其重载函数是单目操作符的前置用法。而操作符+和有前置和后置两种用法。为了能够区分,则可以定义另一个带有int型参数的操作符+和的重载函数来表示它们的后置用法。437计算机科学与技术学院张淼classCounterintvalue;public:Counter()value=0;Co
288、unter&operator+()/前置value+;return*this;constCounteroperator+(int)/后置Countertemp=*this;+(*this);returntemp;438计算机科学与技术学院张淼作为全局(友元)函数重载o双目操作符重载函数的声明格式operator#(,)o使用格式a;b;a#b或operator#(a,b)439计算机科学与技术学院张淼o单目操作符重载函数的声明格式operator#()o单目操作符重载函数的使用格式a;#a;或operator#(a);440计算机科学与技术学院张淼o为了能够区分前置和后置+和的重载函数,它们的
289、后置用法:operator+(,int);441计算机科学与技术学院张淼规则和限制o可以重载C+中除下列运算符外的所有运算符:.*:?:sizeof()o只能重载C+语言中已有的运算符,不可臆造新的。o不改变原运算符的优先级和结合性。o不能改变操作数个数。o经重载的运算符,其操作数中至少应该有一个是自定义类型。o在重载运算符()、-或者=时,运算符重载函数必须声明为类的一个成员。对于其他的运算符,运算符重载函数可以是成员函数或者友元函数.o但在某些情况下,操作符必须以全局函数来重载,才能满足使用上的要求。442计算机科学与技术学院张淼o重载操作符+,使其能够实现实数与复数的混合运算。443计算
290、机科学与技术学院张淼classComplexdoublereal,imag;public:Complex()real=0;imag=0;Complex(doubler,doublei)real=r;imag=i;friendComplexoperator+(constComplex&c1,constComplex&c2)friendComplexoperator+(constComplex&c,doubled)friendComplexoperator+(doubled,constComplex&c)444计算机科学与技术学院张淼Complexa(1,2),b(3,4),c1,c2,c3;c1
291、=a+b;c2=b+21.5c3=10.2+a;445计算机科学与技术学院张淼o如果在类对象a的类中重载运算符“+”,则a+3的显示调用()。A.a.operator(3);B.a-operator+(3);C.a.operator+(3);D.3.operator+(a);446计算机科学与技术学院张淼赋值运算符的重载两个同类对象之间可以赋值,其含义是用一个对两个同类对象之间可以赋值,其含义是用一个对象的状态来改变另一个对象的状态。象的状态来改变另一个对象的状态。C+编译编译程序会为每个类定义一个隐式的赋值操作符重载程序会为每个类定义一个隐式的赋值操作符重载函数,其行为是逐个对成员进行赋值操
292、作。函数,其行为是逐个对成员进行赋值操作。对象的成员中有数组或动态的数据类型时,就不对象的成员中有数组或动态的数据类型时,就不能直接相互赋值,否则在程序的编译或执行过程能直接相互赋值,否则在程序的编译或执行过程中出现编译或运行错误。例如:中出现编译或运行错误。例如:447计算机科学与技术学院张淼class class CdemoCdemo public:public:CDemo(charCDemo(char *s) *s) psps = new = new charstrlen(scharstrlen(s) + 1;) + 1;strcpy(psstrcpy(ps, s);, s); CDem
293、oCDemo()() if (if (psps) )delete delete psps; ; void print()void print() coutpsendl;coutpsendl; private:private: char * char *psps; ;void main()void main() CDemoCDemo d1(Key), d2(Mouse); d1(Key), d2(Mouse);d1 = d2;d1 = d2; 448计算机科学与技术学院张淼o除了会产生与默认拷贝构造函数可能产生的类似问题以外,还会导致内存泄露。449计算机科学与技术学院张淼#include #i
294、nclude #include #include class class CDemoCDemopublic:public:/ / 同上面的斜体部分代码同上面的斜体部分代码CDemoCDemo& & operator = (const operator = (const CDemoCDemo &a) &a)/ / 赋值运算符重载赋值运算符重载 if (if (psps) delete ) delete psps; ;if (if (a.ps)psa.ps)ps = new = new charstrlen(a.pscharstrlen(a.ps) + 1;) + 1;strcpy(psstrcp
295、y(ps, , a.psa.ps););else else psps = 0; = 0;return *this;return *this; private: private: char * char *psps; ;void main()void main() CDemoCDemo d1(Key), d2(Mouse); d1(Key), d2(Mouse);d1 = d2;d1 = d2;d1.print(); 运行结果为:运行结果为:Mouse 450计算机科学与技术学院张淼如果一个函数的返回值是一个对象的值,它就被认为是一个常量,是不能如果一个函数的返回值是一个对象的值,它就被认为是一
296、个常量,是不能如果一个函数的返回值是一个对象的值,它就被认为是一个常量,是不能如果一个函数的返回值是一个对象的值,它就被认为是一个常量,是不能出现在等号左边作为左值的(也就是说不能被改变)。出现在等号左边作为左值的(也就是说不能被改变)。出现在等号左边作为左值的(也就是说不能被改变)。出现在等号左边作为左值的(也就是说不能被改变)。C+C+语言中要求赋值表达式是语言中要求赋值表达式是语言中要求赋值表达式是语言中要求赋值表达式是可以作为左值的可以作为左值的可以作为左值的可以作为左值的。由于引用的实质就是对象。由于引用的实质就是对象。由于引用的实质就是对象。由于引用的实质就是对象的地址,所以通过引
297、用当然可以改变对象的值。的地址,所以通过引用当然可以改变对象的值。的地址,所以通过引用当然可以改变对象的值。的地址,所以通过引用当然可以改变对象的值。451计算机科学与技术学院张淼注意:o拷贝构造函数和赋值操作符=重载函数区别:n创建一个对象时,用另一个已存在的同类对象对其初始化,调用拷贝构造函数。n对两个已存在的对象,通过赋值操作用其中一个对象来改变另一个对象的状态时,调用赋值操作符=重载函数。n例如:Aa;Ab=a;b=a;调用拷贝构造函数,等价于调用拷贝构造函数,等价于Ab(a);调用赋值操作符重载函数调用赋值操作符重载函数452计算机科学与技术学院张淼赋值运算符不能重载为友元函数,只能
298、是赋值运算符不能重载为友元函数,只能是一个非静态成员函数。一个非静态成员函数。 并且它不能被派生并且它不能被派生类继承。类继承。453计算机科学与技术学院张淼CH2.3.3输入输入/输出流类库输出流类库输入输入/输出(简称输出(简称I/O)是程序的一个重要)是程序的一个重要组成部分,程序运行所需要的数据往往要从外组成部分,程序运行所需要的数据往往要从外设(如键盘、文件等)得到,程序的运行结果设(如键盘、文件等)得到,程序的运行结果通常也要输出到外设(如显示器、打印机、文通常也要输出到外设(如显示器、打印机、文件等)中去。件等)中去。在在C+中,输入中,输入/输出不是语言所定义的成输出不是语言所
299、定义的成分,而是由具体的实现(编译程序)作为标准分,而是由具体的实现(编译程序)作为标准库的功能来实现的。库的功能来实现的。454计算机科学与技术学院张淼在在C+中,输入中,输入/输出操作是一种基于流的操作。输出操作是一种基于流的操作。在进行输入操作时,可把输入的数据看成逐个字在进行输入操作时,可把输入的数据看成逐个字节从外设流入到计算机内部(内存);在进行输节从外设流入到计算机内部(内存);在进行输出操作时,则把输出的数据看成逐个字节从内存出操作时,则把输出的数据看成逐个字节从内存流入到外设。流入到外设。C+标准库中,除了提供基于字节的输入标准库中,除了提供基于字节的输入/输出输出操作外,为
300、了方便使用,还提供了基于操作外,为了方便使用,还提供了基于C+基基本数据类型数据的输入本数据类型数据的输入/输出操作。输出操作。455计算机科学与技术学院张淼由于由于C+支持过程式和面向对象两种程序设计范型,支持过程式和面向对象两种程序设计范型,因此,在因此,在C+中,输入中,输入/输出操作也可以以这两种方输出操作也可以以这两种方式来进行,式来进行,C+标准库也以两种方式提供了输入标准库也以两种方式提供了输入/输输出功能。出功能。在在C+中,以过程式的方式进行输入中,以过程式的方式进行输入/输出是通过从输出是通过从C语言保留下来的函数库中的输入语言保留下来的函数库中的输入/输出函数来实现输出函
301、数来实现的,用这些函数可以实现对基本类型数据的的,用这些函数可以实现对基本类型数据的I/O操操作。作。以面向对象方式进行输入以面向对象方式进行输入/输出则是通过输出则是通过C+的的I/O类库来实现的。类库来实现的。I/O类库提供的输入类库提供的输入/输出操作输出操作是由一些是由一些I/O类来实现的。类来实现的。456计算机科学与技术学院张淼iosistreamostreamifstreamistrstreamofstreamostrstreamiostreamfstreamstrstream457计算机科学与技术学院张淼istream,ostreamiostream.hiftream,oftr
302、eam,fstreamfstream.h458计算机科学与技术学院张淼istream类重载了类重载了(提取)(提取),用它可以进行用它可以进行基本类型数据的输入操作。基本类型数据的输入操作。ostream类重载了类重载了,进行重载,使得通过进行重载,使得通过I/O类的对象可以对用户自定义的数据(如对象等)类的对象可以对用户自定义的数据(如对象等)进行输入进行输入/输出操作。输出操作。459计算机科学与技术学院张淼控制台I/O控制台控制台I/O指从计算机系统的标准输入设备输入程指从计算机系统的标准输入设备输入程序所需要的数据以及把程序的计算结果输出到计算序所需要的数据以及把程序的计算结果输出到计
303、算机系统的标准输出设备。机系统的标准输出设备。460计算机科学与技术学院张淼预定义的控制台对象预定义的控制台对象在在I/O类库中预定义了四个类库中预定义了四个I/O对象:对象:cin,cout,cerr,clog,利用这些对象可以直接进,利用这些对象可以直接进行控制台的输入行控制台的输入/输出。其中输出。其中cin属于属于istream类的类的对象,它对应计算机的标准输入设备,用来处理标对象,它对应计算机的标准输入设备,用来处理标准输入,即键盘输入;准输入,即键盘输入;cout,cerr以及以及clog属于属于ostream类的对象,类的对象,cout对应计算机的用于输出对应计算机的用于输出程
304、序正常运行结果的标准输出设备,而程序正常运行结果的标准输出设备,而cerr和和clog则对应计算机的用于输出程序错误信息的设备,则对应计算机的用于输出程序错误信息的设备,用来处理标准出错信息,通常它们都对应显示器。用来处理标准出错信息,通常它们都对应显示器。cerr不对输出信息进行缓冲。不对输出信息进行缓冲。461计算机科学与技术学院张淼屏幕输出屏幕输出使用预定义的插入符使用预定义的插入符使用成员函数使用成员函数ostream&ostream:put(charch):输出一个字符ostream&ostream:write(constchar*p,intcount):输出p所指向内存空间中cou
305、nt个字节。cout.put(m);charc=a;cout.put(c);cout.write(“hello”,strlen(“hello”);462计算机科学与技术学院张淼键盘输入键盘输入使用预定义的提取符使用预定义的提取符在输入时,各个数据之间用空白符分开,一般常用空格在输入时,各个数据之间用空白符分开,一般常用空格符、也可用符、也可用tab键(水平制表符)或换行符。因此,从键(水平制表符)或换行符。因此,从键盘输入字符时,空白符只用于输入字符的分隔符,而键盘输入字符时,空白符只用于输入字符的分隔符,而本身不作为从输入流中提取的字符。本身不作为从输入流中提取的字符。提取符可以从输入流中读
306、取一个字符序列,即一个字符提取符可以从输入流中读取一个字符序列,即一个字符串。在处理这种字符序列时,字符串被认为是一个以空串。在处理这种字符序列时,字符串被认为是一个以空白符结束的字符序列。在从输入流中,每读入一个字符白符结束的字符序列。在从输入流中,每读入一个字符串,系统自动加上串,系统自动加上0字符。字符。463计算机科学与技术学院张淼使用成员函数使用成员函数istream:get(char&ch):输入一个字符该函数不忽略空白字符,即将输入流的空白字符也作为一个该函数不忽略空白字符,即将输入流的空白字符也作为一个字符。字符。istream:getline(char*p,intcount,
307、chardelim=n):输入一个字符串直到输入count-1个字符或遇到delim指定的字符为止,并自动加上一个0.istream:read(char*p,intcount):读入count个字符至p所指向的内存空间。464计算机科学与技术学院张淼的重载的重载为了能用为了能用和和对自定义类的对象进行输入输出操对自定义类的对象进行输入输出操作,就需要对自定义的类重载作,就需要对自定义的类重载。classAintx,y;public:friendostream&operator(ostream&out,constA&a)465计算机科学与技术学院张淼ostream&operator(ostrea
308、m&out,constA&a)outa.x,a.y;returnout;Aa,b;coutabendl;466计算机科学与技术学院张淼文件I/O467计算机科学与技术学院张淼程序运行结果有时需要永久保存起来,程序运行结果有时需要永久保存起来,以供其它程序或本程序下一次运行时使以供其它程序或本程序下一次运行时使用。程序运行所需要的数据也常常要从用。程序运行所需要的数据也常常要从其他程序或本程序上一次运行所保存的其他程序或本程序上一次运行所保存的数据中获得。用于永久性保存数据的设数据中获得。用于永久性保存数据的设备称为外部存储器,如磁盘、光盘等。备称为外部存储器,如磁盘、光盘等。在外部存储器中保存
309、数据的方式通常有在外部存储器中保存数据的方式通常有两种:文件和数据库。两种:文件和数据库。468计算机科学与技术学院张淼文件是在计算机内存中以二进制表示的数据在外文件是在计算机内存中以二进制表示的数据在外部存储介质上的另一种存放形式。部存储介质上的另一种存放形式。在在C+C+中,把文件看成是由一系列中,把文件看成是由一系列字节字节字节字节所构成的所构成的字节串,称为字节串,称为流式文件流式文件流式文件流式文件。对文件中数据的操作(输入、。对文件中数据的操作(输入、输出)通常是逐个字节顺序进行。输出)通常是逐个字节顺序进行。469计算机科学与技术学院张淼在对文件数据进行读写前,首先要打开文件。打
310、在对文件数据进行读写前,首先要打开文件。打开文件的目的是:在程序内部的一个表示文件的开文件的目的是:在程序内部的一个表示文件的变量与外部的一个具体文件之间建立联系。变量与外部的一个具体文件之间建立联系。470计算机科学与技术学院张淼b1b2 b3b2b4位置指针位置指针 每个被打开的文件都有一个内部的位置指针,每个被打开的文件都有一个内部的位置指针,他指出文件的当前读写位置。他指出文件的当前读写位置。进行读进行读/ /写操作时,每读写操作时,每读/ /写一个字节,文件指写一个字节,文件指针就会自动往后移动一个字节的位置。针就会自动往后移动一个字节的位置。471计算机科学与技术学院张淼fstre
311、amiofile(文件名,打开方式);ofstreamoutfile;outfile.open(文件名,打开方式);fstreamiofile;iofile.open(文件名,打开方式);ifstreaminfile;infile.open(文件名,打开方式);ofstreamoutfile(文件名,打开方式);ifstreaminfile(文件名,打开方式);472计算机科学与技术学院张淼在以在以ios:out方式打开文件,而未指定方式打开文件,而未指定ios:in,ios:ate,ios:app方式时,则方式时,则隐含隐含ios:trunc方式。方式。473计算机科学与技术学院张淼由于种种
312、原因,打开文件操作可能失败。因此,打开文件时应判断打开是否成功,只有文件打开成功后才能对文件进行操作。判断文件打开是否成功可采用以下方式:if(!outfile)或(outfile.fail()或!outfile.is_open()474计算机科学与技术学院张淼文件打开成功后可以使用插入符文件打开成功后可以使用插入符和成员函数和成员函数get,geline,readget,geline,read来进行文件读操作。来进行文件读操作。475计算机科学与技术学院张淼为了能够随机读写文件中的数据,必须要显示地为了能够随机读写文件中的数据,必须要显示地指出读写的位置。指出读写的位置。对于以输入方式打开的
313、文件,可用下面的操作来对于以输入方式打开的文件,可用下面的操作来指定文件内部指针位置。指定文件内部指针位置。 seekgseekg( (位置位置) );/ /指定绝对位置指定绝对位置 seekgseekg( (偏移量,参照位置偏移量,参照位置) ); / /指定绝对位置指定绝对位置 tellgtellg()/()/获取指针位置。获取指针位置。 476计算机科学与技术学院张淼对于以输出方式打开的文件,可用下面的操作对于以输出方式打开的文件,可用下面的操作来指定文件内部指针位置。来指定文件内部指针位置。 seekpseekp( (位置位置) );/ /指定绝对位置指定绝对位置seekpseekp(
314、 (偏移量,参照位置偏移量,参照位置) ); / /指定绝对位置指定绝对位置tellptellp()/()/获取指针位置。获取指针位置。 477计算机科学与技术学院张淼其中位置和偏移量都是其中位置和偏移量都是longlong型量,并以字节数为型量,并以字节数为单位。单位。参照位置可以是参照位置可以是ios:begios:beg(文件头)、(文件头)、ios:curios:cur(当前位置)(当前位置) 、ios:endios:end(文件尾)(文件尾) 478计算机科学与技术学院张淼文件读写完毕后,通常要关闭文件,其目的是把文件读写完毕后,通常要关闭文件,其目的是把暂存在内存缓冲区中的内容写入
315、到文件中,并归暂存在内存缓冲区中的内容写入到文件中,并归还打开文件时申请的内存资源。还打开文件时申请的内存资源。479计算机科学与技术学院张淼文本文件和二进制文件文本文件和二进制文件o文件就是一片内存中的数据在硬盘上的另一种存放形式,也就是二进制数据,即每个文件都是二进制的。o如果一个文件中的每个字节的内容都可以表示成字符的数据,我们就称这个文件为文本文件。o除了文本文件之外的文件称为二进制文件。480计算机科学与技术学院张淼n n文件通常分为二进制文件和文本文件。文件通常分为二进制文件和文本文件。n n二进制文件是包含在二进制文件是包含在 ASCIIASCII及扩展及扩展 ASCIIASCI
316、I字符中编字符中编写的数据或程序指令的文件。一般是可执行程序、图写的数据或程序指令的文件。一般是可执行程序、图形、图象、声音等等文件。形、图象、声音等等文件。n n文本文件文本文件( (也称为也称为ASCIIASCII文件文件) ):它的每一个字节存放:它的每一个字节存放的是可表示为一个字符的的是可表示为一个字符的ASCIIASCII代码的文件。它是以代码的文件。它是以 “ “行行” ”为基本结构的一种信息组织和存储方式的文件,为基本结构的一种信息组织和存储方式的文件,可用任何文字处理程序阅读的简单文本文件。可用任何文字处理程序阅读的简单文本文件。 文本文件和二进制文件文本文件和二进制文件48
317、1计算机科学与技术学院张淼o当我们按照文本方式往文件中写入数据时,一当我们按照文本方式往文件中写入数据时,一旦遇到换行字符旦遇到换行字符(ASCII为为10),则会转换为回,则会转换为回车换行车换行(ASCII为为13、10)。在读取文件时,。在读取文件时,一旦遇到回车换行的组合一旦遇到回车换行的组合(即连续的即连续的ASCII13、10),则会转换为换行字符,则会转换为换行字符(ASCII为为10)。o当我们按照二进制方式往文件中写入数据,则当我们按照二进制方式往文件中写入数据,则将数据在内存中的存储形式原样输出到文件中。将数据在内存中的存储形式原样输出到文件中。482计算机科学与技术学院张
318、淼o无性繁殖并不只是存在于遗传工程上,对程序员而言它也是一个由来已久的操作。过去,我们只不过是以一个简单而基本的工具,也就是文字编辑器,重制我们的代码。今天C+提供给我们一个更好的繁殖方法:templateo在程序设计中经常需要用到这样的一些程序实体:这些程序实体所完成的功能完全相同,但它们所操作的数据类型不同。CH2.3.4类属(泛型)机制类属(泛型)机制模板模板483计算机科学与技术学院张淼ovoidint_sort(intx,intnum)ovoiddouble_sort(doublex,intnum)ovoidA_sort(Ax,intnum)484计算机科学与技术学院张淼classI
319、ntStackintbuf100;public:boolpush(int);boolpop(int&);classDoubleStackdoublebuf100;public:boolpush(double);boolpop(double&);classAStackAbuf100;public:boolpush(A);boolpop(A&);485计算机科学与技术学院张淼oTemplate提供了比较好的解决方案。它把“一般性的算法”和其“对数据类型的实现部分”区分开来。你可以先写算法的程序代码,稍后在使用时再填入实际数据类型。o新的C+语法使“数据类型”也以参数的姿态出现。o有了templat
320、e,你就可以拥有宏“只写一次”的优点,以及重载函数“类型检查”的优点。486计算机科学与技术学院张淼o模板的含义n以所处理的数据类型的说明作为参数的函数和类,分别称为函数模板和类模板n一个模板并非一个实实在在的类或函数,仅仅是一个类或函数的描述o模板的作用n模板可以实现逻辑相同,数据类型不同的程序代码的复制n模板机制可以减轻编程和维护的工作量和难度487计算机科学与技术学院张淼模板函数和模板类o模板函数n定义函数模板之后可以用类型实参调用该函数o编译器将根据调用该函数实参数据类型,生成相应的重载函数,该重载函数称为模板函数,是一个实实在在的函数o模板类n建立类模板之后,可以用类型实参定义模板类
321、并创建实例对象o模板类是一个实实在在的类,对象是该模板类的实例488计算机科学与技术学院张淼o函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计。函数模板489计算机科学与技术学院张淼函数模板通用函数o求两个数最大值的函数模板intmax(inta,intb)returnab?a:b;floatmax(floata,floatb)returnab?a:b;charmax(chara,charb)returnab?a:b;templateTmax(Ta,Tb)returnab?a:b;490计算机科学与技术学院张淼函数模板的定义和使用o函数模板的定义o函数
322、模版的使用template函数定义函数定义函数名函数名(参数列表参数列表)491计算机科学与技术学院张淼例求绝对值函数的模板#includetemplateT abs(T x) return x0?-x:x; void main() int n=-5; double d=-5.5; coutabs(n)endl; coutabs(d)endl;492计算机科学与技术学院张淼o运行结果:55.5o分析n编译器从调用abs()时实参的类型,推导出函数模板的类型参数。例如,对于调用表达式abs(n),由于实参n为int型,所以推导出模板中类型参数T为int。n当类型参数的含义确定后,编译器将以函数模
323、板为样板,生成一个函数:int abs(int x) return x0?-x:x; 493计算机科学与技术学院张淼o有时编译程序无法根据调用时的实参类型确定所调用的模板函数,这时需要在程序中显示地实例化函数模板。如abs(n);494计算机科学与技术学院张淼o除了类型参数,模板也可带有非类型参数。如:templatevoidf(Ta)Ttempsize;voidmain()f(1);495计算机科学与技术学院张淼类模板通用数据类型o什么是类模版n类模板是用户为类定义的一种模式,使类中的某些数据成员的类型、成员函数的参数或返回值能够使用任意的数据类型n相当于自定义的通用数据类型o类模版的定义t
324、emplate类定义类定义496计算机科学与技术学院张淼例类模板应用举例#include#include/结构体StudentstructStudentintid;/学号floatgpa;/平均分;497计算机科学与技术学院张淼template/类模板:实现对任意类型数据进行存取类模板:实现对任意类型数据进行存取classStoreprivate:Titem;/用于存放任意类型的数据用于存放任意类型的数据inthaveValue;/用于标记用于标记item是否已被存入内是否已被存入内容容public:Store(void);/缺省形式(无形参)的构造函数缺省形式(无形参)的构造函数TGetEl
325、em(void);/提取数据函数提取数据函数voidPutElem(Tx);/存入数据函数存入数据函数;/缺省形式构造函数的实现缺省形式构造函数的实现templateStore:Store(void):haveValue(0)498计算机科学与技术学院张淼template/提取数据函数的实现提取数据函数的实现TStore:GetElem(void)/如果试图提取未初始化的数据,则终止程序如果试图提取未初始化的数据,则终止程序if(haveValue=0)coutNoitempresent!endl;exit(1);returnitem;/返回返回item中存放的数据中存放的数据template
326、/存入数据函数的实现存入数据函数的实现voidStore:PutElem(Tx)haveValue+;/将将haveValue置为置为TRUE,表示表示item中已存入数值中已存入数值item=x;/将将x值存入值存入item499计算机科学与技术学院张淼voidmain(void)Studentg=1000,23;StoreS1,S2;StoreS3;StoreD;S1.PutElem(3);S2.PutElem(-7);coutS1.GetElem()S2.GetElem()endl;S3.PutElem(g);coutThestudentidisS3.GetElem().idendl;c
327、outRetrievingobjectD;coutD.GetElem()endl;/输出对象D的数据成员/由于D未经初始化,在执行函数D.GetElement()时出错500计算机科学与技术学院张淼/file1.cpp#include“file2.h”intmain()Ss1;s1.f();/okSs2;s2.f();/error,连接程序将指出连接程序将指出“voidS:f()”不存在不存在sub();return0;/file2.htemplateclassS/类模版S的定义Ta;public:voidf();externvoidsub();501计算机科学与技术学院张淼/file2.cp
328、p#include“file2.h”templatevoidS:f()/类模版S的实现Voidsub()sx;/实例化“s”并创建该类的一个对象x。x.f();/ok502计算机科学与技术学院张淼/file2.htemplateclassS/类模版S的定义Ta;public:voidf();templatevoidS:f()/类模版S的实现externvoidsub();503计算机科学与技术学院张淼o如果两个源文件都用同一个模板的相同实例,则两个源文件的编译结果都将有相应实例的代码。如何解决?n由开发环境解决。n由连接程序解决。504计算机科学与技术学院张淼templateClassCTre
329、e#include“tree.h”CTreeobj1;CTreeobj2;#include“tree.h”CTreeobj1;CTreeobj2;Tree.hA.cppB.cppCTreeintversionCTreedoubleversionCTreeintversionCTreefloatversionA.objB.objCompilepreprocesscompileCTreeintversionCTreedoubleversionCTreedoubleversionlinkexe505计算机科学与技术学院张淼o在C+标准库中,除了从C标准库保留下来的一些功能外,所提供的功能大都以模板形
330、式给出。这些模板构成了C+的标准模板库(StandardTemplateLibrary,简称STL)。506计算机科学与技术学院张淼面向对象标记o用图形把面向对象程序设计对问题的描述直观的表示出来,设计人员、程序开发人员、用户都可以通过它进行方便的交流。o实际使用的面向对象标记图有很多种,每一种标记方法都必须准确而清楚的描述下面四个问题:n类:包括数据成员和成员函数n对象:类的实例n类及对象的关系:继承或包含n类及对象之间的联系:相互作用与消息传送等。507计算机科学与技术学院张淼o现在广泛使用的面向对象标记有很多种,而且,国际上已经有标准的标记记法,称为UML(UnifiedModeling
331、Language,统一建模语言),由OMG(ObjectTechnologyGroup,对象技术组织)于1997年确认并开始推行。oUML不仅可以描述前面我们提到的问题,而且主要着眼于整个软件开发过程中的可视化建模,相当完整,当然也比较复杂。508计算机科学与技术学院张淼第三部分第三部分MFC509计算机科学与技术学院张淼内容内容oMFC内部机理oMFC消息映射机制o框架窗口界面设计(一)o图形和文本(第八章)o对话框和控件(第四、五章)o框架窗口界面设计(二)(第六章)o文档和视图(第七章)510计算机科学与技术学院张淼VisualC+Windows环境下最主要的应用开发系统之一。环境下最主
332、要的应用开发系统之一。C+语言的集成开发环境。语言的集成开发环境。强大的调试功能为大型复杂软件的开发提供了强大的调试功能为大型复杂软件的开发提供了有效的排错手段。有效的排错手段。511计算机科学与技术学院张淼WinMain()入口函数入口函数窗口的创建窗口的创建o设计一个窗口类;设计一个窗口类;o注册窗口类;注册窗口类;o创建窗口;创建窗口;o显示及更新窗口。显示及更新窗口。消息循环消息循环512计算机科学与技术学院张淼MFC简介简介o什么是什么是MFC?nMicrosoftFoundationClassnMicrosoft提供的提供的MFC是封装是封装WindowsAPI的面向对象的面向对象
333、C+类库类库o以层次结构组织以层次结构组织o封装了大部分的封装了大部分的API函数函数nMFC也是一个也是一个应用程序的框架结构应用程序的框架结构o提供图形环境下的提供图形环境下的应用程序框架应用程序框架和和组件组件o编程方式的改变编程方式的改变n并不经常直接调用并不经常直接调用APIn从从MFC类创建对象并调用其成员函数类创建对象并调用其成员函数513计算机科学与技术学院张淼MFC类库结构类库结构CObjectCCmdTargetCWnd应用类结构窗口支持异常类文件服务类文档类框架窗口类控制条类属性页表类对话框类视图类控件类图形设备环境类控制支持类Windows套接字类图形对象类菜单类ODB
334、C支持类DAO支持类同步类其它类:其它类:Internet支持类自动化类型运行时刻对象支持简单值类型结构其它支持类集合模板类用于同步的类数组类列表类映射类Internet类514计算机科学与技术学院张淼CH3.1MFC内部机理oMFC程序的初始化过程oRTTI(RuntimeTypeInformation)运行时类型识别oDynamicCreation动态创建oPersistence永久保存oMessageMapping消息映射oMessageRouting消息传递515计算机科学与技术学院张淼应用程序对象应用程序对象o头文件头文件nAfxwin.hn包含该头文件可以引用包含该头文件可以引用M
335、FC中的类中的类o应用程序对象应用程序对象n一个一个MFC应用程序有且仅有一个应用程序对象应用程序有且仅有一个应用程序对象n应用程序对象应该继承自应用程序对象应该继承自CWinAppn应用对象必须是全局对象应用对象必须是全局对象nInitInstance虚函数虚函数o应用对象自动调用应用对象自动调用InitInstance虚函数,一般应虚函数,一般应覆盖该函数完成初始化工作,如创建应用的主窗口覆盖该函数完成初始化工作,如创建应用的主窗口o该函数返回该函数返回FALSE程序将退出程序将退出516计算机科学与技术学院张淼AFX函数函数o什么是什么是AFX函数函数n全局函数,并非全局函数,并非MFC
336、类的成员函数类的成员函数n任何地方都可以使用任何地方都可以使用o常用的常用的AFX函数函数AfxAbort无条件终止应用程序AfxBeginThread创建新线程并开始执行AfxEndThread终止当前执行的线程AfxMessageBox显示Windows消息框AfxGetApp返回指向应用程序对象的指针AfxGetAppName返回应用程序的名称AfxGetMainWnd返回指向应用程序主窗口的指针AfxGetInstanceHandle返回应用程序当前实例的句柄AfxRegisterWndClass为MFC应用程序注册自定义WNDCLASS类517计算机科学与技术学院张淼MFC如何使用应
337、用程序对象如何使用应用程序对象o是什么启动了我们的程序?是什么启动了我们的程序?nCWinApp取代了取代了WinMain的地位的地位oCWinApp的主要函数的主要函数virtualBOOLInitApplication();virtualBOOLInitInstance();/初始化应用实例初始化应用实例virtualBOOLRun();/进入消息循环进入消息循环virtualBOOLExitInstance();/最后执行的函数最后执行的函数n执行步骤执行步骤o调用应用对象的构造函数创建全局应用对象调用应用对象的构造函数创建全局应用对象o执行执行CWinApp:InitApplicati
338、ono执行执行pApp-InitInstance,必须重写该函数必须重写该函数n如:通常在该函数中打开应用程序的主框架窗口如:通常在该函数中打开应用程序的主框架窗口518计算机科学与技术学院张淼类作用域类作用域o类定义构成一个作用域:类作用域,其中的类定义构成一个作用域:类作用域,其中的标识符局部于类定义,它们可以与类定义外标识符局部于类定义,它们可以与类定义外的全局标识符或其他类定义中的标识符相同。的全局标识符或其他类定义中的标识符相同。在类定义外使用类定义中的在类定义外使用类定义中的标识符标识符时,需通时,需通过对象名受限或类名受限。过对象名受限或类名受限。在类定义中使用在类定义中使用与局
339、部标识符同名的全局标识符时,需要在与局部标识符同名的全局标识符时,需要在全局标识符前面加上全局域分辨符(全局标识符前面加上全局域分辨符(:)来)来实现。实现。519计算机科学与技术学院张淼MFC中最重要的封装是对中最重要的封装是对Win32API的封装,的封装,因此,理解因此,理解WindowsObject和和MFCObject(C+对象,一个对象,一个C+类的实例类的实例)之间之间的关系是理解的关系是理解MFC的关键之一。所谓的关键之一。所谓WindowsObject(Windows对象)是对象)是Win32下用句柄表示的下用句柄表示的Windows操作系统对操作系统对象;所谓象;所谓MFC
340、Object(MFC对象对象)是是C+对对象,是一个象,是一个C+类的实例,这里类的实例,这里MFCObject是有特定含义的,指封装是有特定含义的,指封装WindowsObject的的C+Object,并非指任意的,并非指任意的C+Object。MFCObject和和WindowsObject是不一样是不一样的,但两者紧密联系。的,但两者紧密联系。520计算机科学与技术学院张淼一个一个MFC窗口对象是一个窗口对象是一个C+CWnd类(或类(或派生类)的实例,是程序直接创建的。在程序执派生类)的实例,是程序直接创建的。在程序执行中它随着窗口类构造函数的调用而生成,随着行中它随着窗口类构造函数的
341、调用而生成,随着析构函数的调用而消失。而析构函数的调用而消失。而Windows窗口则是窗口则是Windows系统的一个内部数据结构的实例,由系统的一个内部数据结构的实例,由一个一个“窗口句柄窗口句柄”标识,标识,Windows系统创建它系统创建它并给它分配系统资源。并给它分配系统资源。Windows窗口在窗口在MFC窗口对象创建之后,由窗口对象创建之后,由CWnd类的类的Create成员成员函数创建,函数创建,“窗口句柄窗口句柄”保存在窗口对象的保存在窗口对象的m_hWnd成员变量中。成员变量中。Windows窗口可以被窗口可以被一个程序销毁,也可以被用户的动作销毁。一个程序销毁,也可以被用户
342、的动作销毁。521计算机科学与技术学院张淼HWNDm_hWnd;其他成员变量其他成员变量成员函数成员函数窗口窗口MFC对象对象522计算机科学与技术学院张淼1.从数据结构上比较从数据结构上比较MFCObject是相应是相应C+类的实例,这些类是类的实例,这些类是MFC或者程序员定义的;或者程序员定义的;WindowsObject是是Windows系统的内部结系统的内部结构,通过一个句柄来引用;构,通过一个句柄来引用;MFC给这些类定义了一个成员变量来保存给这些类定义了一个成员变量来保存MFCObject对应的对应的WindowsObject的句柄。的句柄。523计算机科学与技术学院张淼2.从层
343、次上讲比较从层次上讲比较MFCObject是高层的,是高层的,WindowsObject是低是低层的;层的;MFCObject封装了封装了WindowsObject的大部分的大部分或全部功能,或全部功能,MFCObject的使用者不需要直接应的使用者不需要直接应用用WindowsObject的的HANDLE(句柄)使用(句柄)使用Win32API,代替它的是引用相应的,代替它的是引用相应的MFCObject的成员函数。的成员函数。524计算机科学与技术学院张淼3.从创建上比较从创建上比较MFCObject通过构造函数由程序直接创建;通过构造函数由程序直接创建;WindowsObject由由相应
344、的相应的SDK函数创建。函数创建。MFC中,使用这些中,使用这些MFCObject,一般分两步:,一般分两步:首先,创建一个首先,创建一个MFCObject,或者在,或者在STACK中创建,或者在中创建,或者在HEAP中创建,这时,中创建,这时,MFCObject的句柄实例变量为空,或者说不是一个的句柄实例变量为空,或者说不是一个有效的句柄。有效的句柄。然后,调用然后,调用MFCObject的成员函数创建相应的的成员函数创建相应的WindowsObject,MFC的句柄变量存储一个有效句柄。的句柄变量存储一个有效句柄。当然,可以在当然,可以在MFCObject的构造函数中创建相应的的构造函数中
345、创建相应的Windows对象,对象,MFC的的GDI类就是如此实现的,但从实质上讲,类就是如此实现的,但从实质上讲,MFCObject的创建和的创建和WindowsObject的创建是两回事。的创建是两回事。525计算机科学与技术学院张淼4.从销毁上比较从销毁上比较MFCObject随着析构函数的调用而消失;但随着析构函数的调用而消失;但WindowsObject必须由相应的必须由相应的Windows系统函数销毁。系统函数销毁。设备描述表设备描述表CDC类的对象有所不同,它对应的类的对象有所不同,它对应的HDC句柄对句柄对象可能不是被销毁,而是被释放。象可能不是被销毁,而是被释放。当然,可以在
346、当然,可以在MFCObject的析构函数中完成的析构函数中完成WindowsObject的销毁,的销毁,MFCObject的的GDI类等就是如此实现类等就是如此实现的,但是,应该看到:两者的销毁是不同的。的,但是,应该看到:两者的销毁是不同的。526计算机科学与技术学院张淼CH3.2MFC消息映射机制oSDK中有窗口过程函数,用switch/case语句处理消息oMFC对消息如何处理?n消息映射527计算机科学与技术学院张淼将一个消息映射添加到一个类中o声明消息映射n将DECLARE_MESSAGE_MAP语句添加到类声明中o在类的实现文件中加入表和表项的定义o添加成员函数定义处理消息n成员函
347、数的名字与消息映射宏名字对应o如:ON_WM_PAINT()对应OnPaint()函数BEGIN_MESSAGE_MAP(theClass,baseClass)./当前类当前类,当前类的父类,当前类的父类/END_MESSAGE_MAP()528计算机科学与技术学院张淼鼠标鼠标o映射鼠标消息(映射鼠标消息(以左键按下消息为例以左键按下消息为例)n添加消息映射宏添加消息映射宏oON_WM_LBUTTONDOWN()n声明消息处理函数声明消息处理函数oafx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);nnFlags:位标志位标志npoint:鼠标位置
348、鼠标位置n实现消息处理函数实现消息处理函数voidCMfcTsetView:OnLButtonDown(UINTnFlags,CPointpoint)参见工程Mouse529计算机科学与技术学院张淼键盘o映射键盘消息(以字符键为例)n添加消息映射宏oON_WM_CHAR()n声明并实现消息处理函数oafx_msgvoidOnChar(UINTnChar,UINTnRepCnt,UINTnFlags);nnChar:虚拟键值nnRepCnt:重复次数nnFlags:位标志参见工程Keyboard530计算机科学与技术学院张淼AfxWndProcAfxCallWndProcWindowProcOn
349、WndMsgOnCommandOnNotify标准消息标准消息531计算机科学与技术学院张淼CH3.3框架窗口界面设计(一)o消息路由o菜单的设计o交互对象的动态更新532计算机科学与技术学院张淼用户接口(用户接口(UI)资源是指)资源是指功能菜单、对话框、程序图标、功能菜单、对话框、程序图标、光标光标等资源,它是等资源,它是Windows应用程序界面的重要组成部分。应用程序界面的重要组成部分。资源的使用极大方便了应用程序界面的设计,也大大方便了资源的使用极大方便了应用程序界面的设计,也大大方便了应用程序与用户的交互。应用程序与用户的交互。这些用户资源的实际内容(二进制代码)是借助各种工这些用
350、户资源的实际内容(二进制代码)是借助各种工具产生的。并以各种扩展名的文件存在,如具产生的。并以各种扩展名的文件存在,如.ico,.bmp,.cur等。程序员必须在一个所谓的资源描述文档(等。程序员必须在一个所谓的资源描述文档(.rc)中描述它)中描述它们。们。RC编译器读取编译器读取RC文件的描述后,将所有用户接口资源文件的描述后,将所有用户接口资源文件集中制作一个文件集中制作一个.RES文件。文件。这些资源可以使用这些资源可以使用VC+6.0提供的资源编辑器来实现提供的资源编辑器来实现创建和编辑。创建和编辑。资源资源533计算机科学与技术学院张淼资源资源o资源分类资源分类n菜单菜单oWM_C
351、OMMAND消息消息nwParam低低16位传递菜单项资源位传递菜单项资源IDn对话框对话框oWM_COMMAND消息消息nwParam低低16位传递子窗口(控件)资源位传递子窗口(控件)资源IDno资源资源IDn资源的唯一标识资源的唯一标识534计算机科学与技术学院张淼命令消息的路由命令消息的路由拐弯上溯拐弯上溯AfxWndProcAfxCallWndProcWindowProcOnWndMsgOnCommandOnNotifyOnCmdMsg535计算机科学与技术学院张淼CFrameWnd:OnCommandCWnd:OnCommandCView:OnCmdMsgCWnd:OnCmdMsg
352、(CCmdTarget:OnCmdMsg)DispatchCmdMsgCDocument:OnCmdMsgCFrameWnd:OnCmdMsgmsghandlerCCmdTarget:OnCmdMsgDispatchCmdMsgmsghandlerCWnd:OnCmdMsg(CCmdTarget:OnCmdMsg)DispatchCmdMsgmsghandlerCWinApp:OnCmdMsg(CCmdTarget:OnCmdMsg)DispatchCmdMsgmsghandler1234536计算机科学与技术学院张淼CMainFrame交给View类类DOC类类交给APP类类处理有有没有没有
353、有有处理处理没有537计算机科学与技术学院张淼消息的分类消息的分类o标准消息标准消息除除WM_COMMAND之外,所有以之外,所有以WM_开头的消息。开头的消息。从从CWnd派生的类,都可以接收到这类消息。派生的类,都可以接收到这类消息。o命令消息命令消息来自菜单、加速键或工具栏按钮的消息。这类消息都以来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在呈现。在MFC中,通过菜单项的标识(中,通过菜单项的标识(ID)来)来区分不同的命令消息;在区分不同的命令消息;在SDK中,通过消息的中,通过消息的wParam参数识别。参数识别。从从CCmdTarget派生的类,都可以
354、接收到这类消息。派生的类,都可以接收到这类消息。o通告消息通告消息由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以消息也是以WM_COMMAND形式呈现。形式呈现。从从CCmdTarget派生的类,都可以接收到这类消息。派生的类,都可以接收到这类消息。538计算机科学与技术学院张淼o菜单类:菜单类:CMenun用于用于管理菜单管理菜单n它是一个它是一个WindowsHMenu的封装,提供了的封装,提
355、供了与窗口有关的菜单资源建立、修改、跟踪及删与窗口有关的菜单资源建立、修改、跟踪及删除的成员函数除的成员函数539计算机科学与技术学院张淼当要显示一个菜单时,操作系统发出当要显示一个菜单时,操作系统发出WM_INITMENUPOPUP消息,然后由消息,然后由MFC的基类(的基类(如如CFrameWnd)接管,它创建一个)接管,它创建一个CCmdUI对象,并与对象,并与第一第一个菜单项个菜单项相关联,并调用相关联,并调用CCmdUI对象的一个成员函数对象的一个成员函数DoUpdate()。这个函数发出。这个函数发出CN_UPDATE_COMMAND_UI消息消息,这,这条消息带有指向条消息带有指
356、向CCmdUI对象的指针。如果对这个菜单项对象的指针。如果对这个菜单项捕获了捕获了CN_UPDATE_COMMAND_UI消息,便可以在这个消息,便可以在这个消息的消息响应函数中进行菜单项显示的处理(如可用不消息的消息响应函数中进行菜单项显示的处理(如可用不可用等)。可用等)。处理完第一个菜单项后处理完第一个菜单项后同一个同一个CCmdUI对象就设置为与第对象就设置为与第二个菜单项相关联,这样顺序进行,直到完成所有菜单项。二个菜单项相关联,这样顺序进行,直到完成所有菜单项。命令更新命令更新540计算机科学与技术学院张淼CH3.4图形和文本o设备描述表类CDCn该类及其子类支持设备描述表对象nC
357、DC类是一个较大的类,包括许多成员函数n通过CDC对象的成员函数可以完成所有的绘画工作o获取和释放设备描述表PAINTSTRUCTps;CDC*pDC=BeginPaint(&ps);EndPaint(&ps);CDC*pDC=GetDC();ReleaseDC(pDC);仅用仅用OnPaint处理程序处理程序用于非用于非OnPaint处理程序处理程序以上获取和释放设备描述表的函数都是以上获取和释放设备描述表的函数都是CWnd类的成员函数类的成员函数541计算机科学与技术学院张淼CDC类的派生类o通常我们不直接使用CDC类,而使用其派生类nCPaintDCo用于在窗口客户区画图,仅限于在OnP
358、aint处理程序nCClientDCo用于在窗口客户区画图,在OnPaint处理程序之外使用,构造对象时传递NULL参数可以实现在整个屏幕画图nCWindowDCo用于在窗口内任意地方画图,包括非客户区nMetaFileDCo用于向GDI元文件画图542计算机科学与技术学院张淼画图o画直线和曲线nMoveTonLineTonPolylinenPolylineTonArcnArcTonPolyBeziernPolyBezierTonPolyDrawo画椭圆、多边形等nChordnEllipsenPienPolygonnRectanglenRoundRect所有函数都是设备描所有函数都是设备描述表
359、类的述表类的成员函数成员函数543计算机科学与技术学院张淼画笔类CPeno创建画笔对象n方法一o直接构造对象nCPenpen(PS_SOLID,1,RGB(255,0,0);n方法二o构造一个未初始化的画笔对象,再调用方法初始化nCPenpen;npen.CreatePen(PS_SOLID,1,RGB(255,0,0);544计算机科学与技术学院张淼画笔类CPeno创建画笔对象n方法三o构造一个未初始化的画笔对象,通过向LOGPEN结构中填充描述画笔特性的参数,然后调用CPen的成员函数CreatePenIndirect生成画笔CPenpen;LOGPENlp;lp.lopnStyle=PS
360、_SOLID;lp.lopnWidth.x=1;lp.lopnColor=RGB(255,0,0);pen.CreatePenIndirect(&lp);545计算机科学与技术学院张淼画笔类CPeno使用创建好的画笔n创建好画笔对象后,只要将它选入设备描述表即可CPenpen(PS_SOLID,10,RGB(255,0,0);dc.SelectObject(&pen);dc.Ellipse(0,0,100,100);546计算机科学与技术学院张淼画刷类CBrusho创建画刷对象n方法一o直接构造对象nCBrushbrush(RGB(255,0,0);n方法二o构造一个未初始化的画刷对象,再调用
361、方法初始化nCBrushbrush;nbrush.CreateSolidBrush(RGB(255,0,0);547计算机科学与技术学院张淼画刷类CBrusho创建阴影线画刷n方法一o直接构造对象nCBrushbrush(HS_DIAGCROSS,RGB(255,0,0);n方法二o构造一个未初始化的画刷对象,再调用方法初始化nCBrushbrush;nbrush.CreateHatchBrush(HS_DIAGCROSS,RGB(255,0,0);548计算机科学与技术学院张淼画刷类CBrusho画刷的使用n同画笔对象一样,创建好画刷对象后,只要将它选入设备描述表即可CBrushbrush(
362、HS_DIAGCROSS,RGB(255,255,255);dc.SelectObject(&brush);dc.SetBkColor(RGB(192,192,192);dc.Rectangle(0,0,100,100);549计算机科学与技术学院张淼字体类CFonto什么是字体n字体是一组具有特定尺寸(高度)和字样的字符o字样指示字体共有属性,如粗细等o字体的创建参见工程Hello参见Font.docCFontfont;/调用以下方法之一初始化字体对象调用以下方法之一初始化字体对象font.CreateFontfont.CreateFontIndirectfont.CreatePointFo
363、ntfont.CreatePointFontIndirect通过通过LOGFONT结构来创建字体结构来创建字体550计算机科学与技术学院张淼坐标空间oMicrosoftWindows下的程序运用坐标空间和转换来对图形输出进行缩放、旋转、平移、斜切和反射。o一个坐标空间是一个平面的空间,通过使用两个相互垂直并且长度相等的轴来定位二维对象。(0,0)XmaxXminYmaxYmin551计算机科学与技术学院张淼坐标空间oWin32应用程序设计接口(API)使用四种坐标空间:世界坐标系空间、页面空间、设备空间、和物理设备空间。应用程序运用世界坐标系空间对图形输出进行旋转、斜切或者反射。oWin32A
364、PI把世界坐标系空间和页面空间称为逻辑空间;最后一种坐标空间(即物理设备空间)通常指应用程序窗口的客户区;但是它也包括整个桌面、完整的窗口(包括框架、标题栏和菜单栏)或打印机的一页或绘图仪的一页纸。物理设备的尺寸随显示器、打印机或绘图仪所设置的尺寸而变化。,552计算机科学与技术学院张淼转换o如要在物理设备上绘制输出,Windows把一个矩形区域从一个坐标空间拷贝到(或映射到)另一个坐标空间,直至最终完整的输出呈现在物理设备上(通常是屏幕或打印机)。o如果该应用程序调用了SetWorldTransform函数,那么映射就从应用程序的世界坐标系空间开始;否则,映射在页面空间中进行。在Window
365、s把矩形区域的每一点从一个空间拷贝到另一个空间时,它采用了一种被称作转换的算法,转换是把对象从一个坐标空间拷贝到另一个坐标空间时改变(或转变)这一对象的大小、方位、和形态,尽管转换把对象看成一个整体,但它也作用于对象中的每一点或每条线。http:/www.sunxin.org553计算机科学与技术学院张淼转换YmaxYmin世界坐标系空间下图是运用下图是运用SetWorldTransform函数而进函数而进行的一个典型转换。行的一个典型转换。YmaxYmin页面空间YminYmax设备空间物理设备554计算机科学与技术学院张淼页面空间到设备空间的转换o页面空间到设备空间的转换是原Windows
366、接口的一部分。这种转换确定与一特定设备描述表相关的所有图形输出的映射方式。o所谓映射方式是指确定用于绘图操作的单位大小的一种量度转换。映射方式是一种影响几乎任何客户区绘图的设备环境属性。另外还有四种设备环境属性:窗口原点、视口原点、窗口范围和视口范围,这四种属性与映射方式密切相关。555计算机科学与技术学院张淼页面空间到设备空间的转换o页面空间到设备空间的转换所用的是两个矩形的宽与高的比率,其中页面空间中的矩形被称为窗口,设备空间中的矩形被称为视口,Windows把窗口原点映射到视口原点,把窗口范围映射到视口范围,就完成了这种转换,如下图所示:窗口原点视口原点窗口视口页面空间设备空间556计算
367、机科学与技术学院张淼设备空间到物理空间的转换o设备空间到物理空间的转换有几个独特之处:它只限于平移,并由Windows的窗口管理部分控制,这种转换的唯一用途是确保设备空间的原点被映射到物理设备上的适当点上。没有函数能设置这种转换,也没有函数可以获取有关数据。557计算机科学与技术学院张淼默认转换o一旦应用程序建立了设备描述表,并立即开始调用GDI绘图或输出函数,则运用默认页面空间到设备空间的转换和设备空间到客户区的转换(在应用程序调用SetWorldTransform函数之前,不会出现世界坐标空间到页面空间的转换)。o默认页面空间到设备空间的转换结果是一对一的映射;即页面空间上给出的一点映射到
368、设备空间的一个点。正如前文讲到的,这种转换没有以矩阵指定,而是通过把视口宽除以窗口宽,把视口高除以窗口高而得出的。在默认的情况下,视口尺寸为1x1个象素,窗口尺寸为1x1页单位。o设备空间到物理设备(客户区、桌面或打印机)的转换结果总是一对一的;即设备空间的一个单位总是与客户区、桌面、或打印机上的一个单位相对应。这一转换的唯一用途是平移。无论窗口移到桌面的什么位置,它永远确保输出能够正确无误地出现在窗口上。o默认转换的一个独特之处是设备空间和应用程序窗口的y轴方向。在默认的状态下,y轴正向朝下,负y方向朝上。558计算机科学与技术学院张淼逻辑坐标和设备坐标o几乎在所有的GDI函数中使用的坐标值
369、都是采用的逻辑单位。Windows必须将逻辑单位转换为“设备单位”,即像素。这种转换是由映射方式、窗口和视口的原点以及窗口和视口的范围所控制的。oWindows对所有的消息(如WM_SIZE、WM_MOUSEMOVE、WM_LBUTTONDOWN、WM_LBUTTONUP),所有的非GDI函数和一些GDI函数(例如GetDeviceCaps函数),永远使用设备坐标。o“窗口”是基于逻辑坐标的,逻辑坐标可以是象素、毫米、英寸等单位;“视口”是基于设备坐标(象素)的。通常,视口和客户区是相同的。o缺省的映射模式为MM_TEXT。在这种映射模式下,逻辑单位和设备单位相同。559计算机科学与技术学院张
370、淼逻辑坐标和设备坐标的相互转换o窗口窗口(逻辑逻辑)坐标转换为视口坐标转换为视口(设备设备)坐标的两个公式:坐标的两个公式:xViewport=(xWindow-xWinOrg)*+xViewOrgyViewport=(yWindow-yWinOrg)*+yViewOrgo视口视口(设备设备)坐标转换为窗口坐标转换为窗口(逻辑逻辑)坐标的两个公式:坐标的两个公式:xWindow=(xViewPort-xViewOrg)*+xWinOrgyWindow=(yViewPort-yViewOrg)*+yWinOrgxViewExtxWinExtyViewExtyWinExtxWinExtxViewE
371、xtyWinExtyViewExt560计算机科学与技术学院张淼在MM_TEXT映射方式下逻辑坐标和设备坐标的相互转换o窗口(逻辑)坐标转换为视口(设备)坐标的两个公式:xViewport=xWindow-xWinOrg+xViewOrgyViewport=yWindow-yWinOrg+yViewOrgo视口(设备)坐标转换为窗口(逻辑)坐标的两个公式:xWindow=xViewport-xViewOrg+xWinOrgyWindow=yViewport-yViewOrg+yWinOrg561计算机科学与技术学院张淼CH3.5对话框和控件o对话框有两种类型:模态对话框和非模态对话框。o模态对
372、话框在应用程序能够继续执行之前必须被关闭掉。即当我们显示一个模态对话框时应用程序就会暂停,直到我们关闭对话框我们才能继续执行程序中的其他任务。o非模态对话框允许我们在显示对话框时转而执行程序的其他任务而不用关闭对话框。562计算机科学与技术学院张淼o对话框类:CDialogn由于对话框是一个特殊的窗口,所以该类是从CWnd类中派生出来的,包括o通用对话框类CDialogo支持文件选择、颜色选择、字体选择、打印、替换文本的公共对话框子类563计算机科学与技术学院张淼o控件的创建和基本使用方法n在对话框模板中用编辑器指定控件,将对话框看作控件的父窗口。n编程方式,即调用相应控件类的成员函数Crea
373、te来创建,并在Create函数指定控件的父窗口指针。564计算机科学与技术学院张淼565计算机科学与技术学院张淼对话框控件访问七种方式oGetDlgItem()-Get(Set)WindowText()oGetDlgItemText()/SetDlgItemText()oGetDlgItemInt()/SetDlgItemInt()o将控件和整型变量相关联o将控件和控件变量相关联oSendMessage()oSendDlgItemMessage()566计算机科学与技术学院张淼Z-order窗口的Z次序表明了重叠窗口堆中窗口的位置,这个窗口堆是按一个假想的轴定位的,这个轴就是从屏幕向外伸展的
374、Z轴。Z次序最上面的窗口覆盖所有其它的窗口,Z次序最底层的窗口被所有其它的窗口覆盖。应用程序设置窗口在Z次序中的位置是通过把它放在一个给定窗口的后面,或是放在窗口堆的顶部或底部。Windows系统管理三个独立的Z次序一个用于顶层窗口、一个用于兄弟窗口,还有一个是用于最顶层窗口。最顶层窗口覆盖所有其它非最顶层窗口,而不管它是不是活动窗口或是前台窗口。应用程序通过设置WS_EX_TOPMOST风格创建最顶层窗口。一般情况下,Windows系统把刚刚创建的窗口放在Z次序的顶部,用户可通过激活另外一个窗口来改变Z次序;Windows系统总是把活动的窗口放在Z次序的顶部,应用程序可用函数BringWin
375、dowToTop把一个窗口放置到Z次序的顶部。函数SetWindowPos和DeferWindowPos用来重排Z次序。567计算机科学与技术学院张淼窗口o兄弟窗口共享同一个父窗口的多个子窗口叫兄弟窗口。o活动窗口活动窗口是应用程序的顶层窗口,也就是当前使用的窗口。只有一个顶层窗口可以是活动窗口,如果用户使用的是一个子窗口,Windows系统就激活与这个子窗口相应的顶层窗口。任何时候系统中只能有一个顶层窗口是活动的。用户通过单击窗口(或其中的一个子窗口)、使用ALT+TAB或ALT+ESC组合键来激活一个顶层窗口,应用程序则调用函数SetActiveWindow来激活一个顶层窗口。568计算机
376、科学与技术学院张淼窗口o前台窗口和后台窗口在Windows系统中,每一个进程可运行多个线程,每个线程都能创建窗口。创建正在使用窗口的线程称之为前台线程,这个窗口就称之为前台窗口。所有其它的线程都是后台线程,由后台线程所创建的窗口叫后台窗口。用户通过单击一个窗口、使用ALT+TAB或ALT+ESC组合键来设置前台窗口,应用程序则用函数SetForegroundWindow设置前台窗口。如果新的前台窗口是一个顶层窗口,那么Windows系统就激活它,换句话说,Windows系统激活相应的顶层窗口。569计算机科学与技术学院张淼CH3.6框架窗口界面设计(二)o单文档和多文档程序框架窗口570计算机
377、科学与技术学院张淼p主框架窗口是直接放置在桌面(DeskTop)上的那个窗口,每个应用程序只能有一个主框架窗口。主框架窗口负责管理各个用户交互对象并根据用户操作相应地创建或更新文档窗口及其视图。p文档窗口对SDI程序来说,和主框架窗口是一致的,主框架窗口就是文档窗口;对于MDI程序,文档窗口是主框架窗口的子窗口。p文档窗口一般都有相应的可见边框,它的客户区(除了窗口标题栏、边框外的区域)是由相应的视图来构成的,因此可以说视图是文档窗口内的子窗口。571计算机科学与技术学院张淼窗口状态的改变MFC AppWizardMFC AppWizard为每个窗口设置了相应的大小和位置。为每个窗口设置了相应
378、的大小和位置。运运行行程程序序时时,会会自自动动调调用用框框架架内内部部的的WinMainWinMain函函数数,并并自自动动查查找找该该应应用用程程序序类类的的全全局局变变量量theApptheApp,然然后后自自动动调调用用用用户户应应用用程程序序类类的的虚虚函函数数InitInstanceInitInstance,该该函函数数会会进进一一步步调调用用相相应应的的函函数数来来完完成成主主窗窗口口的的构构造造和显示工作,代码:和显示工作,代码:BOOL BOOL CEx_SDIApp:InitInstanceCEx_SDIApp:InitInstance()() m_pMainWndm_pM
379、ainWnd-ShowWindow(SW_SHOWShowWindow(SW_SHOW););/ / 显示窗口显示窗口m_pMainWndm_pMainWnd-UpdateWindowUpdateWindow();();/ / 更新窗口更新窗口return TRUE;return TRUE;m_pMainWnd是主框架窗口指针变量,是主框架窗口指针变量,ShowWindow是是CWnd类的成员函数,用来按指定的参数显示窗口。类的成员函数,用来按指定的参数显示窗口。572计算机科学与技术学院张淼 通通过过指指定定ShowWindowShowWindow函函数数的的参参数数值值可可以以改改变变改改
380、变变窗窗口口显显示示状状态态。例例如如下下面面的的代代码码是是将将窗窗口口的的初初始始状态设置为状态设置为“最小化最小化”:BOOL BOOL CEx_SDIApp:InitInstanceCEx_SDIApp:InitInstance()() .m_pMainWndm_pMainWnd-ShowWindow(ShowWindow(SW_SHOWMINIMIZED););m_pMainWndm_pMainWnd-UpdateWindowUpdateWindow();();return TRUE;return TRUE; 573计算机科学与技术学院张淼574计算机科学与技术学院张淼p通常有一般和
381、扩展两种形式。可在函数通常有一般和扩展两种形式。可在函数CWnd:Create或或CWnd:CreateEx参数中指定,参数中指定,CreateEx函数可同时支持函数可同时支持以上两种风格,以上两种风格,CWnd:Create只能指定窗口的一般风格。只能指定窗口的一般风格。控件和对话框的窗口风格可直接通过其属性对话框来设置。控件和对话框的窗口风格可直接通过其属性对话框来设置。p除了上述风格外,框架窗口还有以下三个自己的风格。它们都除了上述风格外,框架窗口还有以下三个自己的风格。它们都可以在可以在PreCreateWindowPreCreateWindow重载函数的重载函数的CREATESTRU
382、CTCREATESTRUCT结构中指定。结构中指定。nFWS_ADDTOTITLEFWS_ADDTOTITLE该风格指定相关的信息如文档名添加到框架窗口标题的后面。该风格指定相关的信息如文档名添加到框架窗口标题的后面。nFWS_PREFIXTITLEFWS_PREFIXTITLE 该风格使得框架窗口标题中的文档名显示在应用程序名之前。该风格使得框架窗口标题中的文档名显示在应用程序名之前。nFWS_SNAPTOBARSFWS_SNAPTOBARS该风格用来调整窗口的大小,使它刚好包含了框架窗口中的控该风格用来调整窗口的大小,使它刚好包含了框架窗口中的控制栏。制栏。窗口风格575计算机科学与技术学
383、院张淼oAppWizard中进行修改o修改CREATESTRUCT结构n窗口创建前,自动调用窗口创建前,自动调用PreCreateWindowPreCreateWindow虚函数。虚函数。用用MFC AppWizardMFC AppWizard创建文档应用程序结构时,创建文档应用程序结构时,MFCMFC已为主窗口或文档窗口类自动重载了该虚函已为主窗口或文档窗口类自动重载了该虚函数。可以在此函数中通过修改数。可以在此函数中通过修改CREATESTRUCTCREATESTRUCT结结构来设置窗口的绝大多数风格。构来设置窗口的绝大多数风格。576计算机科学与技术学院张淼o使用ModifyStyle和
384、ModifyStyleExModifyStyleExModifyStyleEx可可更更改改窗窗口口的的扩扩展展风风格格。两两个个函函数数具具有相同的参数,含义。有相同的参数,含义。 BOOL BOOL ModifyXXXXModifyXXXX( DWORD ( DWORD dwRemovedwRemove, DWORD, DWORD dwAdddwAdd,UINT,UINT nFlagsnFlags = 0 ); = 0 ); 参数参数dwRemovedwRemove指定需要删除的风格,指定需要删除的风格,dwAdddwAdd指定需指定需 要增加的风格,要增加的风格,nFlagsnFlags表
385、示表示SetWindowPosSetWindowPos的标的标 志。志。框框架架窗窗口口设设定定扩扩展展风风格格只只能能通通过过调调用用ModifyStyleModifyStyle函函数来进行。数来进行。577计算机科学与技术学院张淼改变窗口的大小和位置 CWnd类的成员函数SetWindowPos或MoveWindow可以改变窗口的大小和位置。SetWindowPos可以改变窗口的大小、位置,还可以改变所有窗口在堆栈排列的次序(Z次序) 。578计算机科学与技术学院张淼状态栏状态栏的定义o AppWizardAppWizard创创建建的的SDISDI或或MDIMDI应应用用程程序序框框架架中
386、中,有有一一个个静静态态的的indicatorindicator数数组组,是是在在MainFrm.cppMainFrm.cpp文文件件中中定义的,被定义的,被MFCMFC用作状态栏的定义。用作状态栏的定义。o 数数组组中中的的元元素素是是一一些些标标识识常常量量或或是是字字串串资资源源的的ID号号。图图列列出出了了indicators数数组组元元素素与与标标准准状状态态栏栏窗格的关系。窗格的关系。StaticUINTindicators=ID_SEPARATOR,ID_INDICATOR_CAPS,ID_INDICATOR_NUM,ID_INDICATOR_SCRL,图6.28indicato
387、rs数组的定义579计算机科学与技术学院张淼o增加和减少窗格增加和减少窗格 在状态栏中增加信息行窗格,在在状态栏中增加信息行窗格,在indicatorsindicators数数组中增加一个组中增加一个ID_SEPARATORID_SEPARATOR标识;在状态栏中标识;在状态栏中增加指示器窗格,在增加指示器窗格,在indicatorsindicators数组中增加一数组中增加一个在字符串表中定义过的资源个在字符串表中定义过的资源IDID。状态栏减少。状态栏减少一个窗格,只需减少一个窗格,只需减少indicatorsindicators数组元素。数组元素。580计算机科学与技术学院张淼o在状态栏
388、上显示文本调调用用CStatusBar:SetPaneTextCStatusBar:SetPaneText函函数数更更新新任任何窗格中的文本。函数原型:何窗格中的文本。函数原型:BOOL SetPaneText( int nIndexnIndex, LPCTSTR lpszNewTextlpszNewText, BOOL bUpdatebUpdate = = TRUE );581计算机科学与技术学院张淼p改变状态栏的风格在在MFCMFC的的CStatusBarCStatusBar类类中中,有有两两个个成成员员函函数数可可以以改改变变状态栏风格,它们是:状态栏风格,它们是:void SetPan
389、eInfo( int nIndexnIndex, UINT nIDnID, UINT nStylenStyle, int cxWidthcxWidth );void SetPaneStyle( int nIndexnIndex, UINT nStylenStyle ); 582计算机科学与技术学院张淼图标和光标 使用GetClassLong和SetClassLong重新指定应用程序窗口的图标,原型:DWORD SetClassLong( HWND hWnd, int nIndex, LONG dwNewLong);DWORD GetClassLong( HWND hWnd, int nInde
390、x);583计算机科学与技术学院张淼o使用系统光标 标标准准光光标标可可以以使使用用CWinAppCWinApp: : LoadStandardCursorLoadStandardCursor加加载载到到程程序序中中,函数:函数:HCURSOR LoadStandardCursor( LPCTSTR lpszCursorNamelpszCursorName ) const;lpszCursorNamelpszCursorName用来指定一个标准光标名,可以是下列宏定义:用来指定一个标准光标名,可以是下列宏定义:IDC_ARROW IDC_ARROW 标准箭头光标标准箭头光标IDC_IBEAM
391、IDC_IBEAM 标准文本输入光标标准文本输入光标IDC_WAIT IDC_WAIT 漏斗型计时等待光标漏斗型计时等待光标IDC_CROSS IDC_CROSS 十字形光标十字形光标IDC_UPARROW IDC_UPARROW 垂直箭头光标垂直箭头光标IDC_SIZEALL IDC_SIZEALL 四向箭头光标四向箭头光标IDC_SIZENWSE IDC_SIZENWSE 左上至右下的双向箭头光标左上至右下的双向箭头光标IDC_SIZENESW IDC_SIZENESW 左下至右上的双向箭头光标左下至右上的双向箭头光标IDC_SIZEWE IDC_SIZEWE 左右双向箭头光标左右双向箭头
392、光标IDC_SIZENS IDC_SIZENS 上下双向箭头光标上下双向箭头光标 584计算机科学与技术学院张淼o使用光标资源用用编编辑辑器器创创建建或或从从外外部部调调入入的的光光标标资资源源,通通过过函函数数CWinApp:LoadCursorCWinApp:LoadCursor进行加载,原型:进行加载,原型:HCURSOR HCURSOR LoadCursorLoadCursor( ( LPCTSTR LPCTSTR lpszResourceNamelpszResourceName ) ) const;const;HCURSOR HCURSOR LoadCursorLoadCursor(
393、 UINT ( UINT nIDResourcenIDResource ) const; ) const;585计算机科学与技术学院张淼o更改程序中的光标更改程序中的光标 更更 改改 程程 序序 中中 的的 光光 标标 最最 简简 单单 的的 方方 法法 是是 MFC MFC ClassWizardClassWizard映映射射WM_SETCURSORWM_SETCURSOR消消息息,该该消消息息是是光光标标移移动动到到一一个个窗窗口口内内并并且且还还没没有有捕捕捉捉到到鼠鼠标标时时产产生生的。的。CWndCWnd为此消息的映射函数定义这样的原型:为此消息的映射函数定义这样的原型:afx_ms
394、gafx_msg BOOL BOOL OnSetCursorOnSetCursor( ( CWndCWnd* * pWndpWnd, , UINT UINT nHitTestnHitTest, UINT , UINT messagemessage ); );pWndpWnd表表示示拥拥有有光光标标的的窗窗口口指指针针,nHitTestnHitTest用用来来表表示示光标所处的位置。光标所处的位置。messagemessage用来表示鼠标消息。用来表示鼠标消息。在在OnSetCursorOnSetCursor函数调用函数调用SetCursorSetCursor来设置相应的光来设置相应的光标,并将
395、标,并将OnSetCursorOnSetCursor函数返回函数返回TRUETRUE,就可改变当,就可改变当前的光标了。前的光标了。586计算机科学与技术学院张淼CH3.7文档和视图Document/Viewo人有“体面”,数据也有“体面”,实际的数据就是体,显示在屏幕上(甚而打印机上)的画面就是面。oMFC之所以为ApplicationFramework,最重要的一个特征就是它能够将管理数据的程序代码和负责数据显示的程序代码分离开来,这种能力由MFC的Document/View提供。oDocument/View是MFC的基石。n甚至OLE复合文件都是建筑在文档/视图的基础上587计算机科学与
396、技术学院张淼o其实Document/View不是什么新主意,XeroxPARC实验室是这种观念的滥觞,它就是Smalltalk环境中的关键部分MVC(Model-View-Controller)nModelDocumentnControllerDocumentTemplate588计算机科学与技术学院张淼o“文档/视图”是一种程序类型,最适合于开发文本编辑之类的软件。oMFC中有两种类型的文档视结构程序:单文档界面(SDI)应用程序和多文档界面(MDI)应用程序。n在单文档界面程序中,用户在同一时刻只能操作一个文档。n一个多文档界面应用程序也能操作文档,但它允许同时操作多个文档。589计算机科
397、学与技术学院张淼o注意,有两种情况不宜采用文档/视图结构:不是面向数据的应用或数据量很少的应用程序,不宜采用文档/视图结构。如一些工具程序包括磁盘扫描程序、时钟程序,还有一些过程控制程序等。不使用标准的窗口用户界面的程序,像一些游戏等。590计算机科学与技术学院张淼oCDocument:负责管理数据的类,提供保存和加载数据的功能,即数据的体。oCView:负责显示数据,是数据的用户窗口,为用户提供了文档的可视数据显示,它把文档的部分或全部内容在窗口中显示出来。以及给用户提供对数据的编辑和修改功能,即数据的面。591计算机科学与技术学院张淼CMyDoc:serialize()/把数据读出文件把数
398、据读出文件/放入放入Document中中CMyView:OnDraw()/取得取得Document/调用调用GDI函数函数/将数据表现出来将数据表现出来TheC+compliergenings,allofwhichaareCausedbytheHello,IamJ.JHou,aGoodman.Thedifference,omitlpCmdLineparameterHello,IamJ.JHou,aGoodman.Document是数据的体,是数据的体,View是数据的面是数据的面592计算机科学与技术学院张淼CMyDoc:serialize()/把数据从把数据从Document写入档案写入档案
399、CMyView:OnDraw()/记录鼠标位置为记录鼠标位置为DWORD/并将并将DWORD加入加入Document0400FFFF010007435374726F6B65000800018005000026001C0027000027001C000180000800018005000026001C002700View是是Document的第一线,负责与使用者接触的第一线,负责与使用者接触593计算机科学与技术学院张淼opersistence永久保存n放在RAM中的东西,生命受电力的左右,不可能永久保存;唯一的办法就是把它写到文件中去。n只要把其中的成员变量依次写入文件。n对于成员对象,先要记
400、载其类名,然后才是对象中的数据。n读,当程序从文件中读到一个类名称时,如何实现一个对象?594计算机科学与技术学院张淼oMFC的六大关键技术nMFC程序的初始化过程nRTTI(RuntimeTypeInformation)运行时类型识别nDynamicCreation动态创建nPersistence永久保存nMessageMapping消息映射nMessageRouting消息传递595计算机科学与技术学院张淼Serialize序列化(串行化)oMFC有一套Serialize机制,目的在于把文件名的选择,文件的开关,缓冲区的建立,数据的读写、提取运算符和插入运算符的重载、对象的动态创建等都包装
401、起来。oSerialization:存储和恢复对象的过程。o负责这项任务的是MFCCObject类中的一个名为Serialize的虚函数,文件的读写操作均通过它。596计算机科学与技术学院张淼oCArchiven没有基类nCArchive允许以永久的二进制形式(通常使用磁盘存储)保存复杂的对象网络。n这些对象被删除后存储器仍保存它们。以后程序员可以从保留存储器中装入这些数据,在内存中重组这些对象。串行化597计算机科学与技术学院张淼IDR_MAINFRAME字符串资源中各子串的含义(1)CDocTemplate:windowTitle,主窗口标题栏上的字符串,MDI程序不需要指定,将以IDR_
402、MAINFRAME字符串为默认值。(2)CDocTemplate:docName,缺省文档的名称。如果没有指定,缺省文档的名称是无标题。(3)CDocTemplate:fileNewName,文档类型的名称。如果应用程序支持多种类型的文档,此字符串将显示在File/New对话框中。如果没有指定,就不能够在File/New对话框处理这种文件。598计算机科学与技术学院张淼(4)CDocTemplate:filterName,文档类型的描述和一个适用于此类型的通配符过滤器。这个字符串将出现在“File/Open”对话框中的文件类型列表框中。要和CDocTemplate:filterExt一起使用。
403、(5)CDocTemplate:filterExt,文档的扩展名。如果没有指定,就不能够在“File/Open”对话框中处理这种文档。要和CDocTemplate:filterName一起使用。(6)CDocTemplate:regFileTypeId,如果你以:RegisterShellFileTypes向系统的注册表注册文件类型,此值会出现在HEY_CLASSES_ROOT之下成为其子项,并仅供Windows内部使用。如果没有指定,这种文件类型就无法注册。(7)CDocTemplate:regFileTypeName,这也是存储在注册表中的文件类型名称。它会显示于程序中用以访问注册表的对话
404、框内。IDR_MAINFRAME字符串资源中各子串的含义599计算机科学与技术学院张淼oCWinApp拥有一个对象指针:CDocManager*m_pDocManageroCDocManager拥有一个指针链表CPtrListm_templateList,用来维护一系列的DocumentTemplate。oCDocTemplate拥有三个成员变量,分别由Document,View,Frame的CRuntimeClass指针。另有一个成员变量m_nIDResource,用来表示此Document显示时应采用的UI对象。600计算机科学与技术学院张淼o在MFC中,文档类负责管理数据,提供保存和加载
405、数据的功能。视类负责数据的显示,以及给用户提供对数据的编辑和修改功能。601计算机科学与技术学院张淼oMFC给我们提供Document/View结构,将一个应用程序所需要的“数据处理与显示”的函数空壳都设计好了,这些函数都是虚函数,我们可以在派生类中重写这些函数。有关文件读写的操作在CDocument的Serialize函数中进行,有关数据和图形显示的操作在CView的OnDraw函数中进行。我们在其派生类中,只需要去关注Serialize和OnDraw函数就可以了,其它的细节我们不需要去理会,程序就可以良好地运行。602计算机科学与技术学院张淼o当我们按下“File/Open”,ApplicationFramework会激活文件打开对话框,让你指定文件名,然后自动调用CGraphicDoc:Serialize读取文件。ApplicationFramework还会调用CGraphicView:OnDraw,传递一个显示DC,让你重新绘制窗口内容。603计算机科学与技术学院张淼oMFC给我们提供Document/View结构,是希望我们将精力放在数据结构的设计和数据显示的操作上,而不要把时间和精力花费在对象与对象之间、模块与模块之间的通信上。o一个文档对象可以和多个视类对象相关联,而一个视类对象只能和一个文档对象相关联。604计算机科学与技术学院张淼