Visual C++ 2010程序设计案例教程(txt+pdf+epub+mobi电子书下载)


发布时间:2020-07-03 22:39:15

点击下载

作者:刘冰,张林,蒋贵全

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Visual C++ 2010程序设计案例教程

Visual C++ 2010程序设计案例教程试读:

前言

作为新一代开发工具,Visual Studio 2010能够帮助开发团队在最新的平台上构建具有更佳用户体验的应用程序,进行灵活快速开发,实现生产效率新突破,并能使开发团队更好地进行协作。Visual Studio 2010通过增强编译器后端的代码生成功能来提高生成应用程序的编译速度、质量和性能;在基于Visual Studio 2010的Visual C++ 2010开发平台中,解决方案和项目的构建系统(build system)从原先基于VCBuild的构建系统,迁移到基于MSBuild(Microsoft Build Engine)的构建系统,MSBuild的加入使得“一次编码,多个平台运行”成为可能;Microsoft Visual Studio Team System 2010提供完整的工具套件和统一的开发过程,适用于任何规模的开发团队,帮助所有团队成员提高自身技能,使得开发人员、设计人员、测试人员、架构师和项目经理更好地协同工作,缩短软件或解决方案的交付时间。

本书共分10章,在讲解Visual C++语法的基础上,通过案例介绍面向对象的程序设计方法。第1章主要对Visual C++ 2010的新特征和Visual Studio 2010集成开发环境进行概述;第2章介绍Visual C++ 2010开发环境以及如何创建第一个MFC应用程序和控制台应用程序;第3章介绍函数和编译预处理、C++的对象、C++的类、构造函数与析构函数等内容;第4章介绍C++的基本数据类型、标识符和关键字、运算符和表达式等内容;第5章介绍MFC应用程序基本框架以及MFC应用程序中包含的MFC类,如应用程序类CWinApp、主框架类CFrameWnd、视图类CView、文档类CDocument、对话框类CDialog、菜单类CMenu和线程基类CWinThread;第6章介绍菜单的设计、菜单编程、工具栏设计、状态栏设计等内容;第7章介绍对话框的设计,静态控件、编辑框、按钮、列表框、组合框和滚动条等标准控件的使用,以及旋转按钮、进度条、滑块、属性页控件、树形控件等公共控件的使用;第8章介绍图形设备接口、绘图环境、画笔和画刷、文本与字体等内容;第9章介绍打印编程和数据库编程等内容;第10章对图书信息管理系统进行综合示例分析。

本书的编者都是长期在高校从事软件教学的教师,有丰富的教学经验和科研开发能力。另外,在编写本书的过程中编者还参阅了大量国内外有关C++程序设计的教材和资料。本书的顺利出版,要感谢重庆邮电大学计算机科学与技术学院的相关领导和老师给予的大力支持和帮助,还要感谢计算机教育界许多同行的关心。

为方便教师,本书有配套电子教案和习题答案,如有需要可与编者联系(cobly1837@sina.com)或登录华章网站(www.hzbook.com)下载。

目前,国内外有关Visual C++方面的资料很多,新理论、新技术层出不穷。由于Visual C++程序设计方法、设计思想发展迅速,加上时间仓促,编者水平有限,书中难免存在不妥和错误之处,恳请读者批评指正,并提出宝贵意见,以便进一步完善。

感谢您阅读本书,请将您的宝贵建议和意见发送至:liubing@cqupt.edu.cn。

教学建议

第1章

Visual C++ 2010开发平台概述

1.1 Visual C++ 2010概述

Visual C++ 2010开发环境为项目管理与配置(包括更好地支持大型项目)、源代码编辑、源代码浏览和调试工具提供强大的支持,是开发过程中不可缺少的工具,是提高代码生产力的基本保障。

在Visual C++ 2010中,增强的MFC为程序员开发出环境优美、安全稳定的应用程序奠定了坚实的基础。Visual C++ 2010中的MFC新功能包括:(1)便于生成Windows 7应用程序

Visual Studio 2010提供了为本机Windows API编写代码所需的Windows SDK组件。此外该版本的Visual Studio还可以在增强的MFC的帮助下更轻松地编写Windows应用程序。可通过MFC库访问主要的Windows 7功能,而不必直接写入本机API。只需重新编译,现有的MFC应用程序就可以在Windows 7上运行使用,而且新应用程序可以充分利用新增的功能。(2)增加了重新启动管理器

对于大多数的程序编写者来说,可能遇到过由于应用程序的意外关闭或重新启动,将花了很大功夫编写的文档化为乌有的情况,这是很郁闷的事情。在Visual C++ 2010中增加了重新启动管理器的功能,一旦遇到上述情况,便可以恢复到发生意外情况时的状态,不至于让自己的工作成果因为故障而丢失。

重新启动管理器是Windows Vista中引入的一项有用的功能,可以使应用程序在终止前执行保存操作。应用程序可以调用此功能,然后在重新启动时还原其状态。在Visual C++ 2010中,可以在MFC应用程序中充分利用重新启动管理器,更妥善地处理应用程序崩溃和重新启动的情况。使用重新启动管理器时,分两种情况:一是向现有的应用程序中添加重新启动管理器;二是在新创建的MFC应用程序中使用此功能。(3)使用任务对话框

