2.2 C++程序构架及词法符号约定
2.2.1 C++程序示例
先通过一个简单的示例来分析用该语言所编写的程序的基本结构及一些特点。
例2.1 一个简单的C++程序
//EX2_1.cpp:
//分别输入一个学生的3门功课成绩,根据其相应的学分,计算其加权平均值
#include <iostream.h> //预处理指令
double Average(double score1,double score2,double score3); //函数引用说明
void main()
{
double score1,score2,score3,average;
cout<<”第一门功课成绩:”;
cin>>score1; //接收用户输入
cout<<”第二门功课成绩:”;
cin>>score2;
cout<<”第三门功课成绩:”;
cin>>score3;
average=Average(score1,score2,score3); //调用子函数,用返回值为变量赋值
cout<<”加权平均分为:”<<average<<”\n”;//输出计算结果
}
//程序的子函数
double Average(double score1,double score2,double score3)
{
double credit1,credit2,credit3,average;
credit1=3.0;
credit2=4.0;
credit3=2.0;
average=(credit1*score1+credit2*score2+credit3*score3)/(credit1+credit2+credit3);
return average;
}
2.2.2 C++程序的一般结构
C++源程序以文件为单位进行存储。通常,最终被编译、链接成一个可执行文件的程序都包含一个工作空间(workspace),其中可以包括一个或多个不同性质的文件。
从总体上看,C++程序一般可以分成4个部分:预处理指令、全局说明、对象类的定义、程序的主函数和用户自定义的函数,如下图2.1所示。
预处理指令
全局说明
主函数
子函数1
.


子函数n
图2.1 C++程序的一个结构
2.2.2.1 预处理指令
在C++程序中,预处理指令就是源程序中所包括的各种编译命令。所有的预处理指令均以“#”号开始进行标识,而且“#”号还必须被置于该指令所在程序行的第一列。各种预处理指令在程序编译前执行,其作用是以中间文件的形式向编译器传递一定的信息,并不影响源程序。
引进预处理指令的目的是对C++程序设计环境进行扩展,使得进行程序开发时更加方便或控制程序编译的某些流程。
下面介绍几个常用的预处理指令。
1、预处理指令#include (最为常用的预处理指令)
在程序执行的过程中,经常要使用到各种编译系统提供的标准函数、类库提供的类以及用户开发的、存放在其它文件中的变量、函数和类等。而这些变量、函数和类等的说明和其它信息,都保存在相关的头文件(.h文件)中。为了使用头文件中定义的变量、函数和类,必须将相应的头文件包含到要使用它们的源文件中。为此可以使用预处理指令#include,该指令的格式为:
#include <headfile.h> 或 #include,headfile.h”
如果头文件名是由尖括号括起来,则编译器将在由编译系统设定的相应子目录中去搜索该头文件。一般用于将编译系统提供的标准头文件或类库提供的头文件包含到程序中。如果头文件名是由双引号括起来,则编译器将在当前目录中去搜索该头文件。一般用于将自己开发的头文件包含到程序中,以调用保存在其它源文件中的变量、函数和类等。如果编译器在相应的目录中找不到相应的头文件,将产生致命错误(fatal error)。
2、条件预处理指令由于被预处理包含指令#include所指定的头文件中也可以使用#include指令,因此就可能出现头文件嵌套甚至是头文件循环相互调用的情况,导致编译效率低下甚至失败的情况。
为了避免这种情况的发生,引入了条件预处理指令,用来标识是否已经包含了某头函数或头函数的部分。若已经包含,则在以后遇到要求包含该头函数或部分头函数的各部分时,跳过相应的部分。
条件预处理指令包括:
#ifdef #ifndef #define #else #endif
例2.2 条件预处理指令用法1。
#ifndef MYHEADFILE_H
#define MYHEADFILE_H


/*此处为头文件应加入的代码*/


#endif /* MYHEADFILE_H */
例2.3 条件预处理指令用法2。
#ifdef u362


/*此处专门为AT&T 3B计算机指定的代码 */


#endif /* u362 */
#ifdef sun


/*此处专门为SUN计算机指定的代码 */


#endif /* sun */
此处,我们看到了#ifdef预处理指令的一个重要用法:为程序的不同编译运行机型、不同编译系统等指定特定的代码,以使程序具有良好的可移植性。
例2.4 条件预处理指令用法3。
#ifdef _cplusplus


/*专门为C++语言指定的代码 */


#else


/*专门为C语言指定的代码 */


