文档名称:Visaul C++ 6.0使用简介
文档作者:沈捷
创建日期:2004.03.20
当前版本:1.0.0.1
修改记录:N/A
内容提要:
1.基本概念
|
|__1.1项目的概念
|
|__1.2工作区的概念
2.VC界面介绍
|
|__2.1常用菜单项
| |
| |__2.1.1文件菜单
| |
| |__2.1.2编译菜单
|
|__2.2类视图简介
|
|__2.3文件视图简介
|
|__2.4资源简介
|
|__2.5代码的颜色
3.VC常用数据类型
4.一个实例——一步步开始你的第一个VC程序
5.结束语
文档内容:
1.基本概念:
1.1 项目的概念:
用于生成一个最终程序的各个源代码文件和其它辅助文件的集合被我们称为一个“项目”。这个概念也许对于一些初学者还比较陌生,这是完全可以理解的。在以前我们使用的Turbo C中,虽然提供了对项目文件管理的支持(Project菜单项),但它的功能并不强大,而且使用起来步骤繁琐,因此并没有被重视。而且那个时候我们所面对的程序一般也比较简单,把所有的代码放在一个源文件里面就够了,因此也没有对使用项目的迫切需求。但是在实际的程序设计工作中,一个程序的结构往往十分复杂,如果想用一个文件来实现几乎是不可能的。因此程序员们往往把一个程序分成较小的一些功能模块,然后分别在不同的源文件中实现各个模块的功能。在编译时,首先分别编译各源文件,生成一系列的.obj文件,然后再将它们相互连接(往往还要连接上必要的.lib静态库文件)得到最终的程序文件。为了维护一个项目中文件间的相互关系,在项目中一般还加入了用于描述这些关系的项目描述文件,这些文件的内容和格式随编译器的不同也不尽相同,对于VC,是项目文件夹中.dsp文件。这个文件的内容是由VC自动维护的,而不需要也不应当被程序员修改。
下面我们就列举一个项目的实例来讲解一下VC中项目的组织结构。这个例子中的有些内容可能设计到以后的知识,因此我们并不期望读者在这里就可以完全理解它,只是想借此为诸位建立一个“项目”直观的概念。
实例 1.1:
项目名称:APITest 项目文件夹名称:APITest
项目文件夹结构:
APITest 项目文件夹
|
|__StdAfx.h 程序源文件之一,可由用户修改
|
|__StdAfx.cpp 程序源文件之一,可由用户修改
|
|__APITest.h 程序源文件之一,可由用户修改
|
|__APITest.cpp 程序源文件之一,可由用户修改
|
|__resource.h 程序源文件之一,内容关于资源符号的定义,由VC维护,我们不建议用户修改该文件
|
|__APITest.rc 资源描述文件,可由用户从VC的资源编辑器中对其修改,对于某些高级用户,也可以直接用文本方式修改
|
|__APITest.dsw 工作区描述文件,由VC维护
|
|__APITest.dsp 项目描述文件,由VC维护
|
|__APITest.plg 编译记录,由VC维护,用户可查看
|
|__APITest.aps 项目相关文件,由VC维护
|
|__APITest.ncb 项目相关文件,由VC维护
|
|__ReadMe.txt 项目建立时由VC生成的自述文件,描述了项目中一些主要文件的功能,不建议用户修改
|
|__Debug 当编译选项目为“Debug”时的默认输出路径
| |
| |__APITest.exe 编译和连接后的最终程序(Debug版)
| |
| |__*.* 编译时产生的中间文件,包括.obj、.ilk等
|
|__Release 当编译选项目为“Release”时的默认输出路径
| |
| |__APITest.exe 编译和连接后的最终程序(Release版)
| |
| |__*.* 编译时产生的中间文件,包括.obj、.ilk等
|
|__Res 项目的资源文件夹,与.rc文件配合使用,用于存放该项目需要的各种资源(.bmp、.ico等),由VC负责维护,不建议在VC之外修改
|
|__*.* 项目的资源文件
刚才所举的还只是一个很小的程序而已,正如诸位所见到的,VC的项目组成是十分复杂的。但是需要声明的是,VC对项目有良好的自动维护机制,因此很多文件不需要我们亲自维护。甚至在一个项目中,我们一般都很少自己去新建或打开文件,而是由我们来提出具体要求让VC来判断是否应当新建文件并负责建立文件的操作。比如当我们要新建一个类的时候,VC会自动为这个类的代码建立一组源文件(.h与.cpp)。同时,当我们要查看某一段代码的时候,也不需要亲自一个个的打开文件然后查找,只需要在类视图窗口中选中想阅读的函数,VC则会自动帮我们找到它所在的文件并打开它。总的来说,VC在这里就承担了一个大管家的角色,它帮助我们管理了复杂的项目文件结构,而把逻辑层面上的内容清晰的呈现在我们的面前。也就是说,当我们在写代码的时候,不需要关心倒底在写哪个文件,只需要关心在下哪一个类、哪一个函数就可以了。换句话说,VC让我们看不到文件的概念,呈现在我们眼前的只是类、函数这些逻辑概念,这正是VC项目管理机制的强大之处。
1.2工作区的概念
工作区的概念可以认为是VC项目管理机制对项目概念的一个延伸。在我们工作中,很多时候不仅只关心各个文件的内容。比如我们刚刚在A文件中增加了一个函数,然后下班时间到了,终于可以休息一下了。但是毕竟这个函数还没有写完,所以我们希望再次开始工作的时候能自动打开A文件并把输入位置设置为上次中断的位置而不是文件头以便于我们继续工作。VC通过一个“工作区”来满足这种需求,“工作区”这个概念正如它的名字,就是用于描述用户当前工作状态的。比如打开了哪些文件、当前输入位置在什么地方这一类的信息被保存在工作区文件中,它在VC关闭的时候会自动保存。当用户下一次继续工作的时候,只需要打开这个工作区文件,就可以回到上一次关闭前的状态,而不需要再费心思回忆上一次到底在改哪一行代码了。
这里特别给出两个提示,一:工作区与项目并不一定是一一对应的,一个工作区中也可以包含两个或多个项目。但一般情况下,人们还是喜欢每次只在一个项目中进行工作,因此一个工作区中往往只有一个项目,或者说,每个项目往往都有与之对应的工作区;二:正是如此,当我们想打开一个项目的时候,常用“打开工作区Open Workspace”菜单项打开这个项目文件夹中的工作区文件而不是使用“打开项目Open Project”。
2.VC界面简介
2.1常用菜单项:
正如诸位所见,VC的界面上有很菜单项,但是很多功能一般是用不到,因此这里仅对常用的几个项目做一下简单的介绍。
2.1.1文件(File)菜单组:
New (新建):新建项目或新建文件都是由它完成的,点击后出现一个对话框询问新建项目还是新建文件以及新建的项目或文件的类型。具体的操作将在后面详细介绍
Open(打开):用于打开文件。注意,这个菜单项不是为打开项目准备的,而只是用来打开单独的文件,因此它的默认打开类型是.h和.cpp的文件。这个功能一般不常用到,但有的时候希望打开一些不属于任何项目的源文件时可以用到这一项功能。
Close(关闭):关闭当前被打开且处于活动状态的文件。
Open Workspace(打开工作区):在打开项目的时候常用的选项,用它来打开项目文件夹中的.dsw文件即可以。也可以用来打开项目描述文件(.dsp),但是如果检测到有.dsw文件的存在则会自动以打开这个.dsw文件的方式打开项目。
Save Workspace(保存工作区):保存当前的工作区状态。这个功能并不常用,因为当VC在关闭的时候往往会自动执行这个操作。
Close Workspace(关闭工作区):当我们需要开始或打开一个新的项目的时候最好先关闭当前的工作区,这个时候应当使用这一菜单项。仅仅关闭所有打开的文件是不行的,此时的工作区仍然处于打开状态,只不过没有被打开的代码源文件而已。
Save(保存):保存当前处于被编辑状态的源文件。这个功能作用并不是很大,因为它一次只能保存一个文件,而且只能保存在工作区中以文本方式打开(.h和.cpp等)的文件,如果对资源描述文件一类的文件做了修改(当然,是通过资源编辑器,而不是直接用文本方式修改)它就无能为力了。
Save As(另存为):文件令存为。它存在与此同时Save命令一样的缺点。
Save All(保存全部):保存目前打开的所有文件,包括以非文本方式打开的文件(如.rc,.aps等),即保存目前对该项目所做的一切修改。这个命令经常被使用。
其它的项和通用的菜单项没有太大的区别,就不在详述了。还有两点需要注意的:一,VC中有Recent Files和Recent Workspace两个选项,一个对应于打开文件,一个对应于打开工作区。后者比前者常用的多;二,如果当前被激活的文件中存在未被保存的修改,则在标题栏中会出现一个“*”提示符。
2.1.2编译(Compile)菜单组:
Compile XXX(编译当前文件):编译当前的源文件产生其对应的.obj文件。
Build XXX(构建项目的EXE文件):首先编译所有没编译过或已被修改过的源文件,连接它们的.obj文件和其它的文件生成最终的EXE文件。常用它来实现构建。
Rebuild All(重建全部):同样用来构建EXE,它和Build的区别是:Build只编译过时的.obj文件,而它不考虑目前这些的.obj是否为最新版本,而重新编译所有源文件,然后连接生产工具EXE文件。一般很少使用这个功能。
Execute XXX(执行EXE文件):首先构建出EXE文件,然后运行之,相当于Turbo C中Ctrl+F9的功能。推荐使用。
Set Active Configuration(设置可运行配置):VC程序一般有两个编译配置:调试版(Debug)和完全版(Release),新建的项目默认为Debug配置。用这个配置编译出的EXE文件在项目文件夹的Debug目录中,它一般比较大,但是包括了很多可调试信息,方便与VC调试器一起完成项目的调试。而Release版的程序则要小的多,但不能调试,因此一般是作为项目的最终成品,而在制作工程中一般使用Debug版。
至于其它的菜单项,一般与调试有关,要讲起来就要长篇大论了。幸好对于较小的项目也不怎么用到,所以就先略过了。
2.2类视图(Class View)简介:
当VC中有活动的项目时,其界面的左侧会出现一组选项卡,它们从左至右分别是Class View(类视图)、Resource View(资源视图)和File View(文件视图)。其中的Class View就是这一节要介绍的内容,同时也是三个视图中最有用的一个。
VC的Class View以树形图的形式显示了在当前项目中的类层次结构。一般刚打开一个项目的时候,所有的类都以折叠的方式显示,即只显示类名,并在前面有一“+”图标。另外在所有的类下面有一个“Global(全局)”项,其中包括了不在任何类中的函数和全局变量。双击一个类名则会自动在代码编辑窗口中转到这个类定义的位置。若要进一步查看该类的内容,可以点击类名左侧的“+”标志。此时该类层次结构被展开,显示出它的所有成员函数和成员变量,同时前面的图标变为“-”,点击之则重新回到折叠状态。函数前面以粉红色的小方块图标标识,而变量前面则是一个绿色的小方块标志。如果在小方块的前面还有一个锁的图标,则表示该成员是私有(Private)的,若为一个钥匙的标志,则是保护(Protect)的,若没有其它图标,则是公共(Public)的。双击一个函数的名字,则编辑窗口的输入位置跳转到该函数的定义(实现)位置,若想跳转到它的声明位置,则可以右击Class View中的函数名,在出现的菜单中选择“Go To Declaration”一项;选择Property一项则可以直接查看该函数的属性,包括返回值类型、参数类型等。如果双击一个变量名,则会跳转到该变量的定义位置,同时也可以用Property这个右键菜单项来查看这个变量的类型。
若想新建类,则可以在Class View中的根节点(显示为XXX classes,XXX为当前项目名)的右键菜单中选择“New Class”项,之后在弹出的对话框中填写好相应的内容,点确定即可。之后VC会帮你产生相关的文件和类的最初定义信息,并将当前输入位置切换到新建的类实现文件中。要在类中新建函数或变量,可以在类名的右键菜单中选择“Add Memeber Function”或“Add Member Variable”项,填写好相应内容后,VC会自动产生代码并跳转输入位置。若要删除一个函数,特别是消息处理函数或映射函数,最好使用函数名右键菜单中的“Delete”命令,它不仅会清除掉函数的实现和声明,还会同时清除掉消息映射宏中的相关项(对于这部分的概念,我们以后还会详细介绍)。当然,除此之外,使用传统的纯手工方法也是可以的,只是前者工作量小而且不容易出错而已。
Class View中显示的内容是由VC自动维护的,它会依用户的修改自动完成更新,并在退出VC时自动保存。
2.3文件视图(File View)简介:
File View是VC界面左侧的第三个选项卡。它也是以树形图的形式显示的。文件视图中的文件虽然也是以类似WIN资源管理器中的文件夹树显示的,但这里显示的文件层次关系并不是实际存放的文件树,而是项目中各文件间的逻辑关系。每一个项目都有四个逻辑文件夹:Source File(源文件)、Header File(头文件)、Resource File(资源文件)和External Dependencies(外部依赖)。另外,还有一些不属于任何逻辑文件夹的文件,比如ReadMe.txt等,这些文件一般不需要开发者维护。 Source File中包括了程序中所有以.cpp和.c为后缀名的文件。Header File中是项目中的头文件(.h)。在Resource File中是项目中的资源文件,要编辑资源文件,一般不需要在这里打开,而可以在Resource View选项卡中打开相应的ID号来对它们进行修改。External Dependencies中的文件是项目的外部依赖文件。比如在你的项目中有一句“include XXX.h”,而XXX.h并不是项目中的头文件,则这个文件被认为是外部依赖的。刚打开项目的时候,VC一般不知道项目中有哪些外部依赖的文件,必须构建一次项目,这个文件夹中的内容才会被更新。有时候可以会发现在一些文件名的后面有一个“*”符号,这表示在这个文件中有未被保存的修改存在。
在File View中双击文件名则会打开这个文件,若其已经被打开,则将输入焦点切换到该文件。在文件名的右键菜单中选择Delete命令可以将这个文件删除出项目,但必须注意一点,这个文件并没有被删除,也没有被移动,只是被认为不再属于该项目。如果要真正删除该文件,还需要在VC外面删除这个文件。这一点在需要重写一个文件的候要特别注意,如果仅在File View中删除之,可能会造成一些奇怪的错误。
2.4资源(Resource)简介:
资源是Windows下编程的新概念。众所周知,WIN程序是以其精致的GUI(Graphice User Interface 图形用户界面)著称的。但是如果所有的图形都要在程序中通过绘图命令来实现,那工作量简直是不可想象的。除此之外,很多情况下,我们可能会希望程序能播放一些声音提示,如果把它们以文件的形式存放在程序之外当然未尝不可,但当然不如把它们直接写到程序里面方便。因此WIN下的程序引入了资源的概念,资源一般是一些图片、图标或其它程序中需要直接使用的非代码的组成部分,它们被存放在生成的EXE文件的“资源节(Resource Section)”中。项目中的每一个资源平时是单独以相应的文件形式存放在Res文件夹中的,而它们之间的关系则存放在.rc文件中。在编译的时候它们被编译成一种资源目标文件,然后和.obj、.lib文件等一起连接起来组成最终的EXE文件。
在项目中,每个资源用一个32位无符号整数常量标识,为了便于记忆,它们被用#define宏定义了相应的符号常量,比如IDI_MAINFRAME等,这被称为资源ID(Resouce Identifier)。这些宏定义存放在resource.h头文件中,所以一般你可以在很多.cpp文件中看到#i nclude "resource.h"的命令,这就是为了使它可以识别这些常量宏定义。resource.h是由VC维护的,当用户新增、删除资源或更改资源ID的时候,它会被自动更新。至于使用资源的方式,WinAPI和MFC都提供了很多相应的函数,这里就不再详述,它们并不是本文的重点。在VC界面左侧三个选项卡中的中间一个,就是Resource View(资源视图),它也是以类似File View的逻辑文件层次树的形式显示的。
需要说明的是,在这里对资源的介绍是很简略的,我们并不期望读者可以在这里完全学会资源的使用方法,只是希望诸位在这里先建立起“资源”的概念以便于我们后面的介绍。
2.5代码颜色:
也许在这里讨论代码的颜色有点可笑,但是要知道,在VC中,代码的颜色除了起装饰左右外还显示了相当的信息。在VC中代码主要有四种颜色:黑、蓝、绿和灰。黑色是最常见的颜色,所有普通的代码是用黑色表示的。蓝色则标识关键字,包括if、for这类程序流程关键字和int、float这些数据类型关键字,但是它只包括基本的ANSI C++类型,用typedef或#define生成的新类型是不被标识的,这一点的确让人颇为不满。绿色标识的内容是程序注释,即在/*...*/之间和//至行尾之间的部分。而灰色的代码是由Class Wizard(VC的组成部分之一)维护的代码,我们不建议用户修改,这可能导致Class Wizard的工作不正常,并且不能保证你的改动最后能被保留下来——Class Wizard完全有可能重写这段代码。
3.VC常用数据类型:
当然在VC中使用ANSI C++数据类型是完全可以的,但是VC里面增加了很多“新”的数据类型,之所以打上引号,是因为它们并不是真的新东西,而是通过typedef对已有的数据类型进行重命名而已。比如DWORD类型是typedef unsigned long DWORD;,即DWORD等价于unsigned long。这样做的目的在于增加代码的可读性,比如HANDLE和DWORD都是unsigend long,但从字面意义上可以看出,HANDLE类型表示句柄(WIN下的一个概念,这里不再详述,以后会详细介绍),而DWORD则表示一般的数据类型,显然一个函数声明写成DWORD GetPara(HANDLE hWnd)要比unsigned long GetPara(unsigned long hWnd)更容易理解。另外一点,DWORD比unsigned long要短的多,不要小看这一点点差别,当工程庞大的时候这可为我们写代码的时候省了不少输入工作。
下面就把在VC中常用到的新数据类形罗列如下:
BYTE unsigned char;
WORD unsigned short;
DWORD unsigned long;
LONG signed long;
LPTSTR char *;
LPCTSTR const char *;
LPVOID void *;
HANDLE unsigned long;
还有一个比较特殊的类型:BOOL,它是ANSI C++中所没有的。它实际上是一个整型,有两种取值,TRUE(1)和FALSE(0),当然也可以把它当做一般的整型数据来使用,不过我可不希望你这么做,毕竟我们是拿它来当布尔值来用的啊。
另外特别声明一点,在VC中,int和long一样是32位的,需要16位的×××应当定义为short形。这一点和以前的Turbo C不同。另外一点,在WIN编程中,所有的指针都是32位而不是16位的,因此它具有4GB虚寻址空间,所以就没有了DOS下的远指针、近指针概念,或者说,在WIN中所有的指针都是远指针,因此不用考虑寻址范围这种麻烦问题。
4.一个实例——一步步开始你的第一个VC程序:
上面讲了那么多,也许已经看的有写发昏了吧?的确,VC的概念是多了些,要想一下子都理解清楚并不是那么容易的事情。正如马克思注意哲学所说,人类对自然界的认识始终离不开实践,因此在本文的最后,我们来手把手的讲解一个实例,并借此来讲解一些技巧,希望能对读者的理解和记忆有所帮助。
这里我们要写的程序是一个简单的Windows Console程序(这是一种很接近于DOS下程序的WIN程序,它没有窗口、没有消息循环,因此结构简单,很适合用来学习C++时做练习之用)。当然我们可以做一个“Hello World!”,但我想还是做点更有智商的东西比较有趣,所以这次我们做的是一个小游戏:由程序在0~99中随机选取一个数,然后由玩家猜测计算机选择的是哪个数字。下面就是建立这个工程的基本步骤:
首先,让我们来建立我们的项目:
打开VC,选择File->New,之后会出先一个对话框。记住,我们曾经说过,VC中的基本单位是项目,因此首先让我们切换到“Project”属性页。在对话框的左側显示了一个列表框,其中显示了很多项目类型,一般常用的是MFC AppWizard(dll)(MFC动态连接库)、MFC AppWizard(exe)(MFC可执行程序)、Win32 Application(普通Win32程序)、Win32 Console Application(Win32控制台程序)、Win32 Dynamic-Link Library(Win32动态连接库)。这里我们选择Win32 Console Application,右面有两个文本输入框,一个是Location,即项目文件夹的位置,可以直接输入,也可以通过后面的“...”按钮选取。另一个是Project,即项目名称,也是项目文件夹的名字(项目文件夹的实际位置是Location\Project),其它的内容使用默认选项,点OK即可,然后进入下一设置。在这里为了以后叙述方便起见,我们假设项目名称是“Example01”,位置是“E:\项目\Teaching”。
当完成了刚才的设置之后,VC会启动一个叫做Application Wizard的组件,它通过向用户询问一些内容来自动产生项目的框架性代码,用户只需在这个构架中填入实现具体功能的代码即可完成一个程序。Console程序的App Wizard相对比较简单,它并不需要太多的信息。正如你看到的,它只有一步。这里显示的对话框中有四个选项,它们的意思分别是:An empty project,一个空项目,它不包含任何文件,所以一般不会使用这一项;A simple project,一个简单的项目,它包含一些纯构架性的代码,生成后直接可以编译成一个“什么都不做”的EXE程序,然后程序员在里面加入需要实现的功能即可完成程序的设计;A "Hello World!" Application,它产生的是一个Hello World程序的源代码,在Console下,这一项没什么用处,但在其它类型的项目中,我们有时会先建立一个这种类型的项目再加以修改得到最终程序,这比从simple project开始要省力的多;An application that supports MFC,一个支持MFC的项目,和A simple application差不多,但使用它的项目可以使用MFC中非界面部分的类,这是经常使用的选项,毕竟,使用MFC比纯粹用API要方便的多。但是在这里,我们似乎并不需要用到MFC的内容,所以我们选择第二项:A simple application,然后点击Finnish完成AppWizard的设置。在着之后,回出现一分报告,告诉你AppWizard都进行了哪些工作,同时,这里也是你最后一次后悔的机会,一但点击确定,AppWizard就开始按照你刚才的设置完成工作了,要知道,AppWizard进行的工作在完成之后是不能撤消或修改的,所以请一定要认真阅读这份报告来确定你刚才的设置是否正确。不过对于一个Console类型的程序,AppWizard的设置并不多,似乎也没什么可以出错的地方,所以让我们直接点OK吧。
下面让我们从File View中看看AppWizard倒底做了些什么吧!这时的项目中四个文件,分别是Example01.cpp、StdAfx.cpp、StdAfx.h和ReadMe.txt。Example01.cpp是程序的主文件,这个程序的Main函数就在这个文件中,以下就是其中的内容:
//
// Construction/Destruction
//
CGuess::CGuess()
{
m_CompTimes=0;
m_wValue=0;
::srand((unsigned)time(NULL)); // 初始化随机数种子
}
CGuess::~CGuess()
{
}
void CGuess::Initialize()
{
m_CompTimes=0;
m_wValue=rand()%100; // 产生随机数
}
int CGuess::Compare(int wInput)
{
m_CompTimes++;
return wInput-m_wValue; //比较
}
int CGuess::GetCompTime()
{
return m_CompTimes;
}
下面再让我们来完成Main函数的改写,修改后的Example01.cpp内容如下(黑体为新增部分):
文档作者:沈捷
创建日期:2004.03.20
当前版本:1.0.0.1
修改记录:N/A
内容提要:
1.基本概念
|
|__1.1项目的概念
|
|__1.2工作区的概念
2.VC界面介绍
|
|__2.1常用菜单项
| |
| |__2.1.1文件菜单
| |
| |__2.1.2编译菜单
|
|__2.2类视图简介
|
|__2.3文件视图简介
|
|__2.4资源简介
|
|__2.5代码的颜色
3.VC常用数据类型
4.一个实例——一步步开始你的第一个VC程序
5.结束语
文档内容:
1.基本概念:
1.1 项目的概念:
用于生成一个最终程序的各个源代码文件和其它辅助文件的集合被我们称为一个“项目”。这个概念也许对于一些初学者还比较陌生,这是完全可以理解的。在以前我们使用的Turbo C中,虽然提供了对项目文件管理的支持(Project菜单项),但它的功能并不强大,而且使用起来步骤繁琐,因此并没有被重视。而且那个时候我们所面对的程序一般也比较简单,把所有的代码放在一个源文件里面就够了,因此也没有对使用项目的迫切需求。但是在实际的程序设计工作中,一个程序的结构往往十分复杂,如果想用一个文件来实现几乎是不可能的。因此程序员们往往把一个程序分成较小的一些功能模块,然后分别在不同的源文件中实现各个模块的功能。在编译时,首先分别编译各源文件,生成一系列的.obj文件,然后再将它们相互连接(往往还要连接上必要的.lib静态库文件)得到最终的程序文件。为了维护一个项目中文件间的相互关系,在项目中一般还加入了用于描述这些关系的项目描述文件,这些文件的内容和格式随编译器的不同也不尽相同,对于VC,是项目文件夹中.dsp文件。这个文件的内容是由VC自动维护的,而不需要也不应当被程序员修改。
下面我们就列举一个项目的实例来讲解一下VC中项目的组织结构。这个例子中的有些内容可能设计到以后的知识,因此我们并不期望读者在这里就可以完全理解它,只是想借此为诸位建立一个“项目”直观的概念。
实例 1.1:
项目名称:APITest 项目文件夹名称:APITest
项目文件夹结构:
APITest 项目文件夹
|
|__StdAfx.h 程序源文件之一,可由用户修改
|
|__StdAfx.cpp 程序源文件之一,可由用户修改
|
|__APITest.h 程序源文件之一,可由用户修改
|
|__APITest.cpp 程序源文件之一,可由用户修改
|
|__resource.h 程序源文件之一,内容关于资源符号的定义,由VC维护,我们不建议用户修改该文件
|
|__APITest.rc 资源描述文件,可由用户从VC的资源编辑器中对其修改,对于某些高级用户,也可以直接用文本方式修改
|
|__APITest.dsw 工作区描述文件,由VC维护
|
|__APITest.dsp 项目描述文件,由VC维护
|
|__APITest.plg 编译记录,由VC维护,用户可查看
|
|__APITest.aps 项目相关文件,由VC维护
|
|__APITest.ncb 项目相关文件,由VC维护
|
|__ReadMe.txt 项目建立时由VC生成的自述文件,描述了项目中一些主要文件的功能,不建议用户修改
|
|__Debug 当编译选项目为“Debug”时的默认输出路径
| |
| |__APITest.exe 编译和连接后的最终程序(Debug版)
| |
| |__*.* 编译时产生的中间文件,包括.obj、.ilk等
|
|__Release 当编译选项目为“Release”时的默认输出路径
| |
| |__APITest.exe 编译和连接后的最终程序(Release版)
| |
| |__*.* 编译时产生的中间文件,包括.obj、.ilk等
|
|__Res 项目的资源文件夹,与.rc文件配合使用,用于存放该项目需要的各种资源(.bmp、.ico等),由VC负责维护,不建议在VC之外修改
|
|__*.* 项目的资源文件
刚才所举的还只是一个很小的程序而已,正如诸位所见到的,VC的项目组成是十分复杂的。但是需要声明的是,VC对项目有良好的自动维护机制,因此很多文件不需要我们亲自维护。甚至在一个项目中,我们一般都很少自己去新建或打开文件,而是由我们来提出具体要求让VC来判断是否应当新建文件并负责建立文件的操作。比如当我们要新建一个类的时候,VC会自动为这个类的代码建立一组源文件(.h与.cpp)。同时,当我们要查看某一段代码的时候,也不需要亲自一个个的打开文件然后查找,只需要在类视图窗口中选中想阅读的函数,VC则会自动帮我们找到它所在的文件并打开它。总的来说,VC在这里就承担了一个大管家的角色,它帮助我们管理了复杂的项目文件结构,而把逻辑层面上的内容清晰的呈现在我们的面前。也就是说,当我们在写代码的时候,不需要关心倒底在写哪个文件,只需要关心在下哪一个类、哪一个函数就可以了。换句话说,VC让我们看不到文件的概念,呈现在我们眼前的只是类、函数这些逻辑概念,这正是VC项目管理机制的强大之处。
1.2工作区的概念
工作区的概念可以认为是VC项目管理机制对项目概念的一个延伸。在我们工作中,很多时候不仅只关心各个文件的内容。比如我们刚刚在A文件中增加了一个函数,然后下班时间到了,终于可以休息一下了。但是毕竟这个函数还没有写完,所以我们希望再次开始工作的时候能自动打开A文件并把输入位置设置为上次中断的位置而不是文件头以便于我们继续工作。VC通过一个“工作区”来满足这种需求,“工作区”这个概念正如它的名字,就是用于描述用户当前工作状态的。比如打开了哪些文件、当前输入位置在什么地方这一类的信息被保存在工作区文件中,它在VC关闭的时候会自动保存。当用户下一次继续工作的时候,只需要打开这个工作区文件,就可以回到上一次关闭前的状态,而不需要再费心思回忆上一次到底在改哪一行代码了。
这里特别给出两个提示,一:工作区与项目并不一定是一一对应的,一个工作区中也可以包含两个或多个项目。但一般情况下,人们还是喜欢每次只在一个项目中进行工作,因此一个工作区中往往只有一个项目,或者说,每个项目往往都有与之对应的工作区;二:正是如此,当我们想打开一个项目的时候,常用“打开工作区Open Workspace”菜单项打开这个项目文件夹中的工作区文件而不是使用“打开项目Open Project”。
2.VC界面简介
2.1常用菜单项:
正如诸位所见,VC的界面上有很菜单项,但是很多功能一般是用不到,因此这里仅对常用的几个项目做一下简单的介绍。
2.1.1文件(File)菜单组:
New (新建):新建项目或新建文件都是由它完成的,点击后出现一个对话框询问新建项目还是新建文件以及新建的项目或文件的类型。具体的操作将在后面详细介绍
Open(打开):用于打开文件。注意,这个菜单项不是为打开项目准备的,而只是用来打开单独的文件,因此它的默认打开类型是.h和.cpp的文件。这个功能一般不常用到,但有的时候希望打开一些不属于任何项目的源文件时可以用到这一项功能。
Close(关闭):关闭当前被打开且处于活动状态的文件。
Open Workspace(打开工作区):在打开项目的时候常用的选项,用它来打开项目文件夹中的.dsw文件即可以。也可以用来打开项目描述文件(.dsp),但是如果检测到有.dsw文件的存在则会自动以打开这个.dsw文件的方式打开项目。
Save Workspace(保存工作区):保存当前的工作区状态。这个功能并不常用,因为当VC在关闭的时候往往会自动执行这个操作。
Close Workspace(关闭工作区):当我们需要开始或打开一个新的项目的时候最好先关闭当前的工作区,这个时候应当使用这一菜单项。仅仅关闭所有打开的文件是不行的,此时的工作区仍然处于打开状态,只不过没有被打开的代码源文件而已。
Save(保存):保存当前处于被编辑状态的源文件。这个功能作用并不是很大,因为它一次只能保存一个文件,而且只能保存在工作区中以文本方式打开(.h和.cpp等)的文件,如果对资源描述文件一类的文件做了修改(当然,是通过资源编辑器,而不是直接用文本方式修改)它就无能为力了。
Save As(另存为):文件令存为。它存在与此同时Save命令一样的缺点。
Save All(保存全部):保存目前打开的所有文件,包括以非文本方式打开的文件(如.rc,.aps等),即保存目前对该项目所做的一切修改。这个命令经常被使用。
其它的项和通用的菜单项没有太大的区别,就不在详述了。还有两点需要注意的:一,VC中有Recent Files和Recent Workspace两个选项,一个对应于打开文件,一个对应于打开工作区。后者比前者常用的多;二,如果当前被激活的文件中存在未被保存的修改,则在标题栏中会出现一个“*”提示符。
2.1.2编译(Compile)菜单组:
Compile XXX(编译当前文件):编译当前的源文件产生其对应的.obj文件。
Build XXX(构建项目的EXE文件):首先编译所有没编译过或已被修改过的源文件,连接它们的.obj文件和其它的文件生成最终的EXE文件。常用它来实现构建。
Rebuild All(重建全部):同样用来构建EXE,它和Build的区别是:Build只编译过时的.obj文件,而它不考虑目前这些的.obj是否为最新版本,而重新编译所有源文件,然后连接生产工具EXE文件。一般很少使用这个功能。
Execute XXX(执行EXE文件):首先构建出EXE文件,然后运行之,相当于Turbo C中Ctrl+F9的功能。推荐使用。
Set Active Configuration(设置可运行配置):VC程序一般有两个编译配置:调试版(Debug)和完全版(Release),新建的项目默认为Debug配置。用这个配置编译出的EXE文件在项目文件夹的Debug目录中,它一般比较大,但是包括了很多可调试信息,方便与VC调试器一起完成项目的调试。而Release版的程序则要小的多,但不能调试,因此一般是作为项目的最终成品,而在制作工程中一般使用Debug版。
至于其它的菜单项,一般与调试有关,要讲起来就要长篇大论了。幸好对于较小的项目也不怎么用到,所以就先略过了。
2.2类视图(Class View)简介:
当VC中有活动的项目时,其界面的左侧会出现一组选项卡,它们从左至右分别是Class View(类视图)、Resource View(资源视图)和File View(文件视图)。其中的Class View就是这一节要介绍的内容,同时也是三个视图中最有用的一个。
VC的Class View以树形图的形式显示了在当前项目中的类层次结构。一般刚打开一个项目的时候,所有的类都以折叠的方式显示,即只显示类名,并在前面有一“+”图标。另外在所有的类下面有一个“Global(全局)”项,其中包括了不在任何类中的函数和全局变量。双击一个类名则会自动在代码编辑窗口中转到这个类定义的位置。若要进一步查看该类的内容,可以点击类名左侧的“+”标志。此时该类层次结构被展开,显示出它的所有成员函数和成员变量,同时前面的图标变为“-”,点击之则重新回到折叠状态。函数前面以粉红色的小方块图标标识,而变量前面则是一个绿色的小方块标志。如果在小方块的前面还有一个锁的图标,则表示该成员是私有(Private)的,若为一个钥匙的标志,则是保护(Protect)的,若没有其它图标,则是公共(Public)的。双击一个函数的名字,则编辑窗口的输入位置跳转到该函数的定义(实现)位置,若想跳转到它的声明位置,则可以右击Class View中的函数名,在出现的菜单中选择“Go To Declaration”一项;选择Property一项则可以直接查看该函数的属性,包括返回值类型、参数类型等。如果双击一个变量名,则会跳转到该变量的定义位置,同时也可以用Property这个右键菜单项来查看这个变量的类型。
若想新建类,则可以在Class View中的根节点(显示为XXX classes,XXX为当前项目名)的右键菜单中选择“New Class”项,之后在弹出的对话框中填写好相应的内容,点确定即可。之后VC会帮你产生相关的文件和类的最初定义信息,并将当前输入位置切换到新建的类实现文件中。要在类中新建函数或变量,可以在类名的右键菜单中选择“Add Memeber Function”或“Add Member Variable”项,填写好相应内容后,VC会自动产生代码并跳转输入位置。若要删除一个函数,特别是消息处理函数或映射函数,最好使用函数名右键菜单中的“Delete”命令,它不仅会清除掉函数的实现和声明,还会同时清除掉消息映射宏中的相关项(对于这部分的概念,我们以后还会详细介绍)。当然,除此之外,使用传统的纯手工方法也是可以的,只是前者工作量小而且不容易出错而已。
Class View中显示的内容是由VC自动维护的,它会依用户的修改自动完成更新,并在退出VC时自动保存。
2.3文件视图(File View)简介:
File View是VC界面左侧的第三个选项卡。它也是以树形图的形式显示的。文件视图中的文件虽然也是以类似WIN资源管理器中的文件夹树显示的,但这里显示的文件层次关系并不是实际存放的文件树,而是项目中各文件间的逻辑关系。每一个项目都有四个逻辑文件夹:Source File(源文件)、Header File(头文件)、Resource File(资源文件)和External Dependencies(外部依赖)。另外,还有一些不属于任何逻辑文件夹的文件,比如ReadMe.txt等,这些文件一般不需要开发者维护。 Source File中包括了程序中所有以.cpp和.c为后缀名的文件。Header File中是项目中的头文件(.h)。在Resource File中是项目中的资源文件,要编辑资源文件,一般不需要在这里打开,而可以在Resource View选项卡中打开相应的ID号来对它们进行修改。External Dependencies中的文件是项目的外部依赖文件。比如在你的项目中有一句“include XXX.h”,而XXX.h并不是项目中的头文件,则这个文件被认为是外部依赖的。刚打开项目的时候,VC一般不知道项目中有哪些外部依赖的文件,必须构建一次项目,这个文件夹中的内容才会被更新。有时候可以会发现在一些文件名的后面有一个“*”符号,这表示在这个文件中有未被保存的修改存在。
在File View中双击文件名则会打开这个文件,若其已经被打开,则将输入焦点切换到该文件。在文件名的右键菜单中选择Delete命令可以将这个文件删除出项目,但必须注意一点,这个文件并没有被删除,也没有被移动,只是被认为不再属于该项目。如果要真正删除该文件,还需要在VC外面删除这个文件。这一点在需要重写一个文件的候要特别注意,如果仅在File View中删除之,可能会造成一些奇怪的错误。
2.4资源(Resource)简介:
资源是Windows下编程的新概念。众所周知,WIN程序是以其精致的GUI(Graphice User Interface 图形用户界面)著称的。但是如果所有的图形都要在程序中通过绘图命令来实现,那工作量简直是不可想象的。除此之外,很多情况下,我们可能会希望程序能播放一些声音提示,如果把它们以文件的形式存放在程序之外当然未尝不可,但当然不如把它们直接写到程序里面方便。因此WIN下的程序引入了资源的概念,资源一般是一些图片、图标或其它程序中需要直接使用的非代码的组成部分,它们被存放在生成的EXE文件的“资源节(Resource Section)”中。项目中的每一个资源平时是单独以相应的文件形式存放在Res文件夹中的,而它们之间的关系则存放在.rc文件中。在编译的时候它们被编译成一种资源目标文件,然后和.obj、.lib文件等一起连接起来组成最终的EXE文件。
在项目中,每个资源用一个32位无符号整数常量标识,为了便于记忆,它们被用#define宏定义了相应的符号常量,比如IDI_MAINFRAME等,这被称为资源ID(Resouce Identifier)。这些宏定义存放在resource.h头文件中,所以一般你可以在很多.cpp文件中看到#i nclude "resource.h"的命令,这就是为了使它可以识别这些常量宏定义。resource.h是由VC维护的,当用户新增、删除资源或更改资源ID的时候,它会被自动更新。至于使用资源的方式,WinAPI和MFC都提供了很多相应的函数,这里就不再详述,它们并不是本文的重点。在VC界面左侧三个选项卡中的中间一个,就是Resource View(资源视图),它也是以类似File View的逻辑文件层次树的形式显示的。
需要说明的是,在这里对资源的介绍是很简略的,我们并不期望读者可以在这里完全学会资源的使用方法,只是希望诸位在这里先建立起“资源”的概念以便于我们后面的介绍。
2.5代码颜色:
也许在这里讨论代码的颜色有点可笑,但是要知道,在VC中,代码的颜色除了起装饰左右外还显示了相当的信息。在VC中代码主要有四种颜色:黑、蓝、绿和灰。黑色是最常见的颜色,所有普通的代码是用黑色表示的。蓝色则标识关键字,包括if、for这类程序流程关键字和int、float这些数据类型关键字,但是它只包括基本的ANSI C++类型,用typedef或#define生成的新类型是不被标识的,这一点的确让人颇为不满。绿色标识的内容是程序注释,即在/*...*/之间和//至行尾之间的部分。而灰色的代码是由Class Wizard(VC的组成部分之一)维护的代码,我们不建议用户修改,这可能导致Class Wizard的工作不正常,并且不能保证你的改动最后能被保留下来——Class Wizard完全有可能重写这段代码。
3.VC常用数据类型:
当然在VC中使用ANSI C++数据类型是完全可以的,但是VC里面增加了很多“新”的数据类型,之所以打上引号,是因为它们并不是真的新东西,而是通过typedef对已有的数据类型进行重命名而已。比如DWORD类型是typedef unsigned long DWORD;,即DWORD等价于unsigned long。这样做的目的在于增加代码的可读性,比如HANDLE和DWORD都是unsigend long,但从字面意义上可以看出,HANDLE类型表示句柄(WIN下的一个概念,这里不再详述,以后会详细介绍),而DWORD则表示一般的数据类型,显然一个函数声明写成DWORD GetPara(HANDLE hWnd)要比unsigned long GetPara(unsigned long hWnd)更容易理解。另外一点,DWORD比unsigned long要短的多,不要小看这一点点差别,当工程庞大的时候这可为我们写代码的时候省了不少输入工作。
下面就把在VC中常用到的新数据类形罗列如下:
BYTE unsigned char;
WORD unsigned short;
DWORD unsigned long;
LONG signed long;
LPTSTR char *;
LPCTSTR const char *;
LPVOID void *;
HANDLE unsigned long;
还有一个比较特殊的类型:BOOL,它是ANSI C++中所没有的。它实际上是一个整型,有两种取值,TRUE(1)和FALSE(0),当然也可以把它当做一般的整型数据来使用,不过我可不希望你这么做,毕竟我们是拿它来当布尔值来用的啊。
另外特别声明一点,在VC中,int和long一样是32位的,需要16位的×××应当定义为short形。这一点和以前的Turbo C不同。另外一点,在WIN编程中,所有的指针都是32位而不是16位的,因此它具有4GB虚寻址空间,所以就没有了DOS下的远指针、近指针概念,或者说,在WIN中所有的指针都是远指针,因此不用考虑寻址范围这种麻烦问题。
4.一个实例——一步步开始你的第一个VC程序:
上面讲了那么多,也许已经看的有写发昏了吧?的确,VC的概念是多了些,要想一下子都理解清楚并不是那么容易的事情。正如马克思注意哲学所说,人类对自然界的认识始终离不开实践,因此在本文的最后,我们来手把手的讲解一个实例,并借此来讲解一些技巧,希望能对读者的理解和记忆有所帮助。
这里我们要写的程序是一个简单的Windows Console程序(这是一种很接近于DOS下程序的WIN程序,它没有窗口、没有消息循环,因此结构简单,很适合用来学习C++时做练习之用)。当然我们可以做一个“Hello World!”,但我想还是做点更有智商的东西比较有趣,所以这次我们做的是一个小游戏:由程序在0~99中随机选取一个数,然后由玩家猜测计算机选择的是哪个数字。下面就是建立这个工程的基本步骤:
首先,让我们来建立我们的项目:
打开VC,选择File->New,之后会出先一个对话框。记住,我们曾经说过,VC中的基本单位是项目,因此首先让我们切换到“Project”属性页。在对话框的左側显示了一个列表框,其中显示了很多项目类型,一般常用的是MFC AppWizard(dll)(MFC动态连接库)、MFC AppWizard(exe)(MFC可执行程序)、Win32 Application(普通Win32程序)、Win32 Console Application(Win32控制台程序)、Win32 Dynamic-Link Library(Win32动态连接库)。这里我们选择Win32 Console Application,右面有两个文本输入框,一个是Location,即项目文件夹的位置,可以直接输入,也可以通过后面的“...”按钮选取。另一个是Project,即项目名称,也是项目文件夹的名字(项目文件夹的实际位置是Location\Project),其它的内容使用默认选项,点OK即可,然后进入下一设置。在这里为了以后叙述方便起见,我们假设项目名称是“Example01”,位置是“E:\项目\Teaching”。
当完成了刚才的设置之后,VC会启动一个叫做Application Wizard的组件,它通过向用户询问一些内容来自动产生项目的框架性代码,用户只需在这个构架中填入实现具体功能的代码即可完成一个程序。Console程序的App Wizard相对比较简单,它并不需要太多的信息。正如你看到的,它只有一步。这里显示的对话框中有四个选项,它们的意思分别是:An empty project,一个空项目,它不包含任何文件,所以一般不会使用这一项;A simple project,一个简单的项目,它包含一些纯构架性的代码,生成后直接可以编译成一个“什么都不做”的EXE程序,然后程序员在里面加入需要实现的功能即可完成程序的设计;A "Hello World!" Application,它产生的是一个Hello World程序的源代码,在Console下,这一项没什么用处,但在其它类型的项目中,我们有时会先建立一个这种类型的项目再加以修改得到最终程序,这比从simple project开始要省力的多;An application that supports MFC,一个支持MFC的项目,和A simple application差不多,但使用它的项目可以使用MFC中非界面部分的类,这是经常使用的选项,毕竟,使用MFC比纯粹用API要方便的多。但是在这里,我们似乎并不需要用到MFC的内容,所以我们选择第二项:A simple application,然后点击Finnish完成AppWizard的设置。在着之后,回出现一分报告,告诉你AppWizard都进行了哪些工作,同时,这里也是你最后一次后悔的机会,一但点击确定,AppWizard就开始按照你刚才的设置完成工作了,要知道,AppWizard进行的工作在完成之后是不能撤消或修改的,所以请一定要认真阅读这份报告来确定你刚才的设置是否正确。不过对于一个Console类型的程序,AppWizard的设置并不多,似乎也没什么可以出错的地方,所以让我们直接点OK吧。
下面让我们从File View中看看AppWizard倒底做了些什么吧!这时的项目中四个文件,分别是Example01.cpp、StdAfx.cpp、StdAfx.h和ReadMe.txt。Example01.cpp是程序的主文件,这个程序的Main函数就在这个文件中,以下就是其中的内容:
// Example01.cpp : Defines the entry point for the console application.
//
#i nclude "stdafx.h"
//
#i nclude "stdafx.h"
int main(int argc, char* argv[])
{
return 0;
}
{
return 0;
}
可以看出,这没什么特别的,所以我们就此跳过,在看看下面的文件。StdAfx.cpp和StdAfx.h是预编译头文件组。先让我们来看看它们的内容:
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_)
#define AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_)
#define AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// TODO: reference additional headers your program requires here
//`AFX_INSERT_LOCATION`
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_)
//`AFX_INSERT_LOCATION`
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_)
// stdafx.cpp : source file that includes just the standard includes
// Example01.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#i nclude "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
// Example01.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#i nclude "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
首先让我们看看StdAfx.h的前两行和最后一行,这被称为头文件保护机制。在这个文件头,首先判断是否定义了AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_宏,如果未定义(显然在一开始是这样的),则执行后面的代码:定义这个宏,然后写入头文件的内容,后面再来一个#endif。因此如果这个头文件被#i nclude了两次,则第一次已经定义了AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_宏,第二次包括这个头文件的时候就不会满足“该宏未定义”的条件,因此后面的那些头文件内容不会被重复包括一次。这就避免了一个头文件被直接或间接包括多次的错误。至于这个宏的名字,是VC起的,之所以起这么长,就是为了希望不要与用户定义的东西重复,我想不会有哪个程序员会想到在自己的代码中起这么奇怪的名字吧?然后我们可以在这个文件中找到一行:“// TODO: reference additional headers your program requires here”。这是在提示你把项目中要用到的所有头文件的#i nclude宏写到这里,然后再在所有的.cpp文件中使用#i nclude "StdAfx.h",这样做有很多好处:首先是因为方便。当我们要更改某些头文件的包括与否的时候,只需修改StdAfx.h中的内容即可,而不需要更改每个源文件中的#i nclude语句。另外一点,VC中有一种叫做“预编译”的机制:正如我们看到的,StdAfx.cpp中除了注释外就只有一行代码:#i nclude "stdafx.h",当VC在编译的时候,它会先编译这个文件产生一个.pch文件,然后在编译其它有#i nclude "stdafx.h"的文件的时候,只需连接上这个.pch文件即可,而不需要再编译一次stdafx.h中包含的头文件,这会大大提高编译过程的效率(当然,这种技术实现的方法可没有这么简单,我就不再长篇大论了)。至于stdafx.h中的其它内容,就不必管了。那么考虑一下我们的这个项目需要包含哪些头文件呢?当然iostream.h是一定要的,另外还需要time.h(为了后面的对time函数的调用)以及stdlib.h(标准库头文件),好吧,让我们在StdAfx.h中加入这么两行吧。以下就是修改后的stdafx.h内容(加黑体的是新增的部分)。
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_)
#define AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_)
#define AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// TODO: reference additional headers your program requires here
#i nclude "iostream.h"
#i nclude "time.h"
#i nclude "stdlib.h" //使用随机函数rand和srand需要包含此头文件。
//`AFX_INSERT_LOCATION`
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_)
#i nclude "iostream.h"
#i nclude "time.h"
#i nclude "stdlib.h" //使用随机函数rand和srand需要包含此头文件。
//`AFX_INSERT_LOCATION`
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__46C144A1_935D_4D36_9A04_F77C1728143A__INCLUDED_)
最后一个文件是ReadMe.txt,它是VC产生的一份项目描述文件,里面解释了项目各个文件的大致内容和意义。这里就不再讲解,其实那都是些陈词滥调,我认为意义不大。
看过了这四个文件的内容,让我们开始我们的工作吧!首先让我们先创建一个用来实现选择数字、对比数字的类。右键点击Class View的根节点(标题是Example01 classes),选择“New Class”,在之后出现的对话框中输入类名:CGuess(在VC中有将所有的类名以‘C’开头的习惯),在类名下面可以发现目前的类实现文件名为“Guess.cpp”,可以点击Change按钮修改之,但我们并不建议这样做,另外,这个类不需要基类,因此,下面的Base Class就让它置空好了。然后点击OK即可。之后你可以看到在Class View中增加了一个类CGuess,它有一个空构造函数和析构函数。下面先让我们来想想这个类需要哪些内容呢?首先它需要一个int型的成员变量m_wValue来记录计算机“想到”的是那个数。在Class View中的CGuess一项的右建菜单中选择“Add Member Variable”,即弹出新增变量对话框,在Variable Type中输入int,在Variable Name中输入m_wValue,另外一点,注意默认的存取权限(Access)是public的,为了遵守面向对象(OOP)的封装性原则,我们最好把它改成protect的,然后点OK则完成添加变量的操作。另外我们还需要一个变量来记录比较的次数,好吧,让我们用相同的方法来增加一个protect权限的int型变量:m_CompTimes。下面,我们认为还需要一个函数来让计算机来产生一个随机数。好吧,让我们来使用New Member Function这个命令。在弹出的对话框中填入相关内容:Function Type是void,Function Declaration是Initialize(),Access当然是public,Static和Virtual复选框置空,然后点OK按钮则在该类中添加了一个void CGuess::Initialize()函数,当然,它也是个空函数,内容还需要我们自己来写。下面我们再用同样的方式添加一个用来比较数字的函数:int CGuess::Compare(int wInput),当然,它也是public的。另外,为了能读取存取权限为protect的m_CompTimes,我们还需要一个public的int CGuess::GetCompTimes()函数。在这之后,就该写代码了,让我们来完成这个类的功能吧。修改后的Guess.cpp的代码如下(黑体是增加部分):
看过了这四个文件的内容,让我们开始我们的工作吧!首先让我们先创建一个用来实现选择数字、对比数字的类。右键点击Class View的根节点(标题是Example01 classes),选择“New Class”,在之后出现的对话框中输入类名:CGuess(在VC中有将所有的类名以‘C’开头的习惯),在类名下面可以发现目前的类实现文件名为“Guess.cpp”,可以点击Change按钮修改之,但我们并不建议这样做,另外,这个类不需要基类,因此,下面的Base Class就让它置空好了。然后点击OK即可。之后你可以看到在Class View中增加了一个类CGuess,它有一个空构造函数和析构函数。下面先让我们来想想这个类需要哪些内容呢?首先它需要一个int型的成员变量m_wValue来记录计算机“想到”的是那个数。在Class View中的CGuess一项的右建菜单中选择“Add Member Variable”,即弹出新增变量对话框,在Variable Type中输入int,在Variable Name中输入m_wValue,另外一点,注意默认的存取权限(Access)是public的,为了遵守面向对象(OOP)的封装性原则,我们最好把它改成protect的,然后点OK则完成添加变量的操作。另外我们还需要一个变量来记录比较的次数,好吧,让我们用相同的方法来增加一个protect权限的int型变量:m_CompTimes。下面,我们认为还需要一个函数来让计算机来产生一个随机数。好吧,让我们来使用New Member Function这个命令。在弹出的对话框中填入相关内容:Function Type是void,Function Declaration是Initialize(),Access当然是public,Static和Virtual复选框置空,然后点OK按钮则在该类中添加了一个void CGuess::Initialize()函数,当然,它也是个空函数,内容还需要我们自己来写。下面我们再用同样的方式添加一个用来比较数字的函数:int CGuess::Compare(int wInput),当然,它也是public的。另外,为了能读取存取权限为protect的m_CompTimes,我们还需要一个public的int CGuess::GetCompTimes()函数。在这之后,就该写代码了,让我们来完成这个类的功能吧。修改后的Guess.cpp的代码如下(黑体是增加部分):
// Guess.cpp: implementation of the CGuess class.
//
//
#i nclude "stdafx.h"
#i nclude "Guess.h"
//
//
#i nclude "stdafx.h"
#i nclude "Guess.h"
//
// Construction/Destruction
//
CGuess::CGuess()
{
m_CompTimes=0;
m_wValue=0;
::srand((unsigned)time(NULL)); // 初始化随机数种子
}
CGuess::~CGuess()
{
}
void CGuess::Initialize()
{
m_CompTimes=0;
m_wValue=rand()%100; // 产生随机数
}
int CGuess::Compare(int wInput)
{
m_CompTimes++;
return wInput-m_wValue; //比较
}
int CGuess::GetCompTime()
{
return m_CompTimes;
}
下面再让我们来完成Main函数的改写,修改后的Example01.cpp内容如下(黑体为新增部分):
// Example01.cpp : Defines the entry point for the console application.
//
#i nclude "stdafx.h"
#i nclude "Guess.h"
//
#i nclude "stdafx.h"
#i nclude "Guess.h"
(#include <iostream.h> //vc6.0中如用#include <iostream>则必须再加上一句即:using namespace std;
//stdafx.h中包含了此头文件则在.cpp源文件中就不要再包含此头文件了。
int main(int argc, char* argv[])
{
float fInput;
int wInput;
CGuess guessObj;
cout<<"\n********** 欢迎使用本程序! **********\n";
for(;;)
{
char sel;
cout<<"我已经想好数字啦(0~99),请猜吧!\n";
guessObj.Initialize();
for(;;)
{
int bComp;
cout<<"\n我想的是:";
cin>>fInput;
wInput=fInput;
bComp=guessObj.Compare(wInput);
if(!bComp)
{
cout<<"\n恭喜您,猜对啦!"<<endl<<"您一共猜了"<<guessObj.GetCompTimes()<<"次"<<endl;
break;
}
else if(bComp>0)
{
cout<<"\n对不起,您猜的数大啦!\n";
}
else
{
cout<<"\n对不起,您猜的数小啦!\n";
}
}
cout<<"\n您还想再玩吗?('n'=No,Others=Yes)\n";
cin>>sel;
cout<<'\n';
if(sel=='n'||sel=='N')
{
break;
}
}
cout<<"********** 感谢您的使用! **********\n";
return 0;
}
{
float fInput;
int wInput;
CGuess guessObj;
cout<<"\n********** 欢迎使用本程序! **********\n";
for(;;)
{
char sel;
cout<<"我已经想好数字啦(0~99),请猜吧!\n";
guessObj.Initialize();
for(;;)
{
int bComp;
cout<<"\n我想的是:";
cin>>fInput;
wInput=fInput;
bComp=guessObj.Compare(wInput);
if(!bComp)
{
cout<<"\n恭喜您,猜对啦!"<<endl<<"您一共猜了"<<guessObj.GetCompTimes()<<"次"<<endl;
break;
}
else if(bComp>0)
{
cout<<"\n对不起,您猜的数大啦!\n";
}
else
{
cout<<"\n对不起,您猜的数小啦!\n";
}
}
cout<<"\n您还想再玩吗?('n'=No,Others=Yes)\n";
cin>>sel;
cout<<'\n';
if(sel=='n'||sel=='N')
{
break;
}
}
cout<<"********** 感谢您的使用! **********\n";
return 0;
}
现在输入代码的工作就结束了,下面我们就可以编译了。一般点击工具栏上的“!”按钮就可以直接构建并运行该程序,如果希望编译Release版可以通过前面介绍的方法,从Set Active Configuration设置目前编译配置为Release即可。
这个例子到这里就结束了,我们在这里借这个例子联系了Application Wizard和Class Wizard的一些基本使用方法,相信会对读者将来的学习有所帮助。当然,这个例子并不完善,还有很多可以改进的地方,比如我们可以让猜测次数有限或者能够记录玩家已经猜过哪些数等等。当然,这部分就留给有兴趣的读者去完成啦。
5.结束语:
到此为止,相信诸位对于VC已经有了一些基本的概念和操作常识,那么我们要恭喜您终于具备继续往下学习的能力。祝您今后的学习愉快!
这个例子到这里就结束了,我们在这里借这个例子联系了Application Wizard和Class Wizard的一些基本使用方法,相信会对读者将来的学习有所帮助。当然,这个例子并不完善,还有很多可以改进的地方,比如我们可以让猜测次数有限或者能够记录玩家已经猜过哪些数等等。当然,这部分就留给有兴趣的读者去完成啦。
5.结束语:
到此为止,相信诸位对于VC已经有了一些基本的概念和操作常识,那么我们要恭喜您终于具备继续往下学习的能力。祝您今后的学习愉快!
----------------------------------------------------------------------------------------------------------
ps:工作区与工程的区别:
一个工程的结果就是一个EXE文件。
一个工作区可以包括多个工程,工作区这个概念就是为了管理多个工程设计的,比如要开发一个网络程序,有服务器和客户端两个程序(工程),那么我用一个工作区把两个工程都包括起来,方便管理,程序编译执行的最小单位还是工程,与工作区无关。
一个工作区可以包括多个工程,工作区这个概念就是为了管理多个工程设计的,比如要开发一个网络程序,有服务器和客户端两个程序(工程),那么我用一个工作区把两个工程都包括起来,方便管理,程序编译执行的最小单位还是工程,与工作区无关。
转载于:https://blog.51cto.com/eagle/166845