为了改善用户体验,在Visual C++ 2010中,使用任务对话框(task dialog)代替原先广泛使用的消息框(message box)。与消息框相比,任务对话框不仅可以向用户显示消息,还可以显示自定义的按钮、命令行选项以及更加丰富的辅助信息等。新增的CTaskDialog类提供了很多简单实用的函数,可以轻松上手,使用任务对话框来改善应用程序的用户体验,使自己的应用程序的界面风格与Vista系统保持一致。1.2 Visual Studio 2010集成开发环境1.2.1 安装Visual Studio 2010

Visual C++ 2010是Visual Studio 2010的一部分。正如Windows 7有旗舰版、家庭高级版、家庭初级版一样,Visual C++ 2010也有更多的子版本,本书选择的是旗舰版,旗舰版的功能最全面。

Visual Studio 2010具体安装步骤如下:

1)将下载的ISO文件装入虚拟光驱,运行“Autorun.exe”程序,开始Visual Studio 2010的第一步,如图1-1所示。图 1-1 启动安装界面

2)复制安装过程中需要的文件。

3)正式开始安装,单击“下一步”按钮,如图1-2所示。图 1-2 Visual Studio 2010安装向导界面

4)选择“我已阅读并接受许可条款”单选按钮,单击“下一步”按钮,如图1-3所示。图 1-3 Visual Studio 2010安装起始页界面

5)选择完全安装或者自定义安装,完全安装需要7.5G的磁盘空间,如图1-4所示。图 1-4 Visual Studio 2010安装选项页界面

6)选择要安装的功能和安装路径,如图1-5所示。图 1-5 选择安装功能及安装路径页面

7)开始安装Visual Studio组件,如图1-6所示。图 1-6 Visual Studio 2010安装组件页面

8)看到图1-7就意味着Visual Studio 2010安装完成。图 1-7 Visual Studio 2010安装完成界面1.2.2 配置Visual Studio 2010

1)第一次运行Visual Studio 2010需要进行环境设置,启动Visual Studio 2010旗舰版,如图1-8所示。图 1-8 启动Visual Studio 2010运行环境设置界面

2)常见的设置。通过菜单“工具→选项”调出“选项”对话框,选择“文本编辑器”下方的“所有语言”,勾选“行号”复选框,如图1-9所示。图 1-9 “选项”对话框

3)如果想调整字体或者选择颜色,可以在“选项”对话框中单击“环境”下方的“字体和颜色”,出现如图1-10所示对话框,并在其中进行选择。图 1-10 字体和颜色调整选项

4)单击工具栏中的空白区域,把生成工具栏调出来,如图1-11所示。图 1-11 生成工具栏

这样就可以直接在工具栏上面选择编译项目、编译整个解决方案、运行程序和调试程序了。

选择生成工具栏旁边的小三角形可以自定义,还可以添加一些按钮。

5)单击自定义界面下面的添加按钮就可以添加新的按钮了,现在把“开始执行(不调试)”添加到工具栏中,如图1-12所示。图 1-12 自定义对话框1.2.3 解决方案和项目

Visual Studio 2010集成开发环境(IDE)提供了一组工具,可帮助编写和修改代码,以及检测和更正错误。

在使用Visual Studio 2010编写Visual C++程序的过程中,第一个任务是选择项目的类型。对于每个项目类型,Visual Studio 2010均会进行编译器设置,并会生成起始代码。下面我们将创建一个基本程序,该程序跟踪有多少个玩家正在玩不同的纸牌游戏。

1.创建项目

1)在“文件”菜单上选择“新建”,再单击“项目”。

2)在“项目类型”区域中,单击“Visual C++ 2010”。然后,在“Visual Studio 2010已安装的模板”窗口中,单击“Win32控制台应用程序”。

3)输入项目名称。对于此示例,项目名称请输入game。

当创建项目时,Visual Studio 2010会将该项目放入一个解决方案。默认情况下,解决方案的名称与项目名称相同。可以接受默认位置、输入一个不同的位置或者浏览到要保存项目的目录。单击“确定”按钮启动“Win32应用程序向导”。

4)在“Win32应用程序向导”的“概述”页上,单击“下一步”按钮。

5)在“应用程序类型”下的“应用程序设置”页,选择“控制台应用程序”。在“附加选项”下选择“空项目”。单击“完成”按钮。

现在有了项目,但项目还没有源代码文件。在此,将向项目中添加一个类,并且Visual Studio 2010将添加.h和.cpp文件。然后,在测试类的主程序中的项目上添加一个新的源代码文件。

2.向项目添加类

1)如果未显示“解决方案资源管理器”,请在“视图”菜单上选择“解决方案资源管理器”。

2)在“解决方案资源管理器”中,右击“头文件”文件夹,选择“添加”,然后单击“类”。

在“Visual C++ 2010”类别中,单击“C++ 2010”,在“Visual Studio 2010已安装的模板”区域中单击“C++ 2010类”,然后单击“添加”按钮。

3)在“一般C++类向导”中,输入Cardgame作为“类名”,并接受默认的文件名和设置。单击“完成”按钮。

4)对已在编辑区域中打开的Cardgame.h文件进行以下更改:

①在类定义的左大括号之后添加两个私有数据成员。

int players;

static int totalparticipants;

②添加一个采用类型为int的参数之一的公共构造函数原型。

Cardgame(int p);

③删除Visual Studio生成的默认构造函数。默认构造函数是没有参数的构造函数,该默认构造函数类似于:

Cardgame(void);

5)在对Cardgame.h文件进行更改之后,该文件应类似于:

#pragma once

class Cardgame

