C++的程序的文件结构.docx
- 文档编号:30489566
- 上传时间:2023-08-15
- 格式:DOCX
- 页数:28
- 大小:32.87KB
C++的程序的文件结构.docx
《C++的程序的文件结构.docx》由会员分享,可在线阅读,更多相关《C++的程序的文件结构.docx(28页珍藏版)》请在冰豆网上搜索。
C++的程序的文件结构
C++的程序的文件结构(zt)
Postedon2009-09-0323:
31CharlesChen阅读(300)评论(0) 编辑收藏网摘所属分类:
C/C++
因项目需要,需要对C++的程序的文件结构有所掌握:
因此在网上找了下面的文章供学习和参考。
希望对刚入门的C++朋友能提供一些帮助。
转载:
程序是由什么组成的?
学习到今天,我们至少有两个答案:
第1,程序由代码语句组成。
正是一行行的代码,组成了一个完整的程序。
第2,程序由函数组成。
一个个函数之间的互相调用,最终构建出一个完整的程序。
今天我们又有一个新的回答:
“程序由文件组成”。
程序为什么需要使用多个文件?
一个小的程序,可以只写一个源文件,但程序稍微一大,就需要将其中不同的逻辑实现放到不同的源文件.对于需要多人一起开发的软件,自然更需要多个源文件。
14.1源文件和头文件
和别的一些语言不同,C,C++的代码文件有“头文件”和“代码文件”之分。
二者合起来我们称为单元(Unit)文件。
扩展名为.c或.cpp的文件,主要用以实现程序的各种功能,我们称为代码文件。
扩展名为.h的文件,称为头文件。
在头文件里主要写一些函数、数据(包括数据类型的定义)、等的声明,这样可以在多个.c或.cpp文件内共享这些函数、数据。
第12章我们提过到头文件的功能。
说它可以起到函数“名片夹”的作用。
大都数时候,源文件和头文件是对应出现的,比如有一个A.cpp的源文件,就会有一个A.h的头文件。
这种情况在我们写应用程序时,更是常见。
所以C++Builder对此进行了强化。
比如,它支持在同名源文件和头文件之间通过热键来回切换。
在CB6.0里,编辑器打开对应的源文件和头文件时,将显示为同一页下的两个子页。
我们来实际动手看看源文件与头文件在CB里的对应关系。
运行C++Builder6或5。
这一次我们需要一个空白的Windows工程。
很有可能,在你打开CB时,它就自动为你打开了一个工程。
为了不出错,我们还是亲自建一个。
CB6请使用主菜单:
File|New|Application;而CB5则使用:
File|NewApplication新建一个Windows空白工程。
如果在这过程中CB出现是否存盘的询问,请回答不存盘。
找到“代码窗口”。
如果你看到的是一个叫"Form1"的表单,请按F12,“代码窗口”将跑到前面。
它的标题应该是默认的"Unit1.cpp"。
正是当前代码文件的文件名。
如下图:
对于CB6,还可以看到在该窗口的底部有这样一个分页:
源文件:
Unit1.cpp和头文件:
Unit1.h并列着,我们可以方便地选择。
至于"Diagram",称为“图解”。
这是一个给这个源文件加配套注解,及表单上各控件的依赖关系的地方。
如果是一个开发小组在进行共同开发,严格地要求每个成员为每个单元文件写上“Diagram”,可以更好地实现程序员之间的沟通。
CB5没有这些,不过下面的热键操作两个版本均一样的,要求大家记住。
按Ctrl+F6可以在源文件和头文件之间来回切换。
请大家试试。
这个简单的操作将在我们今后的编程过程中高频率地使用。
14.2如何创建多个单元文件
前面我们在“Windows应用程序工程”中看到了头文件与源文件的匹配关系,在“控制台”的工程中,也同样存在。
不过由于控制台经常只用来写一些小小的程序,所以往往只需一个源文件即可。
由于只有一个源文件,所以也就不存在函数、数据在多个文件之间“共享”的需要,因此边头文件也就可以不提供。
那么,是不是只有在程序很大,或者只有在有很多人同时开发一个软件时,才需要多个源文件呢?
这就好像你家里只有两本书:
《红楼梦》和《格林童话》,是把它们放在同一个抽屉里呢?
还是分开放到两个抽屉里?
我觉得后者是比较好的选择。
因为我们常常希望家里看《格林童话》的人,最好不要去看《红楼梦》。
程序也一样,最好把不同的逻辑实现,放到不同的源文件中。
下面我们做一个实例。
例子的代码我们都已经学过。
目标是实现一个可以求统计值和平均值的程序。
根据我们现在所学的情况,我把这个工程中的代码分为三个源代码:
其一:
主程序。
就是main()函数所在的代码。
这个源文件实现总的流程。
我将该文件取为main.cpp。
其二:
计算总和及计算平均值的代码。
这个源文件负责用户计算过程,也包括每个过程所需输入输出。
该文件将被存盘为mainfunc.cpp。
意为主要功能。
其三:
assifunc.cpp。
表示辅助功能函数所在代码。
它只提供一个函数:
将用户输入的大写或小写的字母'Y'或'N'确保转换为大写。
这个函数将main()主函数内,判断用户是否继续时用到。
新CB新建一个控制台程序(如果你还开着上个程序,先选File|CloseAll关闭它)。
CB会自动生成第一个文件,不过现在的名字为“Unit1.cpp"。
接下来是一项新工作,我们来添加两人新的单元文件,即上面说的“其二”和“其三”。
CB6:
File|New|Unit;CB5:
File|NewUnit。
请进行两次以上操作,CB将为我们生成新的两个单元文件:
Unit2.cpp和Unit3.cpp。
大家可以再试试Ctrl+F6。
(注意,第一个单元文件:
Unit1.cpp没有配套的.h文件,所以不要在该文件里尝试Ctrl+F6)。
然后选择File|SaveAll。
全部存盘,最好不要存在CB默认的目录下。
记得按以下关系重命名:
Unit1.cpp存盘为main.cpp;
Unit2.cpp存盘为mainfunc.cpp;
Unit3.cpp存盘为assifunc.cpp;
至于总的工程,随你便,我图方便,还是叫:
Project1.bpr。
(现在我们第一次在一个工程中用到多个源文件。
所以你得学会如何快速打开一个工程中某个源文件——当然,现在这三个文件都已经打开着,不过假设你有点事关闭CB,我们不希望下回打开这个工程时,你“找”不到第2和第3个文件了——请点击CB工具栏上的这个图标:
,将出现源文件列表对话框,如左图)
接下来讲在这三个文件中,我们分别写些什么?
大多数代码我们都已经在前面学过,所以我对代码的功能不作太多的解释。
我们的重点是:
三个源文件之间的代码如何实现“沟通”。
第一个文件:
main.cpp用来实现程序的主流程。
在main.cpp中的main()函数内,我们加入代码。
#include
......
intmain(intargc,char*argv[])
{
charch;
intcount;//求总和或平均值时,需要输入的成绩个数
do
{
cout<<"1)求总和"< cout<<"2)求平均"< cout<<"请选择(1或2)"; cin>>ch; //输入有误,重输: if(ch! ='1'&&ch! ='2') { cout<<"输入有误,请重新输入! "< continue; } cout<<"请输入个数: "; cin>>count; //根据用户的选择,调用不同函数: switch(ch) { case'1': CalcTotal(count);//需要调用的函数之一 break; case'2': CalcAverage(count);//需要调用的函数之一 break; } //是否继续: cout<<"是否继续? (y/n)"; cin>>ch; //确保转换为大写: ch=ToUpper(ch);//需要调用的函数之一 } while(ch=='Y'); return0; } 代码中,红色部分的注释表明,主函数main()需要调用到三个自定义函数。 但现在我们一个也没有定义。 和往常把所有的函数定义在同一个代码文件中不同,今天我们需要把它们分开到不同的代码文件。 第二个文件: mainfunc.cpp存放和计算有关的两个过程(函数)。 先看: CalcTotal()和CalcAverage()。 这两个函数我们将在mainfunc.cpp文件内定义。 你可能又忘了“定义”这个术语? 呵,就是“实现”,更白点,就是在mainfunc.cpp文件内“写”这两个函数。 下面是mainfunc.cpp的内容。 在我们输入以下代码时,mainfunc.cpp已经有了一些必要的内容,下面的代码,除了“#include..”一行在文件最首外,其它均在原有内容之后添加。 #include ...... //--------------------------------------------------------------------------- //求总和的过程 //参数: n用户需要输入的个数 voidCalcTotal(intn) { intnum; intsum=0; for(inti=0;i { cout<<"请输入第"< "; cin>>num; sum+=num; } cout<<"总和为: "< } //--------------------------------------------------------------------------- //求平均值的过程 //参数: n用户需要输入的个数 voidCalcAverage(intn) { intnum; intsum=0; floatave; for(inti=0;i { cout<<"请输入第"< "; cin>>num; sum+=num; } //注意不要除0出错: if(n>=0) { ave=(float)sum/n; cout<<"平均值: "< } else { cout<<"个数为0,不能求平均。 "< } } //--------------------------------------------------------------------------- 第三个文件: assifunc.cpp用以存放辅助作用的函数,现在只有一个。 现在还差一个函数: ToUpper()。 这个函数用来将用户输入的某个小写字母转换为大写。 当然,如果用户输入的不是小写字母,那就不用转换。 和上面的两个函数不同,它需要返回值。 我们把ToUpper()函数单独放在assifunc.cpp里。 同样,下面的代码加在该文件中原有的代码之后。 不过本文件不需要include //小写字母转换为大写 //参数: c待转换的字符 //返回值: 转换后的字符,如果原字符不是小写字母,则为原字符 charToUpper(charc) { intca='A'-'a';//大写字母和小写字母之间差距多少? if(c>='a'&&c<='z') c+=ca; returnc; } 至此,所有自定义函数都已完成定义(实现),而三个文件的主要内容也以确定。 让我们看看示意图: main.cpp中的main()函数调用了三个函数。 回忆我们学习过的“如何调用函数”的知识,当前代码在调用一个函数时,必须能“看到”这个函数。 尽管CalcTotal()、CalcAverage()、ToUpper()三个函数所在文件都在同一工程里,但是在main.cpp里的代码,还是看不到它们。 想一想我们以前说的“请修理工”的比喻。 现在情况是: 在你所住的小区,甚至就是同一楼道里,就有一个电视修理工,但可惜你们互不认识,所以当你电视坏了,想“调用”一个修理工时,你还是找不到修理工。 哎! 要是有它的名片就好了。 让我们试试看,按Ctrl+F9,编辑该工程。 出错! 正好是三个错。 分别告诉我们调用了三个没有定义的函数(Calltoundefinedfunction...)。 (如果你出现的是一堆错,那有可能是你没有在前两个文件内最首行写: “#include 或者是你有些代码输入有误。 ) 如何消除这三个错? 两种方法。 第一种方法就是以前我们在讲“如何调用函数”的时候所说的,直接在调用直接声明要调用的函数。 这里写出代码,算做是一次复习,然后我们将讲该方法不好之处。 在main.cpp的main()函数之前加入如下三行函数声明: voidCalcTotal(intn); voidCalcAverage(intn); charToUpper(charc); intmain(intargc,char*argv[]) { ...... } (上例中,尽管你可以将三行函数声明写在main()函数体内,但不建议这样做)。 如果你一切输入正确的话,现在按Ctrl+F9或F9将可以完成编译或运行。 对于现在这个工程,这种方法确实也不能指责它有何不利之处。 问题在于,如果我们还有其它文件中代码需要调用到这三个函数,我们就不得不在其它文件中也一一写上这三行声明。 所以另一种方法是: 把源文件中需要对外“共享”的函数声明统一写到某个头文件,然后凡是需要用到的其它文件,直接使用“#include"语句来包含该头文件,从而获得这些函数声明。 14.3如何写头文件 在CB中,如果你通过上小节的方法新建个单元文件,那么CB将自动同时生成源文件和头文件。 其实在CB里,源文件和头文件合称为单元文件,它们有相同的文件名,而扩展名一者为.cpp,另一为.h。 14.3.1在头文件内加入函数声明 头文件: mainfunc.h CalcTotal()和CalcAverage()函数定义在mainfunc.cpp文件里,所以它们的声明最好写在对应的头文件mainfunc.h内。 下面我们就来看如何在头文件mainfunc.h内增加函数声明。 一开始,头文件内有以下这些代码。 另外,我增加了一行用于标明我们新加的代码应写在哪里。 //--------------------------------------------------------------------------- #ifndefmainfuncH #definemainfuncH //--------------------------------------------------------------------------- /*! ! ! 头文件中,我们新增的代码必须写在此处! ! ! */ #endif 和源文件中新增代码添加在最后不一样,头文件中新加代码必须在#endif之前插入。 所以本例中,加完函数声明的代码应如其下所示。 (另外,CB总是在头文件的第二行留了一行空白行,我不知道它这是有意还是无意。 总之这里是我们写本文件总体注释的好地方。 记住,头文件像名片,用于让别人看,很有必要写得详细点) //--------------------------------------------------------------------------- //主要操作函数 #ifndefmainfuncH #definemainfuncH //--------------------------------------------------------------------------- //计算总和: voidCalcTotal(intn); //计算平均值: voidCalcAverage(intn); //--------------------------------------------------------------------------- #endif 这就是“在头文件中声明函数”的整个过程。 下面是另外一个头文件。 头文件: mainfunc.h //--------------------------------------------------------------------------- //辅助操作函数 #ifndefassifuncH #defineassifuncH //--------------------------------------------------------------------------- //将字符转换成大写 charToUpper(charc); #endif 今天我们学的是如何在头文件内声明函数,以后我们需要在头文件内声明变量,或者定义新的数据类型,它们都一样需要在上述的#endif之前加入。 14.3.2最常见的预编译语句 现在来解释这三行话: #ifndefmainfuncH #definemainfuncH #endif 中间的#definemainfuncH我们有点脸熟。 在第五章《变量与常量》中,我们讲过用宏表示常数。 语法为: #define宏名称宏值 比如,定义一个∏值: #definePAI3.14159 这里我们学的是宏定义的另一种用法: 仅仅定义一个宏,不需要给出它的值,语法为: #define宏名称 比如: #definemainfuncH 定义了一个宏: mainfuncH。 如果你无法理解“宏”这个词,不妨就当把它解释成“记号”。 即编译器通过该语句,做了一个记号,记号名称为: mainfucH。 这么做的作用是什么呢? 我们继续看上下文。 #ifndef中,if是“如果”,n是no,即“还没有”,def是define,即“定义”,那么: #ifndefmainfuncH意为: “如果还没有定义mainfuncH这个宏”,那么…… 那么之后做什么呢? 就是一直到#endif之间的语句。 总的再来看一遍: mainfunc.h中的主要内容: #ifndefmainfuncH #definemainfuncH voidCalcTotal(intn); voidCalcAverage(intn); #endif 当编译第一次编译mainfunc.h文件时,宏mainfuncH还没有定义,因些,编译器通过对#definemainfuncH的编译而产生了宏mainfuncH。 当编译器第二次编译到mainfunc.h文件时,宏mainfuncH已经存在,所以该头文件被直接跳过,不会重复处理该头文件中内容,比如上面的两个函数声明。 你可能会问两个问题: 第一,为什么编译器可能多次编译到同一个头文件? 第二,为什么源文件,比如mainfunc.cpp就不需要用到#ifndef...#endif? 这两个问题只要回答了其中一个,另一个也就自然消解。 这是由头文件特性所决定的。 头文件是用来被别人包含(include)的。 谁都可以指定要包含某一头文件,这样就可能造成对该头文件的重复包含。 假设有头文件head.h。 如果A文件包含了head.h,而B文件也包含了head.h,那么编译器不会在编译A和编译B时,都要对该头文件尝试编译一次。 另外,头文件本身也可以包含另一个头文件,这种情况下,各文件之间互相嵌套包含的情况就更多了。 源文件(.c或.cpp)尽管可以,但一般不被用来被别的文件包含,所以不需要在源文件中加这些语句。 当然,如果需要,你也可以源文件中使用#ifndef...#endif。 每生成一个头文件,包括在重命名它时,CB会为我们取好该头文件中,上述的宏名称,它取该头文件的全小写文件名,加上一个大写的‘H’字母,比如: "mainfuncH"。 请大家不要改变该宏的名称,以免出错。 除了#ifndef...#endif语句外,还有它的相反逻辑的语句: #ifdef...#endif它是在如果有定义某个宏,那么,编译将继续其后的语句。 另外就像有if语句,还有if...else...语句一样,有#ifdef...#endif,也就还有这个语句: #ifdef ...... #else ...... #endif 不过这些都和我们这里的头文件相关不大,我们暂时不讲。 最后我们来解释一个名词“预编译”。 编译器在编译代码时,至少需要两遍的编译处理,其中第一次,就是专门用于处理所有以#开头的语句,如上述的#ifndef...#endif、#define等等。 这一遍处理,我们称为预编译。 14.4如何使用头文件 事实上我们经常在使用头文件。 不过,以前我们一直在使用别人的头文件,今天是第一次使用我们自已的写的头件。 以前,我们几乎每个例子,包括今天的例子中,都需要在源文件的顶部写上一行: #include 或者: #include iostream.h和stdio.h都是CB提供给我们的头文件。 这些头文件随CB安装时,被保存在固定的文件夹内。 今天的例子中,main.cpp需要使用到在mainfunc.h和assifunc.h。 这是我们自己写的头文件,它们保存在我们自定的文件夹中。 包含自已写的头文件,和包含CB提供的头文件并无多大区别。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C+ 程序 文件 结构