第2章“有关对象的思考”一节开始了关于电梯模拟程序的面向对象设计(OOD)的第一个阶段,即确定实现电梯模拟程序所需要的对象。作为入手点,可以列出问题陈述中的名词,这样就可
以发现电梯模拟程序中的对象有电梯、人、楼层、大楼、各种按钮、时钟、电灯与电铃等等。
第1章介绍对象时曾经指出过对象有属性和行为。对象属性在C++程序中表示为数据,对象行为在C++程序中表示为函数。本节要确定实现电梯模拟程序所需对象的属性。第4章要确定对象行为。第5章要确定电梯模拟程序中对象与对象之间的交互,称为协作(collaboration)。
下面先介绍现实世界中对象的属性。一个人的属性包括身高、体重等。收音机的属性包括调频、调幅、调台和当前音量的设置。汽车的属性包括车速表和全程表、汽油用量表、档位等等。房子的属性包括建筑风格(古典式、现代式)、房间数、面积和层数。个人计算机的属性包括厂家(Apple、IBM、Compaq等等)、显示器类型(黑白或彩色)、主存大小、硬盘容量等等。
1.首先在字处理器和编辑器程序中输入模拟电梯的问题陈述文本(见2.11节)。
2.找出问题中的事实。消除不相关的文本,并将每个事实放在一行(问题陈述中大约有60个事实)。下面是事实文件的第一个部分:
事实文件
两层办公楼
电梯
电梯上的人
门
第1层
方向——上和下
时钟
时间0
每秒滴答一次
电梯模拟程序的调度器组件
随机设置每层第一个到达的人
第一次到达的时间
电梯模拟程序
对指定层生成新的人
将人放在该层
人按下该层的向上或向下按钮
该层的向上或向下按钮
人的目标层
人所在的层
第1层第一个出现的人
出现在第一层的人
人上电梯
人按向上按钮
3.将所有事实分类组合以确定第2章练习中的类。用概述形式,在页的左边列出类,并缩排一个制表符大小以列出该类相关的事实。有些事实只涉及一个类,有些事实涉及多个类。每个事实最初应列在每个涉及该事实的类中。注意“方向--上和下”等事实并不显式地属于某个类,但还是要放在一个类中(本例中,该方向是电梯移动的方向)。这个概述文件用于该任务和下面几个任务。
4.现在将每个类的事实分为两组。第一组标为“属性”,第二组标为“其他事实”。目前操作(行为)应放在“其他事实”中。将操作放在其他事实中时,考虑是否要生成“属性”中的附加项目。例如“电梯关门”是其他事实中的操作,但表示门的属性可开可关:“该层已有人占用”是层的属性,一个层总是被占用或不被占用。电梯的属性包括:运动或停止,有人或无人,向上或向下;按钮的属性是开或关;人的属性是目标层等等。
1.首先列出问题陈述中明确提到的类属性.然后列出问题陈述中隐含的类属性。
2.在需要时增加相应的属性。
3.系统设计不是完善和完整的过程,只要尽力而为,后面几章的练习将会介绍如何对设计进行修改。
4.对象可以是一个类的属性,称为复合。例如,电梯中有第1层和第2层的按钮对象,人需要
按这些按钮以选择目标层。本练习中分别处理所有的类,而不进行复合。第5章将介绍复合。
5.本章介绍了如何实现”随机性”,最终实现电梯模拟程序时,可以用下列语句计划一层中下一个到来的人:
arrivalTime=currentTime+ ( 5+rand( ) % 16);
●要开发和维护大程序,最好的办法是从更容易管理的小块和小组件开始。C++中的模块称为函数和类。
●通过函数调用来调用函数。函数调用指定函数名和提供被调用函数完成任务所需的信息作为参数)。
●信息隐藏的目的是函数只能访问完成任务所需要的信息,从而实现最低权限。这是良好的软件的最重要特性之一。
●调用函数的格式为:先写上函数名,后面跟着左括号,然后是函数参数(或逗号分隔的参数表),最后是右括号。
●double和float都是浮点数据类型。float类型变量能存放比double更大、精度更高的数值。
●函数参数可取常量、变量或表达式。
●局部变量只在声明该变量的函数中有效。函数不能知道任何其他函数的实现细节(包括局部变量)。
●函数定义格式如下:
return--value—type function—name(parameter—list) { declarations and statements }
函数名是任何有效标识符,返回值类型是函数向调用者返回的值的数据类型.返回值类型为void表示函数没有返回值。参数表是逗号分隔的清单,包含传递给函数的参数的声明。如果函数不接受任何值,则参数表为void或空着。花括号中的声明和语句构成函数体。
●函数定义和函数调用的形参和实参的个数、类型、顺序和返回值类型应该相符。
●程序遇到函数时,控制从调用点转入被调用函数,执行该函数,然后控制返回调用者。
●将控制返回函数调用点的方法有三种。如果函数不返回结果,则控制在到达函数结束的右花括号时或执行下列语句时返回:
return;
如果函数返回结果,则下列语句:
return expression;
向调用者返回表达式的值。
●函数原型声明函数名称、函数返回的数据类型、函数要接收的参数个数、参数类型和参数顺序。
●编译器用函数原型确定正确地调用了函数。
●编译器忽略函数原型中提到的参数。
●每个标准库都有对应的头文件,包含库中所有函数的函数原型和这些函数所需各种数据类型和常量的定义。
●程序员可以生成和包括自定义的头文件。
●通过按值调用传递参数时,参数值生成副本并传入被调用函数。副本的改变并不影响调用者的原始变量值。
●rand函数产生0到RAND_MAX之间的整数,RAND_MAX的值至少应为32767。
●rand和srand的函数原型在 <stdlib.h>中。
●通过比例缩放和移动,可以调整1+and()%6产生的整数值范围。
●随机化是用标准库函数srand函数完成的。
●srand语句只在程序完全调试之后才插入程序中。调试时最好省略srand语句,这样可以保证重复性.也是保证修改后的随机数产生程序正确工作的基础。
●如果不想每次输入种子值而随机化.则要用如下语句srrnd(time(0)),使计算机通过时钟值自动取得种子值。time函数(上述语句中的参数0)返回当前“日历时间”的秒数。time函数的函数原型在 <time.h>中。
●可以将随机数结果一般化为如下形式:
n = a + rand( ) % b;
其中n是位移值(等于所要的连续整数范围的开始值),b是比例因子(等于由连续整数构成的该范围的宽度)。
●枚举类型由关键字enum和类型名构成.是一组用户标识符表示的整数常量。
●这些枚举常量的值从。开始.增量为1,但也可以指定其他值。
●enum中的标识符必须惟一,但不同枚举常量可以取相同的值。
●任何枚举常量可以在枚举定义中显式地赋给一个整数值。
●每个标识符都包括存储类、作用域和连接属性。
●C++提供了4个存储类说明符:auto、register、extern和static。
●标识符的存储类确定标识符在内存中存在的时间。
●标识符的作用域是程序中能引用这个标识符的区域。
●标识符的连接确定多源文件程序中,只有当前源文件或是在任何正确声明的源文件中识别标识符。
●自动存储类变量在进入声明该变量的程序块时生成,在程序块活动期间存在,在退出这个程序块时删除。函数的局部变量和参数通常是自动存储类。
●存储类说明符register可以放在自动变量声明之前,让编译器在计算机的高速寄存器中保存这个变量。编译器可以忽略register声明。关键字register只能用于自动存储类的变量。
●关键字extern和stattc声明静态存储类函数和变量的标识符。
●程序开始执行时就分配和初始化静态存储类。
●静态存储类有两种标识符:外部标识符与存储类说明符static中声明的局部变量。
●全局变量生成时将变量声明放在任何函数定义之外,全局变量在整个程序执行期间保留其数值。
●static局部变量在函数退出时保持其数值。
●所有静态存储类的数字变量默认初始化为0,但也可以由程序员显式初始化。
●一个标识符的4个作用域是函数范围、文件范围、块范围和函数原型范围。
●标号是惟一具有函数范围的标识符。标号可以在所在函数中任何地方使用,但不能在函数体之外引用。
●任何函数之外声明的标识符的作用域是文件范围。可以从声明该标识符处到文件末尾的任何函数中访问该标识符。
●块中声明的标识符的作用域是块范围。块范围从标识符声明开始,到表示程序终止的右花括号(1)处结束。
●函数开头声明的局部变量的作用域是块范围,函数参数也是,它们也是函数的局部变量。
●任何块都可以包含变量声明。块嵌套时,如果外层块中的标识符与内层块中的标识符同名,则外层块中的标识符“隐藏”,直到内层块终止。
●只有函数原型参数表中使用的标识符才具有函数原型范围。参数表中使用的标识符可以在程序中其他地方复用,不会产生歧义。
●递归函数是直接调用自己或通过另一函数间接调用自己的函数。
●如果函数调用基本情况,则只是返回一个值。如果在更复杂的问题中调用函数,则函数将问题分成两个概念性部分函数中能够处理的部分和函数中不能够处理的部分。由于这个新问题与原问题相似,因此函数运行递归调用处理这个较小的问晤。
●要让递归最终停止,每次函数调用时都要使问题进一步简化,从而产生越来越小的问题,最终合并到基本情况。这时,函数能识别这个基本情况,将结果返回前一个函数调用,井回溯一系列结果,直到原函数调用最终返回最后的结果。
●C++语言只指定四种运算符的操作数求值顺序,即 &&、||、逗号运算符(,)和:。前三种是二元运算符,操作数从左向右求值。第四种是C++惟一的三元运算符,先求值最左边的操作数,如果最左边的操作数非0,则求值中间的操作数,忽略最后的操作数:如果最左边 的操作数为0,则求值最后的操作数,忽略中间的操作数。
●递归与迭代都是基于控制结构:迭代用重复结构,而递归用选择结构。
●递归与迭代都涉及重复操作:迭代显式使用重复结构,而递归通过重复函数调用实现重复。
●递归与迭代都涉及终止测试:迭代在循环条件失败时终止,遵归在遇到基本情况时终止。
●迭代和递归都可以无限进行:如果循环测试永远不变成false,则迭代发生无限循环;如果递归永远无法归并到基本情况,则发生无穷递归。
●递归重复调用机制,因此重复函数调用的开销很大,将占用很长的处理器时间和大量的内存空间。
●如果要编译C++程序,就要求提供每个函数的函数原型或先定义再使用每个函数。
●不返回数值的函数用void返回类型声明。想从这个函数返回一个值或在调用函效中使用这个函数调用的结果是个语法错误。
●空参数表用空括号或void指定。
●内联函数可以减少函数调用开销。关键字inline指示编译器在适当的时候将函数代码复制到程序中,以减少函数调用。编译器可以忽略内联函数的声明。
●引用参数是C++提供的两种按引用调用的方法之一。要表示函数参数按引用传递,只要在函数原型中参数类型后面加上 &。在函数调用中,只要指定变量名,即按引用调用传递该变量。在被调用函数中,通过参数名指定的变量实际上就是引用了调用函数中的原始变量,被调函数可以直接修改原始变量。
●引用也可以用作函数中其他变量的别名。引用变量必须在声明中初始化,不能作为其他变量的别名而重新赋值。将引用声明为另一变量的别名后,对该别名(即引用)进行的所有操作实际上是对原始变量本身进行。
●程序员可以提供默认参数的默认值。调用函数时如果省略默认参数,则采用该参数的默认值。如果省略的参数不是参数表中最右边的参数.则该参数右边的所有参数也应省略。默认参数应在函数名第一次出现时指定,默认值可以是常量、全局变量或函数调用。
●一元作用域运算符可以在同名局部变量作用域中访问全局变量。
●C++允许定义多个同名函数,这些函数采用不同参数集(至少有不同类型的参数)。这个功能称为函数重载。调用重载函数时,C++编译器通过检查调用中的参数个数、类型和顺序来选择相应的函数。
●重载函数可以有不同的返回类型,但必须有不同参数表。生成不同返回类型和相同参数表的重载函数是个语法错误。
●函数模板只定义一次,即可对不同类型数据生成进行相同操作的函数。
ampersand (&) suffix &号后缀 caller 调用者 argument in a function call 函数调用中的参数 calling function 调用函数 auto storage class specifier auto存储类说明符 coercion of arguments 强制参数类型转换 automatic storage 自动存储 collaboration 协作 automatic stooge class 自动存储类 component 组件 automatic variable 自动变量 const base case recursion 递归中的基本情况 constant variable 常量变量 block 块 copy of avalue 数值副本 bilk scope 块范围 dangling reference 悬挂引用 C++standard library C++标准库 default function arguments 默认函数参数 call a function 调用函数 divide and conquer 分而治之,各个击破 call-by-reference 按引用调用 elementofchance 机会元素 call-bY-value 按值调用 enum called function 被调用函数 enumeration 枚举 enumeration constant 枚举常量 rand extern storage class specifier extern 存储类说明符 random number generation 随机数产生 factorial function 阶乘函数 randomize 随机化 file scope 文件范围 RAND_MAX function 函数 read-only variable 只读变量 function call 函数调用 recursion 递归 function declaration 函数声明 recursive call 递归调用 function definition 函数定义 recursive function 递归函数 function overloading 函数重载 reference parameter 引用参数 function prototype 函数原型 reference type 引用类型 function scope 函数范围 register storage class specifier register 存储类说明符 function signature 函数签名 return global variable 全局变量 return-value-type 返回值类型 header file 头文件 scaling 比例缩放 infinite recursion 无穷递归 scope 作用域(范围) information hiding 信息隐藏 shifting 位移 inline function 内联函数 side effect 副作用 invoke a function 调用函数 signature 签名 iteration 迭代 simulation 模拟 linkage 连接 software engineering 软件工程 linkage specification 连接指定 software reusability 软件复用 local variable 局部变量 srand math library functions 数学库函数 standard library header files 标准库头文件 mixed-type expression 混合类型表达式 static storage class specifier static 存储类说明符 modular program 模块化程序 static storage duration 静态存储期 name decoration 名字修饰 static variable static 变量 name mangling 名字改编 storage class specifier 存储类说明符 named constant 命名常量 storage class 存储类 optimizing compiler 优化编译器 template overloading 重载 template function 模板函数 parameter in a function definition 函数定义中的 time 参数 type-safe linkage 类型安全连接 principle of least privilege 最低权限原则 unary scope resolution operator 一元作用域运 programmer-definnd function 程序员定义的函数 算符 promotion hierarchy 层次提升 unsigned void