{

int players;

static int totalparticipants;

public:

Cardgame(int p);

~Cardgame(void);

};

#pragma once行指明编译器只包含该文件一次。

6)双击“源文件”文件夹中的Cardgame.cpp,将其打开以进行编辑。

7)在#include“Cardgame.h”之后,添加以下各行:

#include <iostream>

using namespace std;

8)为采用一个int参数的构造函数添加代码。

Cardgame:Cardgame(int p)

{

players=p;

totalparticipants+=p;

cout<<p<<"players have started a new game.There are now"

<<totalparticipants<<"players in total."<<endl;

}

开始输入“pl”或“to”时,可以按“Ctrl+空格键”,以便自动完成输入“players”或“totalparticipants”的操作。

9)删除Visual Studio生成的以下默认构造函数:

Cardgame:Cardgame(void);

10)在对Cardgame.cpp文件进行更改之后,该文件应类似于:

#include "Cardgame.h"

#include <iostream>

using namespace std;

Cardgame:Cardgame(int p)

{

players=p;

totalparticipants+=p;

cout<<p<<"players have started a new game.There are now"

<<totalparticipants<<"players in total."<<endl;

}

Cardgame:~Cardgame(void)

{}

3.添加新源文件

现在,为测试类的主程序添加一个源代码文件。

1)在“解决方案资源管理器”中,右击“源文件”文件夹,选择“添加”,然后单击“新建项”。在“Visual C++”类别中,选择“代码”,然后单击“C++文件(.cpp)”。

2)输入testgames作为名称,然后单击“添加”。

3)在testgames.cpp编辑窗口中,输入以下代码。

#include "Cardgame.h"

int Cardgame:totalparticipants=0;

int main()

{

Cardgame *bridge=0;

Cardgame *blackjack=0;

Cardgame *solitaire=0;

Cardgame *poker=0;

bridge=new Cardgame(4);

blackjack=new Cardgame(8);

solitaire=new Cardgame(1);

delete blackjack;

delete bridge;

poker=new Cardgame(5);

delete solitaire;

delete poker;

return 0;

}

4)在“生成”菜单上,单击“生成解决方案”。

如果在“生成”菜单上显示输出结果,这表示项目已编译,并且未发生错误。如果未显示输出,将代码与前面步骤中提供的代码进行比较。1.2.4 生成和调试工具

生成和调试是开发可靠的应用程序、组件和服务的关键活动。通过使用Visual Studio 2010中的工具,能够控制生成、有效地发现和消除错误,以及通过多种方式对生成进行测试。

Visual Studio 2010提供了一些用于在生成应用程序时对其进行测试和调试的工具。创建项目时,将定义默认的项目配置并分配默认的解决方案生成配置,以便提供生成上下文。我们可以编辑这些默认配置,并通过保存这些修改而创建新的配置。

下面介绍具体的生成和调试步骤。

1.在应用程序开发过程中生成

解决方案及其各个项目通常在“调试”(Debug)版本中生成并测试。开发人员将反复编译“Debug”版本(在开发过程的每一步都将进行此操作)。调试过程分为两步:首先,纠正编译时错误,这些错误可以包含不正确的语法、拼错关键字和键入不匹配;接下来,使用调试器检测并纠正在运行时检测到的逻辑错误和语义错误等问题。

在项目或解决方案完全开发并充分调试后,在“发布”(Release)版本中编译其组件。默认情况下,“Release”版本使用各种优化。经过优化的版本被设计为比未经优化的版本小且运行速度更快。

使用“配置管理器”对话框定义项目配置,项目配置是每个受支持的版本和平台(例如,Release Win32)组合的属性集。可以创建自己的特殊版本,如供测试人员使用的QA(Quality Assurance,品质保证)生成配置,或者用于试验某些初级代码的个人生成配置。然后,可以使用“项目设计器”修改每个版本和平台组合的设置。

使用“解决方案属性页”对话框定义解决方案的属性。通用属性包含启动项目和项目依赖项的设置。配置属性包含列出各种可用的项目配置和平台的下拉菜单,以及用于选择要生成和部署(如果已启用)的项目的复选框。项目配置和所选平台的组合决定要使用的项目生成配置。

使用“标准”工具栏中的“解决方案配置”下拉列表,选择活动的解决方案生成配置并打开“配置管理器”对话框。也可以通过从“生成”菜单中选择“配置管理器”来访问“配置管理器”。

2.使用IDE修复编译错误

在本步骤中,故意在代码中引入一个Visual C++语法错误,以了解什么是编译错误,以及如何修复它。编译项目时,会显示错误消息以指示所发生问题的性质和位置。

1)在testgames.cpp中,删除最后一行中的分号,使代码如下所示:

return 0

2)在“生成”菜单上,单击“生成解决方案”。

3)“输出”窗口中显示一条消息,指示生成项目失败。单击“输出”窗口中的“转到下一条消息”按钮(指向右方的绿色箭头)。在“输出”窗口中的错误消息和状态栏区域,指示右大括号前缺少一个分号。若要查看有关错误的更多帮助信息,请突出显示错误,并按F1键。

4)将分号重新添加到导致语法错误的行的末尾,代码如下:

return 0;

5)在“生成”菜单上,单击“生成解决方案”。“输出”窗口中显示一条消息,指示项目已正确编译。

3.调试项目

1)在“视图”菜单上,单击“类视图”,或者单击“解决方案资源管理器”窗口中的“类视图”选项卡。展开“game”项目树并单击“Cardgame”类。下方的区域显示类的成员和方法。右击“~Cardgame(void)”析构函数并单击“转到定义”。

