首页 C++与面向对象程序设计教程实验

C++与面向对象程序设计教程实验

举报
开通vip

C++与面向对象程序设计教程实验C++与面向对象程序设计教程实验 《Visual C++与面向对象程序设计教程》实验 教 学 大 纲 课程编码:609324 课程类别:专业方向课 适用专业:计算机科学与技术 主要教学内容:C++与面向对象程序设计思想 课程总学时:54 课程总学分:3 实验学时:30 实验学分:2 执笔人:王玉亭 本试验指导书分为十二个实验,每个试验可以用两个课时来完成,对于难度较大的实验,可以适当增加课时。任课教师可以根据具体情况对一些实验进行拆分和增删,以适应不同专业不同课时的需求。本试验指导书适用于计算机学院的...

C++与面向对象程序设计教程实验
C++与面向对象程序 设计 领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计 教程实验 《Visual C++与面向对象程序设计教程》实验 教 学 大 纲 课程编码:609324 课程类别:专业方向课 适用专业:计算机科学与技术 主要教学 内容 财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容 :C++与面向对象程序设计思想 课程总学时:54 课程总学分:3 实验学时:30 实验学分:2 执笔人:王玉亭 本试验指导 关于书的成语关于读书的排比句社区图书漂流公约怎么写关于读书的小报汉书pdf 分为十二个实验,每个试验可以用两个课时来完成,对于难度较大的实验,可以适当增加课时。任课教师可以根据具体情况对一些实验进行拆分和增删,以适应不同专业不同课时的需求。本试验指导书适用于计算机学院的三个专业。 【实验目标要求】 《Visual C++与面向对象程序设计教程》是计算机技术专业的一门必修课程。面向对象软件开发方法是吸收了软件工程领域有益概念和有效的方法而发展起来的一种软件开发方法。它集抽象性、封装性、继承性和多态性于一体,可以帮助人们开发出模块化、数据抽象程度高的,体现信息隐蔽、可复用、易修改、易扩大等特性的程序。本课程主要介绍面向对象程序设计的方法和C++语言的基本概念以及基本Windows编程技术,其中以C++语言中的面向对象机制为主。学习者在学习过程中可以通过大量的程序实例和相关练习,逐步掌握C++的面向过程和面向对象的功能,从而掌握面向对象程序设计的基本知识和基本技能。在学习本课程中,只有通过大量的上机实验,才能使学生更好的掌握面向对象程序设计的方法,提高学生运用C++语言和面向对象思想进行编程来解决实际问 快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题 的能力。本课程实验要求学生通过对各部分实验的具体操作练习,能够熟练的掌握c++的基本内容,包括控制结构、基本数据类型、表达式、函数、指针和引用、类与对象的概念以及封装、继承和多态等面向对象程序设计的基础理论,在这些基础理论的基础上,掌握初步的Windows编程技术,包括消息传递机制、MFC应用程序框架、文档视图结构等。 【实验教材及主要参考资料】 教材: 1.《Visual C++与面向对象程序设计教程》(第二版),吕军等编著,高等教育出版社 参考资料: 1.《C++语言程序设计》(含实验指导书),郑莉著, 清华大学出版社 2.《C++程序设计教程》,钱能主编,清华大学出版社 3.《Visual C++程序设计基础》,戴锋编著,清华大学出版社 4.《C++程序设计教程》,吕日著,清华大学出版社 5.《C++语言基础教程题解与上级指导》,吕凤翥编著,清华大学出版社 6.《C++ Primer Plus》(第四版中文版),美国Stephen Prata著,孙建春 韦强译 7.《C++大学教程》,美国Harvey M.Deitel等 【实验学习要求】 认真阅读《Visual C++与面向对象程序设计教程》教材中的与实验相关的章节内容,提前做好实验预习,做到在每个实验前明确实验目的、掌握实验的基本内容及操作方法;在实验中正确使用实验设备,认真观察、分析实验结果;实验后要根据要求做好总结,上交实验报告。 【实验准备】 1 一、Visual C++集成开发环境(IDE)介绍 集成开发环境(IDE)是一个将程序编辑器、编译器、调试工具和其他建立应用程序的工具集成在一起的用于开发应用程序的软件系统。Visual C++软件包中的Developer Studio就是一个集成开发环境,它集成了各种开发工具和VC编译器。程序员可以在不离开该环境的情况下编辑、编译、调试和运行一个应用程序。IDE中还提供大量在线帮助信息协助程序员做好开发工作。Developer Studio中除了程序编辑器、资源编辑器、编译器、调试器外,还有各种向导(如AppWizard和ClassWizard),以及MFC类库,这些都可以帮助程序员快速而正确地开发出应用程序。 向导(Wizard):向导是一个通过一步步的帮助引导你工作的工具。Developer Studio中包含三个向导,用来帮助程序员开发简单的Windows程序,它们是: AppWizard:用来创建一个Windows程序的基本框架结构。AppWizard向导会一步步向程序员提出问题,询问他所创建的项目的特征,然后AppWizard会根据这些特征自动生成一个可以执行的程序框架,程序员然后可以在这个框架下进一步填充内容。AppWizard支持三类程序:基于视图/文档结构的单文档应用、基于视图/文档结构的多文档应用程序和基于对话框的应用程序。也可以利用AppWizard生成最简单的控制台应用程序(类似于DOS下用字符输入输出的程序)。ClassWizard:用来定义AppWizard所创建的程序中的类。可以利用ClassWizard在项目中增加类、为类增加处理消息的函数等。ClassWizard也可以管理包含在对话框中的控件,它可以将MFC对象或者类的成员变量与对话框中的控件联系起来。ActiveX Control Wizard:用于创建一个ActiveX控件的基本框架结构。ActiveX控件是用户自定义的控件,它支持一系列定义的接口,可以作为一个可再利用的组件。 MFC库:库(library)是可以重复使用的源代码和目标代码的集合。MFC(Microsoft Fundamental Casses)是Visual C++开发环境所带的类库,在该类库中提供了大量的类,可以帮助开发人员快速建立应用程序。这些类可以提供程序框架、进行文件和数据库操作、建立网络连接、进行绘图和打印等各种通用的应用程序操作。使用MFC库开发应用程序可以减少很多工作量。 二、项目开发过程 在一个集成的开发环境中开发项目非常容易。一个用C++开发的项目的通用开发过程可以用 左图表示。 建立一个项目的第一步是利用编辑器建 立程序代码文件,包括头文件、代码文件、 资源文件等。然后,启动编译程序,编译程 序首先调用预处理程序处理程序中的预处理 命令(如#include,#define等),经过预处理程 序处理的代码将作为编译程序的输入。编译 对用户程序进行词法和语法分析,建立目标 文件,文件中包括机器代码、连接指令、外 部引用以及从该源文件中产生的函数和数据 名。此后,连接程序将所有的目标代码和用 到的静态连接库的代码连接起来,为所有的 外部变量和函数找到其提供地点,最后产生 一个可执行文件。一般有一个makefile文件 来协调各个部分产生可执行文件。 可执行文件分为两种版本:Debug和 Release。Debug版本用于程序的开发过程,该版本产生的可执行程序带有大量的调试信息,可以供调试程序使用,而Release版本作为最终 2 的发行版本,没有调试信息,并且带有某种形式的优化。学生在上机实习过程中可以采用Debug版本,这样便于调试。 选择是产生Debug版本还是Release版本的方法是:在Developer Studio中选择菜单Build|Set Active Configuration~在弹出的对话框中~选择所要的类型~然后选择OK关闭对话框。 Visual C++ 集成开发环境中集成了编辑器、编译器、连接器以及调试程序,覆盖了的开发应用程序的整个过程,程序员不需要脱离这个开发环境就可以开发出完整的应用程序。 三、使用Visual C++6.0集成开发环境 1、进入Visual C++6.0 单击任务栏中“开始”后选择“程序”,找到Microsoft Visual Studio 6.0文件夹后,单击其中的Microsoft Visual C++6.0图标,则可以启动Visual C++。 2、Visual C++6.0的界面 Visual C++6.0用户界面是一个由窗口、工具条、菜单、工具及其他部分组成的一个集成界面(如下图所示)。通过这个界面,用户可以在同一环境下创建、测试、调试应用程序。主要部分介绍如下: 工具条和菜单,用于提供用户操作的命令接口,菜单以文字和层次化的方式提供命令接口,工具条由一系列按钮组成。 工作区窗口,这个窗口包含关于正在开发的这个项目的有关信息,当打开一个项目以后,工作区窗口将会显示关于当前项目的文件信息和类的信息以及资源的信息。 文档窗口区,这个区域可以显示各种类型的文档,如源代码文件、头文件、资源文件等。可以同时打开多个文档。 输出窗口,输出窗口用来显示几种信息,可以通过选择不同的标签显示不同的信息。这些信息包括:编译连接结果信息(Build标签)、调试信息(Debug标签)、查找结果信息(Find in Files标签)。其中查找结果信息有两个标签,可以显示两次在文件中查找指定内容的结果。 3、获得帮助信息 大多数时候,你可以通过按F1得到上下文帮助。如在编辑文件时按F1可以得到有关编辑的帮助,在编译连接错误信息上按F1可以得到关于该错误的帮助信息。还可以通过选择菜单Help|Contents来启动MSDN查阅器,MSDN查阅器是一个功能强大的程序,可以方便地浏览、查找信息,要想知道具体如何使用MSDN查阅器,可以在MSDN查阅器中选菜单Help下的命 3 令。 4、Visual C++的编辑器 Developer Studio包含一个功能强大的编辑器,可以编辑将被编译成Windows程序的Visual C++源文件。这个编辑器有点象字处理器,但是没有字处理器具备的复杂的排版、文本 格式 pdf格式笔记格式下载页码格式下载公文格式下载简报格式下载 等功能,它注重的是如何帮助程序员快速高效地编制程序。它具有以下特点: 自动语法。用高亮度和不同颜色的字来显示不同的语法成分。 自动缩进。帮助你排列源代码,使其可读性更强 参数帮助。在编辑时用到预定义的windows函数时,可以自动为你显示函数参数 集成的关键字帮助。能够使你快速得到任何关键字、MFC类或Windows函数的帮助信息(按F1即可) 拖放编辑。能够用鼠标选择文本并自由拖动到任意位置 自动错误定位。能自动将光标移动到有编译错误的源代码处。 当你打开一个源代码文件时,就可以利用编辑器对其进行编辑。源代码文件在文档显示区显示,每个文件有独立的显示窗口。如果你选择用其他编辑器编辑源文件,必须将它以纯文本的方式保存。VC的编译器不能处理其中有特别格式字符的文件。 5、常用功能键及其意义 为了使程序员能够方便快捷地完成程序开发,开发环境提供了大量快捷方式来简化一些常用操作的步骤。键盘操作直接、简单,而且非常方便,因而程序员非常喜欢采用键盘命令来控制操作。下面是一些最常用的功能键,希望学员在实验中逐步掌握。 操作类型 功能键 对应菜单 含义 文件操作 Ctrl+N File|New 创建新的文件、项目等 Ctrl+O File|Open 打开项目、文件等 Ctrl+S File|Save 保存当前文件 编辑操作 Ctrl+X Edit|Cut 剪切 Ctrl+C Edit|Copy 复制 Ctrl+V Edit|Paste 粘贴 Ctrl+Z Edit|Undo 撤消上一个操作 Ctrl+Y Edit|Redo 重复上一个操作 Ctrl+A Edit|Select All 全选 建立程序操作 Ctrl+F7 Build| Compiler current file 编译当前源文件 Ctrl+F5 Build|Run exe 运行当前项目 F7 Build|Build exe 建立可执行程序 F5 Build|Start Debugging 启动调试程序 调试 F5 Debug|Go 继续运行 F11 Debug|Step into 进入函数体内部 shift+F11 Debug|Step out 从函数体内部运行出来 F10 Debug|Step over 执行一行语句 F9 设置/清除断点 Ctrl+F10 Debug|Run to cursor 运行到光标所在位置 shift+F9 Debug|QuickWatch 快速查看变量或表达式的值 Shift + F5 Debug|Stop debugging 停止调试 4 【实验计划】 实验序号 实验项目内容 学时 实验类型 实验一 熟悉实验环境以及C++基本要素 2 验证型 实验二 程序的基本控制结构 2 综合型 实验三 基本数据类型 2 综合型 实验四 运算符和表达式 2 综合型 实验五 函数应用 2 综合型 实验六 指针 2 综合型 实验七 类和对象 4 综合型 实验八 继承和派生 4 综合型 实验九 多态 4 综合型 实验十 运算符重载与异常 2 综合型 实验十一 Windows编程(一) 2 综合型 实验十二 Windows编程(二) 2 综合型 【实验任务】 实验一、熟悉实验环境以及C++基本要素 【实验目的】 1、 了解和使用VC集成开发环境。 2、 熟悉VC环境的基本命令和功能键,熟悉常用的功能菜单命令。 3、 学习完整的C++程序开发过程。 4、 理解简单的C++程序结构。 【实验内容】 1、熟悉Visual C++实验环境。 启动Visual C++6.0,看看初始化界面由哪些部分组成。 查看各菜单项,看看都有哪些子菜单和命令。 将鼠标放置于各工具条图标上,系统会自动显示该图标代表的命令含义,了解一下都有哪些命令。 在任意工具条上单击鼠标右键,弹出式菜单上将显示所有可用的工具条,选择其中没有对号(?)的项,看看有什么效果,再选择有对号的项,又有什么效果, 将鼠标移动到任意工具条上,将鼠标放到图标间隙,按下鼠标左键不放,移动鼠标到屏幕中间,有什么现象发生,再将它拖回到原来位置,有什么现象发生, 将鼠标移动到左边的工作区窗口,按下鼠标左键不放,移动鼠标到屏幕中间,有什么现象发生,再将它拖回到原来位置,有什么现象发生, 将鼠标移动到下边的输出窗口,按鼠标右键,弹出一个菜单,选择其中的菜单项”Hide”,结果如何,要重新显示该窗口,选择菜单View|Output,窗口是不是又显示出来了, 选File|Exit退出Developer Studio。 5 2、用AppWizard建立一个控制台应用,在终端上输出”Hello”。 首先创建一个项目(project),项目将代表你的应用,存放你应用的所有信息,包括源文件、资源文件、编译连接设置等。创建项目的步骤为: (1) 启动Developer Studio (2) 从主菜单中选择File|New,将显示出New对话框 (3) 选择Projects标签,并从列表中单击Win32 Console Application (4) 在“Location”编辑框中输入你的工作目录名称,如c:\student\your_name (5) 在对话框的右上角的“project name”编辑框内键入项目的名字,如”Hello”,系统将自动为你的项目分配一个默认的目录 (6) 单击OK继续 (7) 系统将显示一个询问项目类型的程序向导,选择“an empty project” (8) 单击Finish或OK结束配置,创建应用程序 这时系统为你创建一个新的项目,并且在左边的工作区窗口中将出现你项目的名字。工作区窗口出现了两个标签ClassView和FileView。ClassView从类全局函数、和全局变量角度显示项目中建立的各个类,双击某个类名将会在右边的文档显示区显示类的定义文件并把文件的当前位置定位到所选的类;FileView显示构成项目的各个文件,选择某一文件将会在右边的文档显示区显示文件内容。 然后,编辑一个C++源程序,用下面的方法在你创建的项目中添加一个文件: (1) 在主菜单上选择File|New (2) 在New对话框中选择File标签,单击“C++ Source File” (3) 选中Add to Project复选框 (4) 在右边的File name编辑框中为文件指定一个名字,如hello,系统将自动为你加上后缀.cpp。 新的空白文件将自动打开,显示在文档显示区。在文件中输入以下内容: //hello world example #include using namespace std; int main() { cout << "hello!"<< endl ; return 0; //正常返回 } 编辑结束后,仔细检查你输入的内容,看有无错误。确认没有错误之后,选择主菜单的Build|Build Hello.exe来编译你的项目(也可以按功能键F7)。如果你输入的内容没有错误,那么,在屏幕下方的输出窗口将会显示: hello.exe – 0 error(s), 0 warning(s) 如果在编译时得到错误或警告,是你的源文件出现错误,编译的错误会在Visual C++6.0的下方的输出窗口显示出来,逐个查看这些错误的内容,用鼠标双击,光标可以自动移动到发生错误的源程序的相应地点,仔细检查你的源程序,改正发生错误的地方,注意是否否遗留了分号、引号或括号等。改正后,再重新编译,直到编译连接通过为止。 然后就可以运行编译连接后的程序了, 选择Build|Execute hello.exe(或者Ctrl+F5),在开发环境中执行你的程序。程序运行以后将显示一个类似于DOS的窗口,在窗口中输出一行“hello”,紧接着在下面显示“Press any key to continue”,这句话是系统提示你按任意键退出当前运行的程序,回到开发环境中。按任意键,窗口关闭,退回到Visual C++开发环境。(上面的菜单操作都能通过工具条来实现) 3、编写简单的计算程序输入圆的半径,计算圆的周长和面积并输出。 (1) 创建一个控制台项目 6 选择菜单File|New,在Projects标签下选择Windows32 Console Application,输入项目名称“circle”,然后按OK (2) 在项目中增加一个文件 选择菜单File|New,在Files标签下选择C/C++ Source File,输入文件名称“circle”,然后按OK (3) 在文件中输入以下内容 //-------------------------------------------------------------------------------------------------- //该程序让用户输入圆的半径Radius,输出圆的周长Perimeter和面积Area #include #include const double PI = 3.14159; //定义一个常量PI #define PI 3.14159 int main() { int radius; double perimeter, area; cout << "Please input the radius: "; cin >> radius; perimeter = 2 * PI * radius; //周长=2πR area = PI * pow(radius, 2); //面积=πR2 cout << "The perimeter of the circle : " << perimeter << endl; cout << "The area of the circle : " << area << endl; return 0; } 注:power(radius,2)表示求radius的平方,power(x, y)是系统预定义的函数,该函数计算x的y次方。该函数的原型在文件math.h或cmath中说明。 4、编写一个计算矩形面积的程序。 5、使用梯形法计算定积分,其中a = 0, b = 1, 被积函数为sin(x)+e^x,积分区间等分数为200。 实验二、程序的基本控制结构 【实验目的】 1、 掌握选择结构程序的概念。 2、 掌握if语句的执行过程并熟练使用。 3、 掌握switch语句的执行过程并熟练使用。 4、 掌握循环结构程序的概念。 5、 掌握while语句的执行过程并熟练使用。 6、 掌握do~while语句的执行过程并熟练使用。 7、 掌握for语句的执行过程和使用。 8、 掌握break、continue、goto语句的执行过程并熟练使用。 【实验内容】 1、编写计算阶乘n!的程序。 2、编写程序求斐波那契数列的第n项和前n项之和。 3、编写如下程序。 循环从标准输入读入某雇员的工作时间(以小时计)和每小时的工资数,计算并输出他的工资。若雇员月工作小时超过40小时,则超过部分按原工资的1.5倍的加班工资来计算。若雇员月工作小时超过50小时,则超过50的部分按原工资的3 倍的加班工资来计算,而40到50小时的工资仍按照原工资的1.5倍的加班工资来计算。 测试数据: 输入:30 4 7 输出:120 输入:45 4.5 输出:213.75 输入:60 5 输出:425 输入:0 0程序结束 实现要求: 分别用三种循环(for, while, do while)完成程序要求; 要求有输入提示和输出提示,如要输入雇员的工作时间和每小时的工资值时,可以提示: “Please input employee’s work time and wage_per_hour:”。输出时,提示:“The employee’s wage :”; 循环在用户输入的工作时间为0时结束; 可以利用永久循环(while(1))加break语句的方式控制程序流程。 考虑哪种循环语句最适合本应用,如果已经知道要计算的雇员的数目(如5个),用哪种循 环方便, 【实例编程】 验证哥德巴赫猜想 // Example:"验证"哥德巴赫猜想 #include #define M 10001 // 定义验证范围 // 函数 CreatPrimeList(): 生成素数表 void CreatPrimeList(int PrimeList[]) { int i, j; // 将PrimeList的各元素设置为从0开始的正整数 for(i=0; ix/2) // 找到了一个不能分解为两个素数和的偶数 cout<<"Great discovery: Goldbach is wrong!"< int main() { cout << "char length:" << sizeof( char ) << endl; cout << "int length:" << sizeof( int ) << endl; cout << "long length:" << sizeof( long ) << endl; cout << "float length:" << sizeof( float ) << endl; cout << "double length:" << sizeof( double ) << endl; cout << "long double length:" << sizeof( long double ) << endl; cout << "char* length:" << sizeof( char* ) << endl; cout << "int* length:" << sizeof( int* ) << endl; cout << "long* length:" << sizeof( long* ) << endl; cout << "float* length:" << sizeof( float* ) << endl; cout << "double* length:" << sizeof( double* ) << endl; cout << "long double* length:" << sizeof( long double* ) << endl; cout << "void* length:" << sizeof( void* ) << endl; return 0; } 2、用数组来处理求斐波那契数列的第n项和前n项之和。 3、打印杨辉三角形(要求打印十行)。 4、编写一函数,求给矩阵的转置,要求写出主函数进行验证。 5、编写一个字符串处理函数,将一个字符串中的所有大写字母转换为对应的小写字母。 6、掌握编译和连接错误的定位方法。 开发环境下方的输出窗口(Output)显示编译和连接过程中出现的错误,错误信息包括:错 误出现的文件名、行号、错误代码。错误信息格式为<源程序全路径文件名>(错误行号) : <错误 类型和错误编号> : <错误内容> 如果不懂错误消息,将光标移动到该错误信息,按F1,就可以显示该错误的帮助信息。 在Output窗口,双击错误或者选择该错误再按ENTER键,系统自动将光标移动到发生错误 的源程序行,你然后就可以改正错误。 9 F4键可以选择并定位下一个错误。 【实例编程】 模拟仿真 在码头酒馆和游船之间搭了一条长20米,宽4米的跳板,醉酒的船员和游客回艇时必须通 过这个跳板。通过跳板时,有三种可能的结果:向前走,回到游船上休息,不再出来;转身回到 酒馆,重新开始喝酒,不再出来;左右乱晃,落入水中淹死。果醉酒者每次走一步,一步走1 米。而且他们向前走的概率是0.7,向左走、向右走和向后走的概率各为0.1。现在假设开始时他 们都是站在酒馆的门口,请编写程序模拟出若干个醉酒者的最终行为结果。 #include #include #include #include using namespace std; const int SHIP=1; const int BAR=2; const int WATER=3; //一个醉酒者行为的模拟仿真 int drunkard() { int x=-10; //记录醉酒者的x坐标,开始时在酒馆门口 int y=0; //记录醉酒者的y坐标,开始时在跳板的中央 int step=0; //记录醉酒者一共走了多少步 while(abs(x)<=10&&abs(y)<=2) { switch(rand()%10) { case 0: //向左走 y=y-1; break; case 1: //向右走 y=y+1; break; case 2: //向后走 x=x-1; break; case 3: //向前走 case 4: case 5: case 6: case 7: case 8: case 9: x=x+1; } step= step +1; } if(x<-10) { cout<<"After "<10) { cout<<"After "<>drunkardnumber; for(int i=0; ii2>i3d2||i1==i2; 11 (g) c1>i1?i1:c2; (h) 0?1:2?0:0?3:4; (i) i1+=i2*=i3; (j) i3=(i1=1,i2--); (k) i1=(c1,c2,c3); (l) !i1&&i2--; 可以使用下面程序框架上机验证。 int main() { char c1=’a’, c2=’B’, c3=’c’; int i1=10, i2=20, i3=30; double d1=0.1, d2=0.2, d3=0.4; 数据类型说明符x; x= (表达式); cout<<”x=”< #include using namespace std; int main() { bool b = true; short s = 3; int i = 1; float f = 1.0; unsigned int ui = 3; cout << "b type: "<< typeid(b).name() << endl; cout << "s type: " << typeid(s).name()<< endl; cout << "i type: " << typeid(i).name()<< endl; cout << "f type: " << typeid(f).name()<< endl; cout << "ui type: " << typeid(ui).name()<< endl; cout << "b + b type: " << typeid(b +b).name() << endl; cout << "'a' + 'b' type: " << typeid('a' + 'b').name() << endl; cout << "s + s type: " << typeid(s + s).name() << endl; cout << "'a' + i + f type: " << typeid('a' + i + f).name() << endl; cout << "'a' + 3.14 type: " << typeid('a' + 3.14).name() << endl; cout << "123 + 123L type: " << typeid(123 + 123L).name() < int main() { const int Total=7; //小孩总数,可以改动。 int ChooseNum; //用户随机选取的数 int boy[Total]; //表示小孩的数组 for(int i=0; i>ChooseNum; //用户随机输入一个剔除的数 cout<<" Before eliminating, the boys are:"< int n = 0; int func(int x = 10); int main() { int a,b; a = 5; b = func(a); cout << "\nlocal a=" << a<< endl << "local b=" << b<>x>>y; cout<=N ) return t; count=1; for(a=i,b=j+1; chess[a+M*b]==t&&b=N) return t; count=1; for(a=i+1,b=j; chess[a+M*b]==t&&a=N) return t; count=1; for(a=i+1,b=j-1; chess[a+M*b]==t&&a=0; a++,b--) count++; if(count>=N) return t; } } return '*'; } 实验七、类和对象 【实验目的】 1、 掌握类和对象的概念、定义和使用方法。 2、 掌握不同特性对象成员的访问方法,以及this指针的概念和使用方法。 3、 掌握构造函数和析构函数的使用方法。 4、 了解友元函数的概念。 【实验内容】 1、下面是一个完整的Person类的定义,分析代码,了解类的定义以及成员函数的定义方 法。 #include #include using namespace std; class Person { private: char m_strName[20]; int m_nAge; int m_nSex; public: Person();//构造函数 Person( const char *name, int age, char sex ); //构造函数 Person( const Person &p ); //拷贝构造函数 ~Person() //析构函数 { cout<<"Now destroying the instance of Person"<ShowPerson(); p1->SetAge( 19 ); cout << "person1: \t"; p1->ShowPerson(); p2=new Person("Zhang3", 19, 'm'); //动态生成一个Person对象 cout << "person2: \t"; p2->ShowPerson(); *p2 = *p1; //对象之间的赋值 cout << "person2: \t"; p2->ShowPerson(); delete p1; //释放p1指针指向对象所占的空间 delete p2; //释放p2指针指向对象所占的空间 return 0; } 2、仿照上面例子,定义一个Dog类。 该类包含name、age、sex、weight等属性,以及对这些属性操作的方法,并测试这个类。 3、上机运行下面程序,掌握const成员函数和const对象。 #include 20 class R { public: R( int r1 = 0 ) : R1( r1 ) {} void print(); void print() const; private: int R1; }; void R::print() { cout<<"In print:"<<" R1 = "<x = " << this->x << "\n(*this).x = " << ( *this ).x << "\nthis = " << this << endl; } int main() { Test testObject( 12 ); testObject.print(); cout << "&testObject = " << &testObject << endl; return 0; } 【实例编程】 实现一个带有头结点的单链表,链表的头结点称为第0个节点,该链表可以插入整型元素。 #include #include using namespace std; class List //定义整型链表类 { private: class Node { public: Node( const int &data = 0, Node *next = NULL ) : m_nData( data ), m_pNext( next ) {} Node *m_pNext;//指向下一个结点的指针成员 int m_nData;//指向本结点数据的指针成员 }; public: List(); //构造函数 ~List(); //析构函数 bool Append( const int &e, int index = 0 );//在inedex位置后增加节点 bool Prepend( const int &e, int index = 1 ); //在inedex位置前增加节点 bool Remove( int &e, int index = 1 ); //删除inedex位置处的节点 22 bool Find( int &e, int index = 1 ); //查找inedex位置处的节点 void PrintList(); //打印链表 protected: Node *m_pFirst; //头节点 }; List::List() //构造函数 { m_pFirst = new Node(); } List::~List() //构造函数 { Node * p = m_pFirst; Node * q; while( p != NULL ) //寻找inedex位置前一个节点 { q = p; p = p->m_pNext; delete q; } } bool List::Append( const int &e, int index )//在inedex位置后增加节点 { if( index < 0 ) { return false; } Node *p = m_pFirst; int i = 0; while( p != NULL && i < index )//寻找inedex位置处节点 { ++i; p = p->m_pNext; } if( p == NULL ) { return false; } Node *q = new Node( e, p->m_pNext ); p->m_pNext = q; return true; } bool List::Prepend( const int &e, int index )//在inedex位置前增加节点 { if( index < 1 ) { return false; } Node *p = m_pFirst; int i = 0; while( p != NULL && i < index-1 ) //寻找inedex位置前一个节点 { ++i; p = p->m_pNext; } if( p == NULL ) { return false; } Node *q = new Node( e, p->m_pNext ); p->m_pNext = q; return true; } bool List::Remove( int &e, int index ) //删除inedex位置处的节点 { if( index < 1 ) { 23 return false; } Node *p = m_pFirst; int i = 0; while( p != NULL && i < index-1 ) //寻找inedex位置前一个节点 { ++i; p = p->m_pNext; } if( p == NULL || p->m_pNext == NULL ) { return false; } Node *q = p->m_pNext; p->m_pNext = q->m_pNext; e = q->m_nData; delete q; return true; } bool List::Find( int &e, int index ) //查找inedex位置处的节点 { if( index < 1 ) { return false; } Node *p = m_pFirst; int i = 0; while( p != NULL && i < index )//寻找inedex位置处节点 { ++i; p = p->m_pNext; } if( p == NULL ) { return false; } e = p->m_nData; return true; } void List::PrintList() //打印链表 { Node *p = m_pFirst->m_pNext; while( p != NULL )//寻找inedex位置处节点 { cout << p->m_nData << '\t'; p = p->m_pNext; } cout << endl; } int main() { List l; l.Append( 1 ); l.Prepend( 10 ); int s ; l.Find( s, 2 ); l.Remove(s, 2 ); l.PrintList(); return 0; } 实验八、继承和派生 【实验目的】 24 1、 掌握继承的概念。 2、 理解派生类与基类的关系。 3、 理解不同的继承类型。 4、 掌握继承下的构造函数和析构函数。 5、 掌握单继承和多继承使用方法。 6、 理解静态成员。 7、 掌握类模版。 【实验内容】 1、上机分析下面程序,理解继承的概念。 #include #include using namespace std; class Person { private: char m_strName[20]; int m_nAge; int m_nSex; public: Person();//构造函数 Person( const char *name, int age, char sex ); //构造函数 Person( const Person &p ); //拷贝构造函数 ~Person() //析构函数 { cout<<"Now destroying the instance of Person"< class A { public: A() { cout<<"Constructor1_A"<< x << endl; } A( int m ) : x( m ) { cout<<"Constructor2_A"<< x << endl; } ~A() { cout<<"Destructor_A"<< x << endl; } private: int x; }; class B : public A { public: B() { cout<<"Constructor1_B"<< y << endl; } B( int m, int n, int l ) : A( m ), a( n ), y( l ) { cout<<"Constructor2_B"<< y < class sample { public: sample ( ){ ++n; } static int HM(){ return n; } ~sample ( ){ --n; } private: static int n; }; int sample::n = 10; int main() { sample c1,c2; sample *p = new sample(); cout< class Shape 28 { public: virtual double Area() const { return 0.0; } // 纯虚函数,在派生类中重载 virtual void PrintShapeName() const = 0; virtual void Print() const = 0; }; #endif // point.h文件 定义类 Point #ifndef POINT_H #define POINT_H #include "shape.h" class Point : public Shape { int x, y; //点的x和y坐标 public: Point( int = 0, int = 0 ); // 构造函数 void SetPoint( int a, int b ); // 设置坐标 int GetX() const // 取x坐标 { return x; } int GetY() const // 取y坐标 { return y; } virtual void PrintShapeName() const { cout << "Point: "; } virtual void Print() const; //输出点的坐标 }; #endif // Point.cpp文件 Point类的成员函数定义 #include #include "point.h" Point::Point( int a, int b ) : x( a ), y( b ) {} void Point::SetPoint( int a, int b ) { x = a; y = b; } void Point::Print() const { cout << '[' << x << ", " << y << ']'; } // circle.h定义类 Circle #ifndef CIRCLE_H #define CIRCLE_H #include #include "point.h" class Circle : public Point { double radius; public: Circle(int x = 0, int y = 0, double r = 0.0); void SetRadius( double r ); //设置半径 double GetRadius() const; //取半径 virtual double Area() const; //计算面积a 29 virtual void Print() const; //输出圆心坐标和半径 virtual void PrintShapeName() const { cout << "Circle: "; } }; #endif // circle.cpp文件 circle类的成员函数定义 #include "circle.h" Circle::Circle(int a,int b,double r): Point(a,b), radius( r ) { } void Circle::SetRadius( double r ) { radius = ( r >= 0 ? r : 0 ); } double Circle::GetRadius() const { return radius; } double Circle::Area() const { return 3.14159 * radius * radius; } void Circle::Print() const { cout << "Center = "; Point::Print(); cout << "; Radius = " << radius << endl; } //main.cpp文件 演示图形类 #include #include "shape.h" #include "point.h" #include "circle.h" void virtualViaPointer( const Shape * ); void virtualViaReference( const Shape & ); int main() { //创建point、circle对象 Point point(30,50); Circle circle(120,80,10.0); //输出point、circle、rectangle对象信息 point.PrintShapeName(); point.Print(); cout << endl; circle.PrintShapeName(); circle.Print(); //定义基类对象指针 Shape *arrayOfShapes[2]; arrayOfShapes[ 0 ] = &point; arrayOfShapes[ 1 ] = &circle; //通过基类对象指针访问派生类对象 cout << "Virtual function calls made off " << "base-class pointers\n"; for ( int i = 0; i < 2; i++ ) virtualViaPointer( arrayOfShapes[ i ] ); cout << "Virtual function calls made off " << "base-class references\n"; for ( int j = 0; j < 2; j++ ) virtualViaReference( *arrayOfShapes[ j ] ); return 0; } //通过基类对象指针访问虚函数实现动态绑定 void virtualViaPointer( const Shape *baseClassPtr ) { baseClassPtr->PrintShapeName(); 30 baseClassPtr->Print(); cout << "Area = " << baseClassPtr->Area() << endl; } //通过基类对象引用访问虚函数实现动态绑定 void virtualViaReference( const Shape &baseClassRef ) { baseClassRef.PrintShapeName(); baseClassRef.Print(); cout << "Area = " << baseClassRef.Area() << endl; } 2、练习动态绑定。 定义一个类Base,该类含有虚函数display,然后定义它的两个派生类FirstB和SceondB,这两个派生类均含有公有成员函数display,再主程序中定义指向基类Base的指针变量ptr,并分别定义Base、FirstB和SceondB的对象,让ptr分别指向这三个对象的地址,然后执行这些对象的display函数,观察结果。 3、上机完成下面试验。 有一个基类名为“形状”、它有派生类“圆”、“正方形”和“长方形”。利用“多态性”的概念,以纯虚函数的形式完成计算“圆”、“正方形”和“长方形”的面积。提示:初始值分别给出:圆的圆心和半径;正方形的中点和一个顶点;长方形的中点和两个顶点。 4、设计一个计算图形面积的类库。 类库的顶层是一个抽象类,并且提供三个纯虚函数;显示数据成员、返回面积和返回体积。 Class Shape { virtual void showData()=0; virtual double reArea()=0; virtual double reVolume()=0; }; 第二层由Shape类派生TwoDimShape(二维图形)和ThreeShape(三维图形),它们增加了有关的数据成员,但没有成员函数的实现。 第三层派生具体的图形类。TwoDimShape类派生Circle(圆)、Elipse(椭圆)、Rectangle(矩形)和Triangle(三角形)等类。ThreeShape类派生Ball(球体)、Cylinder(圆柱体)、RectangularParallelepiped(长方体)等类。 在主函数测试中使用多态方式调用不同对象的求值函数。 实验十、运算符重载和异常 【实验目的】 1、 理解重载运算符的意义。 2、 掌握用成员函数、友元函数重载运算符的特点。 3、 掌握重载运算符函数的调用方法。 4、 理解C++中的异常处理机制。 【实验内容】 1、上机分析下面程序,掌握运算符重载的方法。 #include class Complex { friend Complex operator+( const double &d, const Complex &c ); friend Complex operator-( const double &d, const Complex &c ); double m_fReal, m_fImag; public: Complex( const double &r = 0, const double &i = 0): m_fReal( r ), m_fImag( i ) {} 31 Complex( const Complex &c ): m_fReal( c.m_fReal ), m_fImag( c.m_fImag ) {} double GetReal() const { return m_fReal; } double GetImag() const { return m_fImag; } Complex& operator=( const Complex &c ) { if( this == &c ) { return *this; } m_fReal=c.m_fReal; m_fImag=c.m_fImag; return *this; } Complex operator+( const Complex &c ) { return Complex( m_fReal+c.m_fReal, m_fImag+c.m_fImag ); } Complex operator-( const Complex &c ) { return Complex( m_fReal-c.m_fReal, m_fImag-c.m_fImag ); } Complex operator+( const double &d ) { return Complex( m_fReal+d, m_fImag ); } Complex operator-( const double &d ) { return Complex( m_fReal-d, m_fImag ); } }; Complex operator+( const double &d, const Complex &c ) { return Complex( d + c.m_fReal, c.m_fImag ); } Complex operator-( const double &d, const Complex &c ) { return Complex( d - c.m_fReal, c.m_fImag ); } int main() { Complex c1( 3.3, 4.4 ); Complex c2( 5.5, 2.2 ); Complex c3; c3 = c1 + c2; cout << "C3 = " << c3.GetReal() << "+i" << c3.GetImag() << endl; c3 = c1 - c2; cout << "C3 = " << c3.GetReal() << "+i" << c3.GetImag() << endl; c3 = c1 + c2; cout << "C3 = " << c3.GetReal() << "+i" << c3.GetImag() << endl; c3 = c1 + 1.1; cout << "C3 = " << c3.GetReal() << "+i" << c3.GetImag() << endl; c3 = c1 - 1.1; cout << "C3 = " << c3.GetReal() << "+i" << c3.GetImag() << endl; c3 = 9.9 + c1; cout << "C3 = " << c3.GetReal() << "+i" << c3.GetImag() << endl; c3 = 9.9 - c1; cout << "C3 = " << c3.GetReal() << "+i" << c3.GetImag() << endl; ( c3 = c1 ) = c2; cout << "C3 = " << c3.GetReal() << "+i" << c3.GetImag() << endl; return 0; } 32 注意重载“=”运算符的方法:首先应判断是否是自身赋值,其次应注意返回值是引用,这 是为了支持( c3 = c1 ) = c2这种用法。 2、完成一个类,用来描述时间段,包括小时和分钟,重载各种运算符,完成时间段的加减 以及赋值。 3、上机分析下面程序,理解最基本的异常处理机制。 #include void trigger(int code) { try { if (code==0) throw code; if (code==1) throw 'x'; if (code==2) throw 3.14; } catch(int i) { cout<<"Catch integer "< #include using namespace std; class MatrixException : public logic_error { public: MatrixException(const string& s) : logic_error(s) {} }; class Singular: public MatrixException { public: Singular(const string& s) : MatrixException("Singular: "+s) {} }; class InvalidIndex: public MatrixException { public: InvalidIndex(const string& s) : MatrixException("Invalid index: "+s) {} }; class IncompatibleDimension: public MatrixException { public: IncompatibleDimension(const string& s) : MatrixException("Incompatible Dimensions: "+s) {} }; 33 //头文件Matrix.h #include "MatrixException.h" class Matrix { double* elems; // 存放矩阵中各元素,按行存放 int row, col; // 矩阵的行与列 protected: double rowTimesCol(int i, const Matrix &b, int j ) const; /矩阵的第i行矩阵b的第j列相乘 public: Matrix(int r, int c); Matrix(double* m, int r, int c); Matrix( const Matrix &m ); ~Matrix(); //重载运算符" =",实现矩阵赋值,若进行运算的矩阵维数不同,抛出IncompatibleDimension异常 Matrix& operator =(const Matrix& b) throw(IncompatibleDimension); //重载运算符"( )",用来返回某一个矩阵元素值,若所取矩阵下标非法,抛出InvalidIndex异常 double& operator () (int i, int j) throw(InvalidIndex); const double& operator () (int i, int j) const throw(InvalidIndex); //给矩阵元素赋值,若所设置矩阵元素下标非法,抛出InvalidIndex异常 void SetElem(int i, int j, double val) throw(InvalidIndex); //重载运算符"*",实现矩阵相乘, //若前一个矩阵的列数不等于后一个矩阵的行数,抛出IncompatibleDimension异常 Matrix operator *(const Matrix& b) const throw(IncompatibleDimension); //重载运算符" +",实现矩阵相加,若进行运算的矩阵维数不同,抛出IncompatibleDimension异常 Matrix operator +(const Matrix& b) const throw(IncompatibleDimension); //重载运算符" -",实现矩阵相减//若进行运算的矩阵维数不同,抛出IncompatibleDimension异常 Matrix operator -(const Matrix& b) const throw(IncompatibleDimension); void Print() const; //按行显示输出矩阵中各元素 }; //成员函数的定义文件Matrix.cpp #include #include #include #include "Matrix.h" using namespace std; string int2String(int i) //将整型数转换为String类型 { char buf[64]; ostrstream mystr(buf, 64); mystr << i << '\0'; return string(buf); } Matrix::Matrix(int r, int c) { if ( r > 0 && c > 0 ) { row = r; col = c; elems = new double[r * c]; //为矩阵动态分配存储 } else { elems = NULL; row=col=0; } } Matrix::Matrix( double* m, int r, int c ) { if ( r > 0 && c > 0 ) { row = r; col = c; elems = new double[r * c]; } else { 34 elems = NULL; row=col=0; } if ( elems != NULL ) { for (int i=0; i < r*c; i++) { elems[i] = m[i]; } } } Matrix::Matrix( const Matrix &m ) : row( m.row ), col( m.col ) { if ( NULL == m.elems ) { elems = NULL; } else { int total = row*col; elems = new double[total]; for( int i = 0; i < total; ++i ) { elems[i] = m.elems[i]; } } } Matrix::~Matrix() { delete []elems; //释放矩阵所占的存储 } Matrix& Matrix::operator =(const Matrix& b) throw(IncompatibleDimension) { if( this == &b ) { return *this; } if ( col != b.col || row !=b.row ) { throw( IncompatibleDimension(" Matrix "+int2String(row) + " x " + int2String(col) + " equails matrix " + int2String(b.row) + " x " + int2String(b.col)+".") ); } row = b.row; col = b.col; delete []elems; if ( NULL == b.elems ) { elems = NULL; } else { int total = row*col; elems = new double[total]; for( int i = 0; i < total; ++i ) { elems[i] = b.elems[i]; } } return *this; } //重载运算符"( )"可以由给出的矩阵行列得到相应的矩阵元素值 //之所以重载"( )"而不是"[]",是因为避免数组elems所造成的二义性 double& Matrix::operator () (int r, int c) throw(InvalidIndex) { if ( r<0 || r>=row || c<0 || c>=col ) 35 { throw( InvalidIndex(string("Get Element(") + int2String(r) + "," + int2String(c) + ")" + " from (" + int2String(row) + " x " + int2String(col) + ")" + " matrix." ) ); } return elems[r*col+c]; } const double& Matrix::operator () (int r, int c) const throw(InvalidIndex) { if ( r<0 || r>=row || c<0 || c>=col ) { throw( InvalidIndex(string("Get Element(") + int2String(r) + "," + int2String(c) + ")" + " from (" + int2String(row) + " x " + int2String(col) + ")" + " matrix." ) ); } return elems[r*col+c]; } void Matrix::SetElem(int r, int c, double val) throw(InvalidIndex) { if ( r<0 || r>=row || c<0 || c>=col ) { throw(InvalidIndex(string("Set Element(") + int2String(r) + "," + int2String(c) + ")" + " for (" + int2String(row) + " x " + int2String(col) + ")" + " matrix." ) ); } elems[r*col+c] = val; } Matrix Matrix::operator*(const Matrix& b) const throw(IncompatibleDimension) { if ( col != b.row ) // incompatible dimensions { throw(IncompatibleDimension(" Matrix "+int2String(row) + " x " + int2String(col) + " times matrix " + int2String(b.row) + " x " + int2String(b.col)+".")); } Matrix ans(row, b.col); for (int r=0 ; r < row ; r++) { for (int c=0 ; c < b.col; c++) { ans.SetElem(r, c, rowTimesCol(r, b.elems, c, b.col)); } } return ans; } Matrix Matrix::operator +(const Matrix& b) const throw(IncompatibleDimension) { if ( col != b.col || row !=b.row ) { throw(IncompatibleDimension(" Matrix "+int2String(row) + " x " + int2String(col) + " adds matrix " + int2String(b.row) + " x " + int2String(b.col)+".")); } Matrix anx(row, col); for (int r=0 ; r < row ; r++) { for (int c=0 ; c < col; c++) { ans.SetElem(r, c, elems[r*col+c]+b.elems[r*col+c]); } } return ans; } Matrix Matrix::operator -(const Matrix& b) const throw(IncompatibleDimension) { 36 if ( col != b.col || row !=b.row ) { throw( IncompatibleDimension(" Matrix "+int2String(row) + " x " + int2String(col) + " minus matrix " + int2String(b.row) + " x " + int2String(b.col)+".") ); } Matrix ans(row, col); for (int r=0 ; r < row ; r++) { for (int c=0 ; c < col; c++) { ans.SetElem(r, c, elems[r*col+c]-b.elems[r*col+c]); } } return ans; } void Matrix::Print() const { for (int i = 0; i < row; i++) { for (int j = 0; j < col-1; j++) { cout << elems[i*col+j] << "\t"; } cout << elems[i*col+col-1]; cout< #include "Matrix.h" using namespace std; int main() { try { //创建矩阵对象 double a[20]= {1.0, 3.0, -2.0, 0.0, 4.0, -2.0, -1.0, 5.0, -7.0, 2.0, 0.0, 8.0, 4.0, 1.0, -5.0, 3.0, -3.0, 2.0, -4.0, 1.0}; double b[15]= {4.0, 5.0, -1.0, 2.0, -2.0, 6.0, 7.0, 8.0, 1.0, 0.0, 3.0, -5.0, 9.0, 8.0, -6.0}; Matrix x1(a, 4, 5); cout<<"the matrix of x1 is:"<ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); 这个主窗口就是整个应用程序的框架窗口。它也是构成文档模板的三要素之一的框架窗口。在HelloMFC程序一启动时,就已经创建了一个文档,因此,该文档对应的框架窗口也自动打开。 (4) 了解了应用程序框架后,打开你应用程序所在的目录,查看一下该目录下都有哪些文件。下面的一段文字介绍这些文件的含义。看看你已经了解了多少,AppWizard自动生成的文件有: 项目文件 helloMFC.DSW工作台文件 helloMFC.OPT工作台选项文件,存放关于工作台的所有选项(如工作台布局) helloMFC.DSP项目文件。存放特定于项目的内容,包括项目中包含的文件、编译方式、连接选项等等。与.mak文件的作用相同 C++源文件和头文件: helloMFC.cpp.helloMFC.h项目的主要源文件,该文件中创建类CHelloMFCApp的实例,并重载其成员函数InitInstance。对于可执行程序,CHelloMFC::InitInstance做以下事情:登记文档模板(作为文档和视图之间连接的机制)、创建主框架窗口、创建一个空文档(或如果在命令行指定了一个文档,则打开一个已有文档)。 helloMFCDoc.cpp,helloMFCDoc.h实现了文档类CHelloMFCDoc,该类从类CDocument派 41 生而来,可以完成文档的存取、修改等操作。文档内容的显示通过与文档相联系的类CHelloMFCView的对象完成。 helloMFCView.cpp, helloMFCView.h实现了视图类CHelloMFCView,视图类用于显示和打印文档数据。CHelloMFCView可以从类CEditView, CFormView, CRecordView, CDaoRecordView, CTreeView, CListView, CRichEditView, CScrollView,或CView派生而来。这个项目中的CHelloMFCView从类CView派生而来。该类中实现了一些框架性函数,包括绘制视图函数、调试诊断语句,如果选择打印支持,则还实现关于打印、打印设置、打印预览等命令处理。 MainFrm.cpp,MainFrm.h实现了从类CMainFrame派生而来的类CFrameWnd (SDI应用程序) 或CMDIFrameWnd (MDI应用程序),该类负责处理工具条和状态条的创建。 StdAfx.cpp,StdAfx.h预编译头文件,用于建立预编译头文件helloMFC.PCH和预编译类型文件STDAFX.OBJ 资源文件 helloMFC.rc, resource.h项目的资源文件及其头文件。资源文件中包含缺省的菜单定义和加速器、字符串表等。还有一个缺省的About对话框和一个icon。资源文件中还包含了标准的MFC资源AFXRES.RC。如果有工具条支持,则还有一个工具条位图文件 (RES\TOOLBAR.BMP). helloMFC.ico项目的图标文件,在应用程序变为最小或在对话框中可以出现图标。 helloMFC.ic2用于存放那些不是由Developer Studio编辑的资源。 helloMFCDoc.ico 项目中文档的图标文件。 RES\Toolbar.bmp工具条位图 文本文件 readme.txt描述项目下由系统的AppWizard或ControlWizard.自动产生的各个文件的含义。 3、学习使用画笔和画刷 前面你已经了解了Windows 应用程序的基本结构,知道AppWizard为你生成的文件的作用。这个实验中,你将尝试在这个程序框架上加上自己的应用逻辑:在视图中画个矩形或是椭圆。这里涉及到Windows程序如何输出信息。Windows程序使用“设备上下文(Device Context)”来向输出设备(显示器、打印机等)输出文字、图形信息。 设备上下文,简称为DC,是由Windows程序保存的一个结构,该结构里存储着程序向设备显示输出时所需要的设备信息,包括图形对象以及它们相关的属性和输出的图形模式。DC是图形设备接口(GDI)的重要组成部分,在使用任何GDI输出函数之前,你必须建立一个设备上下文。使用设备上下文的最大好处是硬件无关性。因为所有的输出都通过DC进行,程序不需要关心DC对应的具体输出设备。 与DC关联的图形对象有画笔、画刷、位图、字体、调色板等。在需要用输出某种图形对象以前,需要先将它与一个设备上下文关联起来,然后通过设备上下文来输出。 在Visual C++中,总是通过MFC类来访问设备上下文。这些类封装了DC数据结构,并提供一些有用的功能来简化应用程序。CDC是所有设备上下文类的基类,在实验一中我们修改了函数CHelloMFCView::OnDraw(),该函数用于视图窗口在它的窗口区输出内容,其中就用到了CDC: void CHelloMFCView::OnDraw(CDC* pDC) { CHelloMFCDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here pDC->TextOut(50,50,"Hello,World!"); } 在OnDraw函数调用前,MFC框架结构就建立好了OnDraw函数所用的设备上下文,并且将它作为参数传递给OnDraw函数,OnDraw函数然后就可以利用这个pDC进行输出。大多数需 42 要设备上下文的函数都需要用DC作为函数参数。 画笔和画刷是常用的两种GDI对象,画笔是WindowsGDI提供的用来绘制直线和图形的对象,它的作用就想我们通常使用的笔,可以用它绘制直线、正方形、矩形、圆等基本的图形。构造画笔时至少要指定三个属性:画笔的类型(画实线、虚线还是点划线等)、宽度和颜色。Windows中提供的画笔类是CPen,你可以构造这个类的对象来创建自己的画笔。 画刷是Windows程序中用来填充一个空间、窗体或其他与区域有关的GDI对象。它主要用来对一个区域着色。画刷具有颜色、图案、填充类型等各种属性。在构造画刷对象时,你至少需要指明画刷的颜色。Windows中提供的画刷类是CBrush,你可以构造这个类的对象来创建自己的画刷。 4、改进验十一中生成的HelloMFC应用程序 下面是在CHelloMFCView::OnDraw()函数中使用画笔和画刷的例子,把这些代码加到你的程序中,运行它,看看运行结果是什么样的, void CHelloMFCView::OnDraw(CDC* pDC) { CHelloMFCDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); //用缺省画笔画十个椭圆 for(int i = 1; i < 20; i+=2) pDC->Ellipse(50+i,50+i,100+i,100+i); //建立一个画笔对象,可以画红色的宽度为1个象素的实线 CPen aPen(PS_SOLID,1,RGB(255,0,0)); //将画笔对象选进设备上下文 CPen *pOldPen = pDC->SelectObject(&aPen); //用选定画笔画四条直线,构成一个矩形 pDC->MoveTo(10,10); pDC->LineTo(50,10); pDC->LineTo(50,50); pDC->LineTo(10,50); pDC->LineTo(10,10); //恢复原来的画笔对象 pDC->SelectObject(pOldPen); //建立一个绿色的画刷对象 CBrush brBackGround(RGB(0,255,0)); //将该对象选进设备上下文 CBrush *pOldBrush = pDC->SelectObject(&brBackGround); //在规定范围内画一个填充椭圆 CRect rcEllipse(100,100,15,200); pDC->Ellipse(rcEllipse); //恢复原来的画刷对象 pDC->SelectObject(pOldBrush); } 5、编制消息处理函数。 利用ClassWizard编制消息处理函数参看教材。 6、在教材例11-7的基础上增加用鼠标右键删除泡泡的功能。 7、重新编写一吹泡泡程序,用鼠标右键生成泡泡,鼠标左键移动泡泡的位置。 43 44
本文档为【C++与面向对象程序设计教程实验】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_769254
暂无简介~
格式:doc
大小:246KB
软件:Word
页数:104
分类:互联网
上传时间:2017-10-24
浏览量:12