#endif /* _cplusplus */
3、宏替换指令#define
使用宏替换指令主要是为了简化代码和增强程序的可读性。C++中的宏替换主要有形式。
形式1:
#define 标识符 所代表的字符或常量 (如 #define PI 3.14159265)
在程序进行编译时,编译器会将遇到的PI用3.14159265进行替换。
形式2:
#define 标识符(参数) 表达式 (如:#define Area(r) PI*r*r)
2.2.2.2 全局说明全局说明一般包括一些程序所要使用的全局变量、类说明、用户定义的子函数的引用说明等。
在全局说明段进行说明的变量,其存在和使用是全局的,在程序运行的整个过程中一直存在,且占用同一段内存区域。
在全局说明段进行说明的子函数,编译器将为该子函数分配一段内存区域,用来保存该子函数的函数指针,在对该子函数进行说明之后的代码中,都可以调用该子函数,而不必关心该子函数的定义部分代码放在源代码的什么地方。
2.2.2.3 主函数任何一个C++程序都有一个且只有一个主函数。在面向DOS操作系统的编程中,主函数的名称为main(),而在面向Windows操作系统的编程中,主函数的名称为winmain()。
注意:在利用类库进行面向Windows操作系统的编程中(如利用VC++的MFC),有时在程序的源代码中看不到主函数winmain(),此时程序的主函数隐含在类库的链接库文件中,而该库文件在程序的主框架类的头文件中。
程序的主函数可以不带参数,也可以带有一个或一个以上的参数。若带有参数,则执行该程序时需要向程序提供相应的参数。
主函数的返回值有两种情况:无返回值及返回值为整型。若主函数的返回值类型说明为void,即无返回值的情况,在主函数中无需返回语句(return)或使用返回语句,而返回语句无表达式(return;)。若主函数的返回值类型说明为int,则程序返回值为0,表示程序运行正常结束,返回其他非零整型值表示程序异常返回。
2.2.2.4 用户自定义的函数
用户自定义的函数是程序开发人员为了实现某些特定的操作而编写的一组代码。这样做能简化代码,避免同样的代码多次重复书写,而且使得程序更加清晰易读、各部分代码功能目的明确。
子函数可以不带任何参数,也可以无返回值(void型),但常用的子函数一般都带一定数目的参数,这些参数可以按值传递,也可以按地址传递,或者同时含有两种参数传递方式,其用法和区别将在2.2节进行讨论。在函数体内,对这些参数进行一定的计算或判断,返回一个特定类型的数值,或通过改变按地址传递参数的数值,实现多值返回。即使无须返回任何数值的子函数,通常也将函数的返回值类型定义为布尔型(bool),利用返回真(true)和假(false)来判断子函数是否调用成功。
一般来说,程序定义的子函数,只能在该子函数定义之后的代码中被调用。为了在子函数定义之前的代码中调用某个子函数,可以在调用它之前的全局说明假中对该子函数进行引用说明。为了在其它源文件中调用在另一源文件中定义的子函数,可以在头文件中对该子函数进行引用说明,则在包含该头文件的所有源文件中都有可以对该子函数进行调用。
除了用户自己编写的函数外,还可以利用库函数来实现一些常用的操作。库函数是由编译器开发商或一些第三方的开发商所提供的,用于实现一些通用的一般操作而编写的函数。一般可以分为三类:
1、若干个以.H为后缀的头文件,其中包含了该组中所有库函数的原型定义。用户可以用任何文本编辑器打开该文件,并了解这些库函数的的函数名、调用参数、函数返回值类型等内容。对类库而言,从该头文件中还可以了解到各个类的定义、类的继承关系、类中的成员数据和成员函数等。
2、一个以.Lib为后缀的动态链接库,其中包含了各个库函数的实现。该.Lib文件也是由若干个后缀为.cpp的源文件和后缀为.h的头文件组合在一起,编译链接而成。只不过由于对编译器的设定不同而形成一种后缀为.cpp的特殊动态链接文件。在需要使用库函数的源文件或该源文件(.Cpp)所包含的头文件(.h)中将该含有该库的头文件(.h)包含进来。
函数定义的一般形式如下:
type function_name(variable_list)
{
statement1;
statement2;
,
.
.
return var;
}
其中,type是函数的返回值类型,function_name是该函数的函,variable_list是向该函数所传递的参数表,statement1,…..是为了完成该函数的功能所需要执行的各个语句,其中最后一个语句return var是将变量var作为函数的返回值传回函数调用处,变量var的类型应与函数的返回值类型type相匹配。而函数原型函数原型说明则只需要包含函数的返回值类型、函数名及参数表,如下所示。
Type function_name(variable_list);
2.2.3 C++的词法符号定
任何计算机语言都是规定了其可以使用的字符集合,同时由该字符集合中的某些元素进行组合,形成一系列具有特定意义的词法符号。利用这些词法符号,通过规定的规则,形成对程序需要执行操作的明确描述。以下将分别对C++中使用的字符集合及词法符号进行介绍。
2.2.3.1 C++中可以使用的字符集合
C++语言所使用的字符集合是ASCII码,包括:
1、基本代码——控制字符(32个),数字字符(10个),英文字母(52个),其它字符(34个)。
2、扩展代码——包括一些制表符和一些特殊的显示符号等。
2.2.3.2 C++规定的词法符号
词法符号是C++程序中编译系统所能识别和处理的最小的、不可再分配的语法单位。C++语言中共规定了六种词法符号:关键字、标识符、标点符号、常量、字符串和运算符。本节仅对关键字、标识符、标点符号进行介绍,其他类型的词法符号将在以后各节中分别进行介绍。
1、关键字
在程序中,不能将关键字用作一般的标识符和其他符号,而必须用小写英文字母表示。一般来说,C++的关键字有以下这些:
asm auto break case catch char class const continue default delete do double else entry enum extern float for friend goto if inline int long new operator overload private protected public register retun short signed sizeof static struct switch template this typedef union unsigned virtual void volatile while
2、标识符
标识符是程序员为程序中的一些元素所指定的名字,这些元素包括变量、数组、指针、函数、符号常量、类及对象等。
在C++语言中,标识符可以由英文字母、阿拉伯数字和下划线组成,并规定标识符的第一个字符必须是英文字母或下划线。一般将标识符的最大长度限定为32个字符(视具体编译器而定)。使用标识符时还应注意,不能使用C++的关键字作为标识符,否则编译系统会产生异义。
例如,以下标识符是非法的标识符:
3th_point,man&women,continue
注意:在C++语言中,区分英文字母的大小写。
例如:public 和Public
科学地使用标识符,便于记忆,同时增强程序的可读性和避免产生异义。如:
(1)、根据变量或函数的意义采用其相应的英文单词、英文单词缩写或汉语拼音作标识符;
(2)、合理地采用下划线分隔英文字母,使标识符意义明确;
(3)、采用大小写混合的英文字母,使标识符意义明确;
(4)、对于用宏定义说明的变量或符号常量使用全部为大写的英文字母加以区别;
(5)、对于标识类名的标识符采用特定的方法加以区别,如用C开头,其后紧跟该类的名称,且各独立单词的首字母大写,如CmyClassName。
3、标点符号
C++中的标点符号主要用来分隔不同的词法符号,主要有三种标点符号:
(1)空白符空白符在程序中起到分隔词法符号的作用。在编译时,空白符将被忽略(字符串中的空白符除外)。它包括空格字符(space)、水平制表符(tab,在字符串中用“\t“表示)、换行符(enter,在字符串中用“\n“表示)和注释四种。
注释用于对源程序中的某段代码的作用及实现方法等进行解释,它只为程序员使用,在程序的编译过程中被忽略。注释可以写在源代码中的任何位置。注释的实现方式有两种:
单行注释:用双斜线“//”进行标识,注释的内容从“//”开始,直到该行结束。
多行注释:用起始符号“/*”和终止符号“*/”进行标识。在“/*”和第一个“*/”之间的即为注释。
注意:注释不能嵌套。
例 使用空白符的简单例子
/*EX2_5.CPP
简单介绍各种空白符的使用*/
#include<iostream.h>/*预处理包含指令*/
void main()//程序的主函数
{
int i=10;//说明整型变量I
char *myStr=”Hellow!\nMy friend,\tgood lucky to your!\n”;
cout<<”I=”/*输出提示信息*/<<i/*输出变量值*/<<’\n’;//输出换行符
cout<<myStr;//输出字符串
}
可以利用适当地添加空白符来改善程序的可读性,使程序层次分明,更加清晰易懂。
(2)普通分隔符
普通分隔符用来分隔其它词法符号,在程序代码中有确定有含义,在程序编译时也不能被忽略,因此不能任意增减普通分隔符。普通分隔符共有10种,它们的表示及作用如下所示:
[ ]方括号,说明数组下标;
( )圆括号,说明函数参数表;
{ }花括号,说明复合语句、函数体等;
,逗号,分隔参数;; 分号,语句结束符;
,冒号,说明语句标号;
..,省略号,说明函数的可变参数;
* 星号,乘法运算符或说明指针;
= 等号,赋值运算符;
# 井号,预处理指令前导符。
(3)、续行符由于语句是C++程序语言的最小独立单元,而一个语句结束的标志是分号“;”。因此在一行之内可以有若干个语句,而一个语句也可以跨越若干行。一般来说,在不引起异义的情况下可以不使用续行符。但在表示一个字任串的时候,若字符串在一行内不能完全表示完整,这时需要使用续行符。
续行符用一个反斜线“\”和回车键表示,放在一行的末尾。在程序进行编译时,编译器遇到续行符时,忽略续行符,同时将其下一行作为该行的继续。
例如:
char *str=”This is a book which\
introduce how to develop C++ program.”;