2)要在Cardgame终止时减少totalparticipants,请在Cardgame:~Cardgame析构函数的左大括号和右大括号之间输入以下代码:

totalparticipants-=players;

cout<<players<<"players have finished their game.There are now"

<<totalparticipants<<"players in total."<<endl;

3)进行更改后,Cardgame.cpp文件应如下所示:

#include "Cardgame.h"

#include <iostream>

using namespace std;

Cardgame:Cardgame(int p)

{

players=p;

totalparticipants+=p;

cout<<players<<"players have started a new game.There are now"

<<totalparticipants<<"players in total."<<endl;

}

Cardgame:~Cardgame(void)

{

totalparticipants-=players;

cout<<players<<"players have finished their game.There are now"

<<totalparticipants<<"players in total."<<endl;

}

4)在“生成”菜单上,单击“生成解决方案”。

5)在“调试”菜单上,单击“启动调试”或按F5键,以“调试”模式运行该程序。程序将在第一个断点处暂停。

6)在“调试”菜单上,单击“逐过程”或者按F10键逐句调试程序。

注意:执行每个Cardgame构造函数后,totalparticipants的值会增大。而在删除每个指针(并调用析构函数)后,totalparticipants的值会减小。

7)单步执行至程序的最后一行。恰好在执行return语句之前,totalparticipants=0。继续逐句执行程序,直到程序退出;或者在“调试”菜单中单击“继续”,或按F5键允许程序继续运行,直到退出。1.2.5 部署工具

Visual Studio 2010改变了依赖于Visual C++库的应用程序的发布方式。依赖于Visual C++库的应用程序不再需要Fusion(WinSxS)Manifest,这意味着当我们将应用程序部署到一个本地文件夹时,将不再需要众多的小Manifest。另外,Visual C++ 2010也同样支持之前的各种部署机制,这些过去常用的方法在System32目录下安装Visual C++库。总之,Visual C++程序的发布与部署将更加简单。

首先,生成前面项目的Release文件,具体方法是选中解决方案,修改配置管理器中的配置为“Release”,然后单击“生成解决方案”即可。接着,在前面创建的解决方案中,添加“安装和部署”项目,步骤如下:

1)选择“文件→新建→项目”,打开“新建项目”窗体。

2)选择“安装和部署→Visual Studio Installer→安装项目”,单击“确定”。

3)选中“Setup1”,单击右键,选择“添加→项目输出”。

4)在“添加项目输出组”中选择“主输出”,配置选择“Release Win32”。

5)单击“重新生成”,即可产生相应文件,将Setup1.msi和setup.exe复制到第二台计算机上,按照安装向导提示的步骤完成安装。

如果将应用程序部署到应用程序本地文件夹,只需生成Release文件,然后复制WinFormDemo和C运行库(CRT)文件、mfc100u.dll和msvcr100.dll。1.2.6 Ribbon界面设计可视化

在Visual C++6.0开发里面,Ribbon界面比较简单。尽管在Visual C++2008里面对Ribbon功能有所改善,但是仍不能进行可视化设计,Visual C++ 2010新增了Windows 7的风格,同时最大的革新就是实现了可视化设计,很容易设计出漂亮的程序界面。

下面我们体验一下Visual C++ 2010界面可视化设计的特性。具体操作步骤如下:

1)打开Microsoft Visual Studio 2010,单击“文件→新建→项目”,打开“新建项目”窗体。

2)在“新建项目”窗体中,选择“Visual C++”节点中的“CLR”,然后在“模板”窗体中选择“Windows窗体应用程序”。名称输入“WinFormDemo”。

3)随即打开Windows窗体设计器,出现Form1窗体。

4)设置窗体属性:Text为WinFormDemo;添加一个Label、一个Button和一个DateTimePick-er,具体如表1-1所示。

5)选中dtpSelected,为其添加ValueChanged事件,输入如下代码:

labMessage->Text=String:Format("您选择的日期是:{0}",dtpSelected->Text);

6)双击btnExit,输入代码:

Application:Exit();

7)按F5键运行,结果如图1-13所示。图 1-13 运行结果1.2.7 重新启动管理器

Visual C++ 2010新增了重新启动管理器功能。重新启动管理器是Visual Studio for Windows Vista的一项新增功能,增加了在应用程序意外关闭或重新启动的情况下对应用程序的支持。重新启动管理器的行为与应用程序的类型有关,如果是文档编辑器之类的应用程序,重新启动管理器让应用程序器能够自动保存已经打开的文档的状态和内容,在程序异常的时候,能够保存运行时的数据,自动恢复到未发生异常时的情况,从而提高了程序的稳健性与可靠性。如果应用程序不是文档编辑器,则重新启动管理器将重新启动应用程序,但默认情况下无法保存应用程序的状态。

重新启动后,根据不同的应用程序,有任务对话框、Windows消息框等消息提示框,供用户选择是否还原到自动保存前的状态,如果用户选择不还原,重新启动管理器将丢弃临时保存的文件。

向现有应用程序中添加对重新启动管理器支持的具体步骤是:

1)在Visual Studio 2010中打开一个现有WinFormDemo应用程序。

2)打开主应用程序的源文件。默认情况下,此文件是与应用程序同名的.cpp文件。例如,WinFormDemo的主应用程序源文件是WinFormDemo.cpp。

