第一章C十十機健 31 记,而且它们最好是用于度量而不是用精确计数。 浮点数占四个字节,通常浮点数总是有符号的。如前所述,浮点常数输人可以用数字和 小数点,如1.2和一555.99等,另外还可以用科学表示法,即在数字之后加E,然后再加上 一个正或负的指数,指数为正时,即表示小数点需右移指数值的个数。指数为负时,小数点需 左移指数值的个数.例如,值2.5E4等价于25000;4.257E-3等价于0.004257。 1.4.2定义型常数 文字型常数用起来很方便,但它的含义不太清晰。例如,53的含义是什么?是某人的岁 数,还是其他别的含义。因此程序中的文字型常数如53,9832等经常使别人或编程者自己弄 不清楚其含义。好的办法是给常量取一个合适的名称。 为常数命名使用#define宏即可,下面给出两个这方面的实例 #define PAYOFF 53 define NEWLINE'\n 因为它们不是语句,因而不以分号结束。这些宏在编译的程序里不占任何空间。程序在 编译时,凡是遇#define后的名称时,就用名称后文本去代替程序中的名称。例如,语句: cout <<"Payoff was $*<PAYOFF <NEWLINE; C++编译时,就用53和n分别代替PAYOFF和NEWLINE 经过设置后,命名常数使程序更加清晰。实际上一些程序员仅使用全数字常数0和】 (有时是一I),它们为其他常数命名为FACTOR,RATE和TAX,有了这样的名称不用说明 别人就能明了程序的含义。 大多数情况,我们像程序清单1.13(DEFINE.CPP)中那样用#define来定义常数。在 DEFINE.CPP中我们定义了C++中几种数据类型的文字常数,它们的名称都有明确的含 义。main函数然后在输出流语句中使用这些常数,DEFINE.CPP中常数名称的定义都是大 写字符。 注:C+十中的宏与C中的宏大不相同。在宏中利用C和C++中的伪指令,可以让# define产生很复杂的命令。有关宏的特点要在以后的幸节里才能详细加以说明。因 此在这里给出的程序中,我们仅简单地使用了#define语句,并且我们建议读者目 前也这样做 程序清单1.13 DEFINE.CPP #include <stream.hpp 5:#define CHARACTER @' 6:林define STRING earning C+ DECIMAL 0b10011011 10.tdefine DECIMAL 155 11:#define FLOATING_POINT 3.14159
32 C十+套用转制教程 34 main() cout <CHARACTER <<'W STRING <n: 17 cout <<OCTAL <<\n' 18: cout <HEXADECIMAL <<n BINAR n 20 G.POINT 2: 在第5一11行中的右边,我们用大写字母定义了常数名称。为了便于阅读,我们以对齐 的方式给出了这些常数的值,实际上在C十+中,只需在名称与值间用一个空格符分开即可 (多余的空格符C+十将忽略). 同样在#deic中还可以加注释,这只需在值的后面加上一个(至少一个)空格符和双 斜线即可: #define FLOATING-POINT 3.14159 ∥Value for Pi 或用C风格注释: #define FLOATING-POINT 3.14159 /Value for Pi/ 1.4.3说明型常数 第二种常用的办法是在程序中定义普通的变量时,前面加上关键字cost,这样编译器 就不允许程序中的任何语句修改该变量的值。 程序清单1.14说明了如何用const来产生常数。与程序DEFINE.CPP比较而言,用 onst的定义规定了数据类型,以分号做为结束符,并向变量那样进行初始化。在用#define 定义时,不规定数据类型,不使用赋值号(一),并且不用分号做为结束。 程序清单1.14 CONST.CPP 1:/const.epp-Demonstrate declared constants #include <stream.hpp const char CHARACTER ='@': 6:const char STRING[] "Learning C++"; 7:const int OCTAL =0233; 8:const int HEXADECIMAL -0x9b 9:const in 0b10011011: FLOATING_POINT =3.14159: 12 13:main() 14:1 cour<C HARACTER <<m 18 ,八n
第一事C十十版述 33 cout oDECIMAL 八 21, cout <<FLOATING.POINT 八n: 22: 除了第六行中的常数STRING外,CNST程序中其他常数的名称与DEFINE中完全 样。在CONST.CPP中,STRING以方括号结尾。加上这个方括号是为了让C++产生 个字符数组,若没有方括号,编译器则认为第六行只是定义了一个单独的字符,而不是数组 C+十中的数组我们将在以后详细介绍.在DEFINE程序中用#define定义常数时则无需方 括号。 使用#define和cons定义常数时,编译器在值运算时是不同的。例如,我们写了语句: 读者可能会认为X的值为5,Y的值是X的值+10,但这样认为是一个严重的错误。Y 的值不是15,而是X+10,在用输出流语句 cout<<"X="<<X<<"Y="<<y, 时,C++编译器5和X+10分别插入X和Y的地方,然后计算X+10的值,而并不是在# define YX+I0后计算Y等于X+10的值。正因为这样,若在这条输出流语句的程序中有 这样的语句: #undef x #define X1o 在编译后的程序中X的值则由5变为10,同样表达式X+10的值也会更改(#undef是 将以前用#define语句做的定义取消)。Y的值之所以被修改,是由于在定义Y时并不对表 达式求值,而是在用到Y的语句时才求Y值。而在cost定义常数时就不会有这些问题。 在程序中用const产生常数还有其他优点。一,用cost定义的常数编译后的程序比# define的程序效率更高。二,由于用const定义常数时需定义数据类型,因而在编译时能立即 检查常数的值是否正确。而用#define定义的常数,只有在程序中的语句用到该常数名称 时,编译器才去检查数据类型是否有错。所以一旦用#define定义的常数数据类型有误,往 往较难发现。 1:4.4枚举常致 有些事物可以自然地分成一类,如纸和笔、齿轮和发动机、冰和雪,为将它们分类可将它 们命名为implements,giymos和badweather。为在程序中使用方便,我们可定义一些常数: 这样在程序中使用常数的名称PAPER和PEN将使用程序具有较好的可读性,而编译 器会自动用0和1来替换语句中出现的这些常量名称,实际上值0和1并无特殊意义,它们 只是为了使常量名称PAPER和PEN在语句里使用方便才设置的
34 C十十实阳将叫教粒 这种方法我们在编程时经常使用,但效率更高的方式是定义枚举型常数,枚举型常数最 有代表性的例子是定义颜色,途径如下: enumcolors(RED.ORANGE.YELLOW,GREEN.BLUE.INDIGO.VIOLET): 这种定义方式同时定义了常数名称colors和列在括号里的常数元素.关键字enum告诉 编译器这些元素是枚举的。编译器在编译时自动从0开始,分别对它们赋值:RED为0, ORANGE为1,.,VIOLET为6. 定义了枚举数据类型后,和其他数据类型一样,也可以产生同类数据类型的变量。例如 我们可定义colors类型的变量: olors favoriteColor -INDIGO 这样就产生了colors类型的变量favoriteColor,并将它们初值置为INDIGO。由于 favoriteColor是一个变量,我们还可以对它对赋值,例如: favoriteColor=ORANGE: 在colors前面加上关键字const就可以定义枚举常数。例如: const colors lastingColor=RED; 读者在编程时若按以上方式使用枚举型常数,一定会大大地增强程序的可读性,如果在 一条没有加注释的程序里,colo=4,其他人甚至编程者自己都很难明了4是什么含义。反之 赋值语句color=BLUE则读起来一目了然。 程序清单1.15(ENUM.CPP)给出了一些枚举常数的例子,以及如何在程序里使用这 些枚举常数。 程序清单1.15ENUM.CPP 1://enum.cpp-Demonstrate enumerated types 3:#include <stream.hpp> 5:enum LANGUAGE (ASSEMBLY,BASIC.C.CPP,FORTRAN.PASCAL)language; 6:enum scale (DO,RE,MI,FA,SOL,LA,TI) 7:enum (FALSE,TRUE): 8: main() one LA 12 RUE: 13 14. age CPP 15 cout <<"language-<<(int)language <'Vn' 16: cout <<"tone =<(int)tone<<'n'; 17: cout<"timeFlies<timeFlies<n' 18: 在第5行里用大写字母定义了枚举类型LANGUAGE,接者在结尾处用小写字母定义 了变量language,并在第14行为这个变量进行了赋值
第一幸C十十纯 35 注:C和C十十的很多程序员都采用这种方式,即用大写字母定义数据类型,并用小写 的同样字母定又变量。程序员在单独一条语句里定义数据类型和说明一个变量时, 往往用这种风格,在ENUM.CPP中我们也这样用,是因为这种方式较为常见.实际 上作者并不主张用大小写字母来区分数据类型和变量。 第6行仅说明数据类型,没有变量。在sCae数据类型中说明的是音符:DO,RE,ME, FA,SOL,LA和TI.数据类型scale产生之后,在第11行中定义了s心ale类变量tone,并将它 的初值置为LA。 第?行说明了如何建立无名称的枚举数据类型。元素FLSE和TRUE为C++增州 了两个新布尔值,FALSE等于0和TRUE等于1。和其他枚举类型一样,在程序语句中使用 它们来定各种条件时,比单纯用0或1来定义程序的可读性更好。 第12行在定义变量timeFlies时,使用了第7行新定义的布尔名称,置timeFlies的初值 为TRUE。在第7行中定义的非命名枚举类型TRUE或FALSE可直接给nt变量赋值,如 果我们以下述方式定义: enum Boolean (FALSE,TRUE) 由于在C十十中,赋值时数据类型必须一致,所以编译时第12行将出错。虽然下标元素 TRUE和FALSE分别取整数值0和1,但在说明中它们是Boolean类,而在C++中int和 Boolean类是不相容的。这时要将第12行做如下修改: enum Boolean timeFliesTRUE 同时由于输出流语句无法识别Boolean数据类,为了显示timeFiles的值第17行需改为 如下: cout<<timeFlies <<(int)timeFlies<<' 运行程序清单1.15,不难发现枚举数据类型显示时并不是枚举常数元素,如CPP,LA 和TRUE。因为输出流语句无法识别scal和LANGUAE,因而必须把它们强制成imt数据类 型。运行程序后的显示结果为 ag3 timeFiles=1 由于输出语句不知道scale和LANGUAGE是什么,因此输出语句必须用int对它们求 值。枚举数据变量名仅在程序文本中出现。当程序运行时,这些校举变量被转换为程序清单 1.15所显示的数字。 1.4.5枚举元素赋值 通常最好是让编译器为枚举数据类型元素顺序赋值。但在需要时也可以改变编译器为 元素所赋的值。例如,若编写了一个显示国际象棋的程序,可定义下面的枚举数据类型: enumpicce(PAWN.KNIGHT,BISHOP.ROOK.QUEEN.KING). 编译器将为这些元素顺序赋值,RAWN为0,KNIGHT为1,KNG为5。但如果枚 举值能反映各个棋子之间的相对重要性,这将便于计算机进行推理,以决定下一步的行棋