3)查找主应用程序的构造函数。例如,如果项目为MyProject,则构造函数为:

CWinFormDemoApp:CWinFormDemoApp()

4)将以下代码行添加到构造函数中:

m_dwRestartManagerSupportFlags=AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTSL;

5)确保应用程序的InitInstance方法调用其父级InitInstance方法:CWinApp:InitInstance或CWinAppEx:InitInstance。InitInstance方法负责检查m_dwRestartManagerSupportFlags参数。

6)编译并运行应用程序。1.3 本章小结

在Visual C++ 2010中,提供了对新标准C++0x的支持。本章从Lambda表达式、auto关键字、static_assert声明和右值(Rvalue)引用四个方面进行了详细介绍,这些特性增强了代码的简洁性,同时有助于提高代码效率和性能,并从Visual C++ 2010便于生成Windows 7应用程序、增加了重新启动管理器、使用任务对话框三个方面介绍了Visual C++ 2010下MFC的新功能。

最后详细介绍了Visual Studio 2010的安装过程、配置环境、解决方案、生成和调试以及部署工具等内容。1.4 习题

1.Visual C++ 2010的新特性有哪些?

2.简述Visual C++ 2010的配置环境和安装步骤。

3.如何进行Ribbon界面的设计可视化?

4.阐述向现有应用程序中添加对重新启动管理器支持的具体步骤。

第2章

Visual C++ 2010 MFC程序设计快速入门

2.1 Visual C++ 2010开发环境概述

Visual C++ 2010虽然被集成在Visual Studio 2010之中,但是可以单独安装使用。

目前有四种最新版本:

·Visual C++ 2010 Express

·Visual C++ 2010 Standard(标准版)

·Visual C++ 2010 Professional(专业版)

·Visual C++ 2010 Team System(团队系统版)

Visual Studio 2010不仅仅是一个开发工具,它也集成了大量的测试工具,是一个完整的开发平台。在Visual Studio 2010中,我们可以创建面向C++的测试项目来完成测试驱动开发流程中的测试环节,从而让整个测试驱动开发过程都在Visual Studio 2010中进行,让测试和开发做到无缝衔接,而测试也真正地驱动了开发。

为了让大家更加了解如何在Visual Studio 2010中进行面向C++的测试驱动开发,我们来看一个实际的例子。例如,我们要编写一个计算工资的类Salary,它可以根据员工的入职年份和现在的年份计算员工应该得到的工资。

按照测试驱动开发的过程,我们首先设计完成Salary类需要实现的功能,为了简便,Salary类只需要完成两个简单的功能:

1)能够给定员工的入职年份,并根据现在的年份给出应得的工资。

2)能够对输入的错误年份返回相应的错误代码。

既然是测试驱动开发,当然是“开发未动,测试先行”。我们首先创建一个测试项目并编写测试用例。对设计中的功能进行测试的步骤如下:

1)启动Visual Studio 2010并创建一个新的“Visual Studio空白解决方案”,方案名称为SalarySys。接下来的所有测试和开发都会在这个解决方案中进行。

2)向刚刚创建的解决方案中添加一个Visual C++测试项目SalaryTest。因为我们的测试需要使用C++/CLI进行编写以便使用.NET的单元测试框架,所以我们要同时修改测试项目属性,让测试项目SalaryTest使用公共语言运行时(CLR)支持。

3)向测试项目SalaryTest中添加一个单元测试。默认情况下,Visual Studio会为我们创建一个UnitTest1.cpp文件,在该文件中我们就可以编写将要实现的工资计算类测试了。

4)在UnitTest1.cpp文件中找到“#pragma region Additional test attributes”,在这个区域中,编写一个测试用例,对Salary的基本功能进行测试。

//创建测试类的智能指针

//测试功能设计中的“能够给定员工的入职年份”

std:unique_ptr pClass(new Salary(2003));

//测试功能设计中的“根据现在的年份给出应得的工资”

//判断函数返回结果是否符合预期

Assert:AreEqual(1900,pClass->GetSalary(2006));

这里我们首先创建了一个Salary类的实例智能指针,其中构造函数的参数2003表示入职年份,然后调用其GetSalary()函数计算工资,其参数2006表示现在的年份。按照设计的计算规则,其结果应该是1300,这里使用Assert:AreEqual函数对测试结果进行判断,如果这个断言函数通过,则表示Salary类的测试通过。

除了使用Assert:AreEqual断言函数对结果进行判断之外,Visual C++ 2010还提供了多种断言函数,以满足对不同类型的返回结果进行判断的需要。更人性化的是,我们还可以在断言函数中添加对测试结果的说明,这样我们可更容易以测试的结果来驱动开发。例如:

//判断不相等

Assert:AreNotEqual(0,(DWORD_PTR)pClass,"pClass指针不应该为空指针");

//判断相等

Assert:AreEqual(0,(DWORD_PTR)pClass,"pClass指针应该为空指针");

//判断比较结果是否为true

Assert:IsTrue(pClass==nullptr,"pClass指针应该为空指针");

//判断StringValue()返回的字符串是否与期望的结果相等

Assert:AreEqual("期望的结果",gcnew String(pClass->StringValue());

如果我们现在直接运行这个测试项目,当然是没法编译通过的。因为我们还没有创建Salary类。接下来就是测试驱动开发中的“开发”部分了。为了让刚才创建的测试项目能够编译运行并通过所有的测试,我们需要做的是:

1)向SalarySys解决方案中新添加一个Visual C++的Win 32静态库项目Salary。我们的开发工作就在这个项目中进行。

2)在Salary项目中新添加一个类Salary以实现工资计算的功能。为了让测试项目中的测试可以通过,我们先将Salary类简单地实现如下:

class Salary

{

public:

Salary(int nBaseYear){};

public:

int GetSalary(int nNow)

{

return 1300;

}

};

3)有了开发项目之后,接下来的工作就是将开发项目和测试项目联系起来,让测试项目对开发项目进行测试。首先,将开发项目目录“(SolutionDir)\Salary\”添加为测试项目的附加包含目录,这样测试项目可以找到Salary类的定义。然后我们还要将开发项目这个静态库链接到测试项目,为了完成这一步,我们需要在项目属性中将解决方案的输出目录“(Out-putPath)”设置为测试项目的附加库目录,最后将静态库Salary.lib设置为测试项目的附加依赖项。

至此,就完成了测试驱动开发过程的一次完整的迭代,接下来的工作,就是编写更多的测试以覆盖设计中的所有用例,然后运行这些测试用例让这些测试通过,如果测试暂时无法通过,则对开发代码进行重构实现设计,让所有测试都可以通过。例如,在完成第一次开发迭代的基础上,可以编写更多的测试覆盖Salary类设计中的所有功能点。

//TestMethod1

void TestCalculationn()

{

std:unique_ptr pClass(new Salary(2003));

int cases[4][2]=

{{2003,1000},{2004,1300},{2005,1600},{2011,3100}

};

for(int i=0;i<4;++i)

{

Assert:AreEqual(cases[i][1],pClass->GetSalary(cases[i][0]));

}

};

在这里使用数组cases定义了多个测试用例,然后使用for循环对这些用例逐个进行测试。现在运行测试项目中的这些测试当然是无法通过的,所以这些测试就驱动去对开发项目中的Salary类进行重构,以使得这些测试可以通过。

class Salary

{

public:

Salary(int nBaseYear)

:m_nBaseYear(nBaseYear)

{};

public:

int GetSalary(int nNow)

{

return 300*(nNow-m_nBaseYear)+1000;

}

private:

int m_nBaseYear;

};

对Salary类进行重构之后,所有测试都可以通过了,这样也就实现了用测试来驱动开发。当然,这里只是对设计中的第一个功能进行了足够的测试,完成了第一个功能的开发。还可以在这个基础上编写更多的测试,进入下次以测试驱动开发的迭代。

按照上面的过程以测试驱动第二个功能的实现如下:

//TestMethod2

void TestInvalidInput()

{

std:unique_ptr pClass(new Salary(2003));

//测试第二个功能点:能够对错误的年份输入返回相应的错误代码

Assert:AreEqual(-1,pClass->GetSalary(2001));

//测试临界输入是否返回正确结果

Assert:AreEqual(1000,pClass->GetSalary(2003));

};

为了让这个测试通过,必须对Salary进行重构,让它对错误的输入进行处理并返回相应的错误代码。

class Salary

{

public:

Salary(int nBaseYear)

:m_nBaseYear(nBaseYear)

{};

public:

int GetSalary(int nNow)

{

int nYears=nNow-m_nBaseYear;

if(nYears<=0)//对错误的输入进行处理并返回相应的错误代码

{

return-1;

}

else

{

//正确的输入返回相应的计算结果

return 300*(nNow-m_nBaseYear)+1000;

}

}

private:

int m_nBaseYear;

};

经过重构之后,测试项目中的所有测试都可以顺利通过,这就宣告了这一次的代码已经顺利完成。而通过不断地进行这样的迭代,可以实现对设计中的所有功能进行测试。

经过简单的几次迭代,就可以测试驱动Salary类的实现,整个过程体现了测试驱动开发的强大优势。因为关注用户反馈,所以可以及时响应需求变更;因为从使用者角度出发进行简单设计,所以也可以更快地适应变化。同时,因为测试驱动开发将测试工作提到编码之前,并频繁地运行所有测试,所以可以尽量地避免和尽早地发现错误,极大地降低了后续测试及修复的成本,提高了代码的质量。在测试的保护下,不断重构代码,以消除重复设计,优化设计结构,提高了代码的重用性,从而提高了软件产品的质量。2.2 创建第一个MFC应用程序

建立MFC应用程序步骤如下:

1)在“文件”菜单上单击“新建”,再单击“项目”。出现“新建项目”对话框。

2)在“已安装的模板”窗口中单击“Visual C++”节点。在“模板”窗口中选择“MFC应用程序”项目模板。

3)在“名称”框中,为应用程序输入一个唯一的名称如:ex02_1,将右下角“浏览”按钮下方的“为解决方案创建目录(D)”勾选上。

4)单击“确定”按钮,出现“欢迎使用MFC应用程序向导”窗口。

5)单击“完成”创建默认设置的MFC应用程序,若要对项目进行详细设置单击“下一步”,出现“应用程序类型”窗口,可以对应用程序类型和项目类型进行设置,如图2-1所示。图 2-1 应用程序类型

6)单击“下一步”,出现“复合文档支持”窗口,可以进行相关设置,如图2-2所示。图 2-2 复合文档支持

7)单击“下一步”,出现“文档模板属性”窗口,可以进行相关设置,如图2-3所示。图 2-3 文档模板属性

8)单击“下一步”,出现“数据库支持”窗口,可以进行相关设置,如图2-4所示。图 2-4 数据库支持

9)单击“下一步”,出现“用户界面功能”窗口,可以进行相关设置,如图2-5所示。图 2-5 用户界面功能

10)单击“下一步”,出现“高级功能”窗口,可以进行相关设置,如图2-6所示。图 2-6 高级功能

11)单击“下一步”,出现“生成的类”窗口,可以进行相关设置,如图2-7所示。图 2-7 生成的类

12)单击“完成”,完成项目建立。

13)单击菜单“调试”下的“开始执行”或者直接按“Ctrl+F5”键,生成并运行程序。2.3 创建控制台应用程序2.3.1 用AppWizard创建一个CLR控制台应用程序

CLR是Common Language Runtime的缩写,即运行时。CLR负责在执行时管理代码,提供内存管理和线程管理等核心服务,同时又确保代码的安全性和准确性。CLR利用metadata加载代码段、管理内存、执行方法调用等操作。

建立CLR控制台应用程序步骤如下:

1)在“文件”菜单上单击“新建”,再单击“项目”。出现“新建项目”对话框。

2)在“已安装的模板”窗口中单击“Visual C++”节点。在“模板”窗口中选择“CLR控制台应用程序”项目模板。

3)在“名称”框中,为应用程序输入一个唯一的名称如:ex02_2,将右下角“浏览”按钮下方的“为解决方案创建目录(D)”勾选上。如图2-8所示。图 2-8 新建CLR控制程序

4)单击“确定”按钮,完成项目建立。

5)生成并运行程序。

方式一:单击工具栏上的“启动调试”按钮或者菜单“调试”下的“启动调试”或者直接按F5键。

方式二:菜单“调试”下的“开始执行”或者直接按“Ctrl+F5”键。

以上两种运行方式下,控制台窗口一闪而过。

方式三:在return语句前输入代码:“Console:ReadLine();”后,再按照上面两种方式运行程序,该方式下控制台窗口如图2-9所示。图 2-9 CLR控制台ex02_2结果

Console:ReadLine()语句执行时,程序将暂停下来显示控制台窗口。按下Enter键将继续执行程序,并允许执行到结束。通常情况下需要对所有C++/CLI控制台示例程序进行该处理,才能看到输出信息。2.3.2 用AppWizard创建一个Win32控制台应用程序

建立Win32控制台应用程序步骤如下:

1)在“文件”菜单上单击“新建”,再单击“项目”。出现“新建项目”对话框。

2)在“已安装的模板”窗口中单击“Visual C++”节点。在“模板”窗口中选择“Win32控制台应用程序”项目模板。

3)在“名称”框中,为应用程序输入一个唯一的名称如:ex02_3,将右下角“浏览”按钮下方的“为解决方案创建目录(D)”勾选上。如图2-10所示。图 2-10 新建Win32控制程序

4)单击“确定”按钮,出现“欢迎使用Win32应用程序向导”窗口。

5)单击“完成”,应用程序选择默认设置,完成项目建立;单击“下一步”,对应用程序进行详细设置,如图2-11所示。图 2-11 应用程序设置

6)单击“完成”,完成项目建立。

7)生成并运行程序。

方式一:单击工具栏上的“启动调试”按钮或者菜单“调试”下的“启动调试”或者直接按F5键,控制台窗口一闪而过。

方式二:菜单“调试”下的“开始执行”或者直接按“Ctrl+F5”键,该方式下控制台窗口如图2-12所示。图 2-12 Win32控制台ex02_3结果2.4 本章小结

Visual Studio 2010不仅仅是一个开发工具,它也集成了大量的测试工具,是一个完整的开发平台。在Visual Studio 2010中,可以创建面向C++的测试项目来完成测试驱动开发流程中的测试环节,从而让整个测试驱动开发过程都在Visual Studio 2010中进行,让测试和开发做到无缝衔接,使得测试真正地驱动了开发。

通过实际案例重点介绍了如何基于Visual C++ 2010创建MFC应用程序以及如何使用App-Wizard创建CLR控制台应用程序和Win32控制台应用程序。2.5 习题

1.一个正整数有可能可以被表示为n(n≥2)个连续正整数之和,如:

15=1+2+3+4+5

15=4+5+6

15=7+8

请编写程序,根据输入的任何一个正整数,找出符合这种要求的所有连续正整数序列。

1)输入数据:一个正整数,以命令行参数的形式提供给程序。

2)输出数据:在标准输出上打印出符合题目描述的全部正整数序列,每行一个序列,每个序列都从该序列的最小正整数开始、以从小到大的顺序打印。如果结果有多个序列,按各序列的最小正整数的大小从小到大打印各序列。此外,序列不允许重复,序列内的整数用一个空格分隔。如果没有符合要求的序列,输出“NONE”。

例如,对于15,其输出结果是:

1 2 3 4 5

4 5 6

7 8

对于16,其输出结果是:

NONE

2.下面程序的运行结果是________:

#include <iostream.h>

void fun(int&a,int&b)

{

int p;

p=a;

a=b;

b=p;

}

void exchange(int&a,int&b,int&c)

{

if(a<b)fun(a,b);

if(a<c)fun(a,c);

if(b<c)fun(b,c);

}

void main()

{

int a,b,c;

a=12;

b=639;

c=78;

exchange(a,b,c);

cout<<"a="<<a<<",b="<<b<<",c="<<c<<endl;

}

A)a=639,b=78,c=12

B)a=12,b=639,c=78

C)a=639,b=12,c=78

D)a=78,b=12,c=639

3.下面程序的正确运行结果为________:

#include <iostream.h>

fun(int a,int b)

{

static int m=1,i=2;

i+=m+1;

m=i+a+b;

return(m);

}

void main()

{

int k=5,m=2,p;

p=fun(k,m);

cout<<p<<",";

p=fun(k,m);

cout<<p<<endl;

}

A)11,22

B)12,23

C)11,23

D)10,23

第3章

面向对象的C++程序设计

3.1 函数和编译预处理

函数是构成C++程序的基础,任一程序均由若干个函数组成。最简单的程序也要有一个主函数。本节介绍定义函数的方法、函数的调用规则、参数的传递方法、变量的作用域和函数重载。3.1.1 函数的声明

C++程序是函数的集合,函数在C++语言中处于十分重要的地位。C++语言中函数实现了更高级的抽象,它封装或隐藏了一些程序的代码和数据,这样就可以让用户的精力集中在函数的接口上。函数的声明和调用在函数的操作中占有极其重要的地位。

1.函数与模块

一个程序可以分成多个相互独立的程序段,这些程序段被称为函数。函数是一段完成一定功能的独立执行代码,可以把函数看成一个整体,只要将数据传送进去就能得到相应的结果。此处函数的概念类似于数学中所讲的“函数”——将一个变量(函数的参数)映射为另一个变量(函数的返回值)。

C++有两种程序模块:函数(function)和类(class)。其中,函数也有两类:一类是类似于C语言中的普通函数(类体外的函数),另一类是类中的成员函数。其区别是前者不属于某个类,而后者却属于某个类,即前者的作用域要大于后者。

函数是程序模块定义的操作,它是程序功能的抽象。调用者只关心函数能做什么,而不需要关心它是如何做的。

C++中可以包含一个或多个函数,其中有且仅有一个以main为名称的函数,这个函数称为主函数,整个程序都是从这个主函数开始执行的。当要执行的程序很大时,需要以一种比较容易管理的方式来组织源代码,通常是将程序划分为若干模块。C++语言使用文件作为划分模块的主要机制,这些组成C++程序的文件称为文件模块,简称为模块。

函数的作用有两个:一是实现任务划分,将一个比较复杂的任务划分成若干简单的任务,每个任务可以由一个或多个函数组成。函数的使用便于任务的分工与处理,便于验证程序的正确性。二是实现软件的源代码复用,把一些功能相似的程序段组织成函数,使得函数的代码只有一处,而调用却可以有多处,即不需要编写相同的代码。

2.函数的声明

函数在使用之前应该先声明。C++中提供了一种函数的引用性声明——函数原型,它的一般形式为:

<函数返回值的类型声明><函数名>(<参数表>);

在C++中函数必须要有原型,这是C++区别于C语言的一个方面。函数原型的作用是告诉编译器有关函数的信息,如函数的名称、函数参数的类型、函数返回值的类型、函数参数的个数和函数参数的顺序。

在编写C++程序时,有大量的“#include xxx.h”的语句。这实质上是一条编译预处理指令,把系统定义的函数或自定义的函数包含进来。“#include xxx.h”只是包含了函数原型,真正的函数实现代码并没有包含进来。编译器根据这些函数原型检查用户调用是否正确。

例如,#include "math.h"是把常见的数学函数原型包含到程序中。这样,当调用某个数学函数时,系统就检查其调用正确与否。3.1.2 函数的参数和返回值

一个函数不仅可以完成某些操作,而且还可以将一些数据从函数的外面通过函数的参数传送给函数进行处理;函数也可以将一个处理的结果值通过函数的return语句返回,还可以通过参数将处理的多个结果带回给调用者。

1.函数的形式参数和实际参数

在函数的定义中,参数表中一一列举说明的参数称为形式参数(parameter,简称为形参)。对于有参函数,C++对形参的个数并没有限制,可以只有一个参数,也可有若干个参数。例如,定义一个函数f(),它有四个形参:

float f(float x,float y,int i,char c)

{

…//函数体的定义部分

}

对于形参表中的每一个参数,都必须依次列举每一个参数的类型,即使同类型的参数也是如此。如上面定义的函数f(),形参不能写成以下形式:

float f(float x,y,int i,char c)

{

…//函数体的定义部分

}

在函数调用时,依次列出的参数称为实际参数或实在参数(argument,简称为实参)。每一个实参均可以是一个表达式,系统先求出表达式的值,然后将所求出的值传递给对应的形参。在实参表中,每一个实参的类型必须与对应的形参的类型相兼容(或称为相匹配)。通常情况下,要求实参在类型和个数上与形参存在一一对应的关系。

示例ex03_1 说明实参与形参的对应关系。

#include "stdafx.h"

#include <iostream>

using namespace std;

int maxi(int a,int b)

{

return a>b?a:b;

}

float maxf(float a,float b)

{

return a>b?a:b;

}

int_tmain(int argc,_TCHAR *argy[])

{

float x=3.4,y=5.6;

char c1='a',c2='b';

int i=20,j=30;

cout<<maxi(x,y)<<'\t';//A

cout<<maxf(x,y)<<'\t';//B

cout<<maxi(c1,c2)<<'\t';//C

cout<<maxf(c1,c2)<<'\t';//D

cout<<maxi(i,45+y)<<'\t';//E

cout<<maxf(j,45+y)<<'\t';//F

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载