第20章 综合程序设计
第20章 综合设计面向对象的程序
至此,已浏览了 C++乐园的各分景点,收获了不少知识。这一站,要浏览 C++乐园的综合景点,是将以上各景点组合在一起的大景点。因为,生产、工作、生活中的实际问题基本上都不是单一的问题,都是会牵涉到方方面面的综合问题,这就需要将前面所学的 C++知识综合起来,加以全面的理解和巩固,并掌握 C++面向对象的程序设计方法,然后运用于综合问题的设计中,以达到学的最终目的——用。
20.1 面向对象的综合设计范例——仓库材料管理软件
【例20-1】请编程设计一个仓库材料管理软件。
设计的内容如下:
1)界面设计有主菜单、子菜单,其中主菜单项有:输入、修改、查询、统计、输出、退出,在各主菜单项之下可有相应的子菜单,例如查询菜单下可有按材料代号查询、按材料名称查询、按分类查询、按单价查询、结存数量小于3的材料查询和返回上层等子菜单。
2)所管理对象的规模为:一个仓库、3种分类、至少5种以上的材料、每种材料至少3个。
3)每种材料的数据包括分类号、材料代号、材料名称、单价、收入数量和金额、发出数量和金额、结存数量和金额。
4)统计菜单应该有计算某个仓库和某类材料的收入数量和金额、发出数量和金额、结存数量和金额的功能。
设计的要求如下:
1)采用面向对象的程序设计方法,使用多个类和类的继承等面向对象技术,最终用包含多个文件的工程文件予以实现。
2)各功能除了能用 C++ 或 C 语言的标准类库和标准函数之外,均用自定义类库和自定义函数定义。
3)程序交互性要好。
4)该软件的操作和使用要方便。
5)可行性、可靠性、可读性、可维护性和可移植性要好。
1. 用心分析人想通,机随人行写提纲
在充分理解了要设计的仓库材料管理软件的内容及要求后,来想想人是怎么做的。人工管理仓库材料时要有一本仓库记账本,进了材料就在记账本上记录材料名称、收入数量等;发放材料时则在记账本上记录材料名称、发出数量等;还可以统计每种材料的收入数量及金额、发出数量及金额和结存数量及金额等;查询或修改时可以按材料号或材料名称查找,找到后可以查看和修改;输出就是打开记账本来查看(当然也可以进行专项输出,这属于查询
中的工作,查询完全有输出显示)。
转换成计算机,人工记账本就是计算机中的数据存储单元,其他人的动作可用流程图描绘出,再用 C++ 语言编程实现。根据该软件的要求,是要用面向对象的程序设计方法进行综合设计,所以就用此方法进行如下设计。
(1) 择优确定仓库材料管理软件的总体设计方案
根据 C++ 面向对象的程序设计方法和本题的设计要求,结合本题的设计内容,择优确定总体设计方案,具体步骤如下。
1 )初步确定类及派生类。
按照面向对象的程序设计方法,先画“顺瓜摸根”(类的继承层次)图,如图20-1(方案一)和图20-2(方案二)所示。


将方案一和方案二填写在方案比较表中(见表20-1),进一步加以比较、分析和选优。
分析:如果再加另一类材料时,假设用方案一,则菜单类、材料类均要修改,而方案二只需修改菜单类即可,比方案一要方便,而且方案二符合实际的瓜、根分布规则,故暂且选择方案二。
2)根据暂选的最优方案,写出各个类架构表,如表20-2~表20-4所示。按照“顺瓜摸根”的方法,头脑跟踪运行这几个表中具体分配的功能任务,即通过一层层继承与派生的关系,调用各函数成员,并结合数据成员考虑,看是否能完成题目要求的功能。例如,从菜单类的“运行”这个函数成员开始,进入该软件主菜单的运行界面,当要对机械类材料进行输入操作时,就选择主菜单的“输入”操作,因为主菜单继承了机械类,机械类又继承了材料类,故可以“顺瓜摸根”地执行到材料类的“输入”这个函数成员,完成输入机械类材料的功能。可依上述方法对其余内容进行头脑跟踪运行,最后可知符合题目要求,所以类的继承和派生关系是合理的。
| 方案 | 继承与派生的合理性、有利性 | 可读性 | 可移植性 | 可维护性 | 编程方便性 | 备注 |
| 方案一 | 一般 | 一般 | 不太好 | 一般 | 中 | |
| 方案二 | 好 | 好 | 好 | 好 | 好 |
| 基 类 | |
| 材 料 类 | |
| 功能(函数成员) | 原材料(数据成员) |
| 输入 | 将材料的所有基本参数声明为材料类结构数组 |
| 修改 | 材料种类的最小值 |
| 查询 | 材料种类的最大值 |
| 统计 | 一些菜单和项目名称栏用的字符或字符串数组 |
| 输出 | |
| 构造函数 | |
| 一些辅助功能的函数 | |
| (如显示菜单、询问、选择等操作) | |
| 第一派生类 | |
| 机械类 | |
| 功能(函数成员) | 原材料(数据成员) |
| 构造函数 | 机械类材料的结构数组 |
| 机械类材料的种类总数 | |
电器和化工类基本同机械类的架构表。
| 第二派生类 | |
| 菜 单 类 | |
| 功能(函数成员) | 原材料(数据成员) |
| 构造函数 | 主菜单的字符串 |
| 运行 | 各子分类字符串 |
| 显示分类状态 | |
3)重新考虑类的继承关系。
根据以上几步,重新考虑继承关系是否合理。根据类的继承层次图和类架构表,经过再三分析,认为合理。
故选择方案二作为本设计的方案。
4 )确定总体设计方案。
该仓库材料管理软件是对仓库材料这个数据库进行管理,可通过主程序显示出主菜单,又在主菜单下显示出各子菜单,完成相应的管理工作,每一个子菜单均有返回上层菜单的功能
能,最后选择退出时就结束本次的管理工作了。
本设计方案的类的继承层次关系如图 20-2 所示,接口关系如表 20-2~表 20-4 所示。按照接口关系的描述,每一个类都由功能(成员函数,又称为接口)和原材料(数据成员)组成,外部接口由公有成员函数组成,而成员函数表示的就是算法,所以,程序的设计思路为:由算法加数据结构组成类,又在若干个类中声明若干个对象,再由若干个对象组成程序,即设计为面向对象的程序了。
(2) 画流程图
根据设计方案,先画出主函数流程图,再画出各成员函数的流程图。然后对照设计内容,运用人脑跟踪运行法检验流程图,直至初步合理。
1 )画出主函数流程图。
主函数流程图如图20-3所示。

2 )画出显示操作菜单成员函数 run 的流程图。
显示操作菜单成员函数 run 的流程图如图 20-4 所示。

3)画出按材料代号查询的成员函数的流程图。
按材料代号查询的成员函数的流程图如图20-5所示。

其余流程图略。
(3) 修改检查设计方案
对照设计内容及要求,根据 C++ 和面向对象程序设计的知识,反复推敲验证上述各流程图的正确性、可行性、可靠性、可读性、交互性、方便性、可维护性和可移植性,直至符合要求。
2. 对号入座写文章,头脑运行改文章
根据 C++ 程序设计语言和流程图对号入座地编写 C++ 工程文件,主文件、子文件、头文件的一般形式请参考 20.3.2 节。本例的程序与例 20-2 中的大部分程序基本相同,由于后面列出了程序,所以此处不再列出。在编写完程序(纸上谈兵)后,要反复地头脑运行,修改程序,直到认为完全正确后,再进入输入调试阶段。
3. C++帮助且裁判,人定胜机凯歌扬
任纸上谈兵和头脑运行之后,就进入了输入调试阶段,即输入、编译、连接、调试所设计的工程文件。
输入运行工程文件,并详细记录运行的过程,包括记录数据、结果、出错现象、出错原因和解决办法等,若达不到要求就重复几次,直到调试成功,运行正确。
完善整个软件,直至形成程序能可靠运行、维护和使用方便、可读性好、交互性好、可移植性好的软件。
最终调试成功的“仓库材料管理软件”的程序代码基本同例20-2的大部分程序代码(除了I/O文件、异常处理、延时程序和少许语句改动之外)。运行结果也基本与例20-2的
运行结果相同。
20.2 勤奋实践,总结评分
20.2.1 习题
1. 学生成绩管理软件
(1) 综合设计内容
请编程设计一个学生成绩管理软件,它包含的内容有:
1)界面设计有主菜单、子菜单,其中主菜单项有:输入、修改、查询、统计、输出、退出,在各主菜单项之下可有相应的子菜单,例如查询菜单下可有按姓名查询、按科目查询、按学号查询、按班级查询、按分数段查询和返回上层的子菜单。
2)所管理对象的规模为:一个班级的至少10个以上的学生。
3)每个学生的数据包括学号、姓名、班级、科目及至少5科以上的成绩。
4)统计菜单应该有计算某人或全班所有科目的平均分、全班单科目的平均分、单科分数或全班平均分的最高分和最低分、某个分数段的人数的功能。
(2)综合设计要求(下述各题的综合设计要求均同此)
1)采用面向对象的程序设计方法,使用多个类、类的继承等面向对象技术,最终用包含多个文件的工程文件予以实现。
2)各功能除了能用 C++ 或 C 语言的标准类库和标准函数之外,均用自定义类库和自定义函数定义。
3)程序交互性要好。
4)该软件的操作和使用要方便。
5)可行性、可靠性、可读性、可维护性和可移植性要好。
2. 工资管理软件
(1) 综合设计内容
请编程设计一个工资管理软件,它包含的内容有:
1)界面设计有主菜单、子菜单,其中主菜单项有:输入、修改、查询、统计、输出、退出,在各主菜单项之下可有相应的子菜单,例如查询菜单下可有按职工号查询、按职工姓名查询、按部门查询、按应发工资查询、按实发工资查询和返回上层的子菜单。
2)所管理对象的规模为:两个部门、至少10人。
3)每个职工的数据包括职工号、职工姓名、部门、基本工资、补贴工资、水电费、其他、应发工资、实发工资。
4)统计菜单应该有计算本单位和某个部门的应发工资平均值和实发工资平均值的功能。
(2)综合设计要求(同第1题)。
3. 人事档案管理软件
(1)综合设计内容
请编程设计一个人事档案管理软件,它包含的内容有:
1)界面设计有主菜单、子菜单,其中主菜单项有:输入、修改、查询、统计、输出、
退出,在各主菜单项之下可有相应的子菜单,例如查询菜单下可有按职工号查询、按职工姓名查询、按出生年月查询、按籍贯查询、按部门查询、按职称查询、按政治面貌查询、按基本工资查询和返回上层的子菜单。
2)所管理对象的规模为:两个部门、至少10人。
3)每个职工的数据包括职工号、职工姓名、出生年月、籍贯、部门、职称、政治面貌、基本工资。
4)统计菜单应该有计算本单位和某个部门的人数、某种职称的人数、某种政治面貌的人数的功能。
(2)综合设计要求(同第1题)
4. 商场货物管理软件
(1)综合设计内容
请编程设计一个商场货物管理软件,它包含的内容有:
1)界面设计有主菜单、子菜单,其中主菜单项有:输入、修改、查询、统计、输出、退出,在各主菜单项之下可有相应的子菜单,例如查询菜单下可有按货架号查询、按货物代号查询、按货物名称查询、按分类查询、按购买地查询、按购买时间查询、按单价查询、结存数量小于10的材料查询和返回上层的子菜单。
2)所管理对象的规模为:两个货架、4种分类、至少10种以上的货物、每种货物至少5个。
3)每种货物的数据包括货架号、分类号、货物代号、货物名称、型号规格、主要功能特点、单价、收入数量和金额、卖出数量和金额、结存数量和金额、购买地、购买时间。
4)统计菜单应该有计算某个货架和某类货物的收入数量和金额、卖出数量和金额、结存数量和金额等功能。
(2)综合设计要求(同第1题)
5. 文件档案管理软件
(1)综合设计内容
请编程设计一个文件档案管理软件,它包含的内容有:
1)界面设计有主菜单、子菜单,其中主菜单项有:输入、修改、查询、统计、输出、退出,在各主菜单项之下可有相应的子菜单,例如查询菜单下可有按文件柜查询、按文件夹查询、按文件号查询、按文件发出日期查询、按文件执行日期查询、按文件检查日期查询、按文件分类名称查询和返回上层的子菜单。
2)所管理对象的规模为:两个文件柜、至少5个文件夹、10份文件。
3)每份文件的数据包括文件柜号、文件夹号、文件号、文件发出日期、文件执行日期、文件检查日期、文件分类名称。
4)统计菜单应该有计算某个文件柜或某个文件夹的文件数、某天发出的文件数的功能。
(2)综合设计要求(同第1题)
6. 课程表编排软件
(1)综合设计内容
请编程设计一个课程表编排软件,它包含的内容有:
1)界面设计有主菜单、子菜单,其中主菜单项有:教师授课状况、课程表编排,在各
主菜单项之下有相应的子菜单,例如输入、修改、查询、统计、输出、返回上层等子菜单,在各子菜单下还可有相应的子菜单,例如查询菜单下可有按姓名查询、按日期查询和返回上层子菜单。
2)对一个至少有7门功课的班级的课程表进行编排。
3)教师授课状况数据库包括教师姓名、课程名称、教师空闲状况(具体为第1~18周的周一到周五的空闲状况)、备注等数据。
课程表的数据包括班级、专业、人数、课程名称、上课时间、上课地点、任课教师姓名、备注。
4)每门课的授课时间为15周,排课时间为第1~18周,每周一到周五全天上课,上午4节课,下午4节课,“十一”长假周不排课,请将课程表面成表格形式。
(2)综合设计要求(同第1题)
7. 购物软件
(1) 综合设计内容
请编程设计一个购物软件(假设已有本章习题第4题的“商场货物管理软件”的支持),它包含的内容有:
1)界面设计有主菜单、子菜单,其中主菜单项有:购物、售后服务、退出,在各主菜单项之下可有相应的子菜单,购物菜单下的子菜单有选购、刷卡、返回上层,在选购子菜单下又有按商品大类分类的子菜单,售后服务菜单下的子菜单有送货方式、顾客意见、返回上层。
2)至少有三大分类、每种分类下有两种商品、每种商品至少有5个。
3)每种商品的数据包括货物代号、货物名称、型号规格、主要功能特点、单价、每种商品的购买数量。
包含一个购物表,购物表中有卡号,密码,选购物品的货物代号、货物名称、单价、每种商品的购买数量、每种商品的购买金额、购买总数量、购买总金额,原来余额,扣除金额,现在余额,取货方式,顾客意见等数据。
4 )顾客购物的步骤如下:
① 当顾客进入购物菜单再进入选购子菜单后,在购物表中输入卡号,按需求进入相应的子菜单选购,选购完时能自动计算出每种商品的购买数量、每种商品的购买金额、购买总数量、购买总金额。
② 选购完后进入刷卡子菜单,输入卡号和密码,刷卡扣钱。
③ 再进入售后服务菜单,选择自己取货或送货方式,最后打印出除购物表中的卡号和密码外的所有项目清单。
④ 完成后退出。
(2)综合设计要求(同第1题)
8. 简单的图书馆借书、还书管理软件
(1)综合设计内容
请编程设计一个简单的图书馆借书、还书管理软件,它包含的内容有:
1)界面设计有主菜单、子菜单,其中主菜单项有:选书、借书、还书、退出,选书菜单下有文学、数理化、科技、返回上层4个子菜单。
2)有文学、数理化、科技三大类书籍,每类中又至少有10本不同的书籍可供读者选择。
3)每本书的数据包括代号、书名、第一作者、出版社名称、出版时间、馆藏状态。
包含读者卡,读者卡的数据有卡号、读者姓名、所借书籍代号、书名、借书日期、还书日期。
4)读者凭读者卡号进入软件,再进入选书菜单,根据分类进入相应的子菜单选借书籍,每位读者最多可借3本书,选好书后,读者再凭借书证进图书库自己取书。读者拿着要借的书来到图书管理员处,管理员输入管理员名和密码,进入借书菜单办理借书手续。
读者还书时也将书交给管理员,管理员输入管理员名和密码,进入还书菜单办理还书手续。
(2)综合设计要求(同第1题)
9. 考勤打卡机管理软件
(1)综合设计内容
请编程设计一个考勤打卡机管理软件,它包含的内容有:
1)界面设计有主菜单、子菜单,其中主菜单项有:考勤打卡、考勤统计、退出,在各主菜单项之下有相应的子菜单,考勤打卡菜单下的子菜单有上班、下班、请假、返回上层,考勤统计菜单下的子菜单有月统计、年统计、返回上层。
2)单位人数为10人,2个部门,对10人的考勤进行管理。
3)考勤卡的数据包括部门、姓名、职工号、正常出勤、迟到、早退、旷工、事假、病假、休假。
4)请假人向有关批准人员请假,批准后,由批准人员输入管理人员名和密码,进入请假菜单进行登记。
职工进入考勤打卡菜单时,按上班、下班进入相应的子菜单,输入本人的职工号,验证无误后确认,就可将对应的考勤登记起来,并输出本人的考勤状况。
假设8时上班,16时下班,小于等于8时打卡、大于等于16时打卡的登记正常出勤;大于8时且小于等于8:30打卡的登记迟到;大于等于15:30且小于16时打卡的登记早退;8:31至15:29打卡且又不是请假的登记旷工。
5)统计菜单的功能如下(只能由管理员操作):
统计某职工的考勤情况,包括3)中的各种情况。
统计各部门全勤职工的人数和姓名。
统计各部门旷工2天以上职工的人数和姓名。
统计各部门迟到或早退5次以上职工的人数和姓名。
6)还可附加考勤查询、考勤输出、考勤修改(由管理员操作)等功能。
(2)综合设计要求(同第1题)
10. 自动电镀生产线的简单生产工序操作控制软件
(1) 综合设计内容
请编程设计一个自动电镀生产线的简单生产工序操作控制软件,假设这是一条悬臂式环形自动电镀生产线,其主要结构是:在这个环形自动生产线的上方是一条环形运行的吊臂,吊臂上有挂具,挂具可以夹持零件,吊臂的下方由数个固定的处理槽组成。电镀时,吊臂吊着零件,通过提升、前进、下降,在不同的处理槽进行不同的工艺操作,走完一圈,即一个循环,就完成了电镀任务,卸下电镀好的成品,又挂上待电镀的零件进入下一次循环。
生产线的主要生产工艺流程为:装待电镀零件→热(或化学)去油→电解去油→清洗→活化→预镀→电镀→清洗→干燥→成品→卸下已电镀好的零件→装待电镀零件,依次循环。每次电镀由11道工序组成。
假设在每一个处理槽的处理时间平均为 3 分钟(调试程序时可调小该时间,如几秒),提升、下降时间各为 3 秒,前进时间为 15 秒。
这条自动电镀生产线的简单生产工序操作控制软件包含的内容有:
1)界面设计有主菜单、子菜单,其中主菜单项有:生产运行、参数调整、统计、程序修改、退出,在各主菜单项之下有相应的子菜单,各子菜单有返回主菜单的子项,请设计主菜单、各子菜单,以完成所要求的功能。
2)设每次电镀20个零件,电镀过程是不断地循环,直到停机。
3)该软件应完成的功能如下。
① 生产运行:根据该自动电镀生产线的主要生产工艺流程完成循环生产过程的各项操作,每当完成了一个工序之后,打印显示该工序的名称;要有统计功能,利用操作“卸下已电镀好的零件”这一工序的时间,产生一组随机数,把该组随机数中的数进行划分,当在某些范围内时是合格品,在某些范围内是次品,又在某些范围内是废品,将各档次成品数量累加,求出合格率、次品率、废品率,并打印显示这些统计数据;还可以随时干预生产线以进入某道工序。
② 参数调整:可以进行一些简单的参数调整,该功能只能由生产当班负责人操作,当在线中途调整参数时,其过程应是:停机(返回主菜单)→参数调整→接着进行停机前的动作(却又进入了生产运行菜单),例如,可进行处理时间的调整。
③ 程序修改:此功能的权限仅属于程序管理员,当中途修改时,其过程是:停机(返回主菜单)→程序修改→根据停机前的工序结合修改的程序决定应该接着什么工序进行操作(即又进入了生产运行菜单)。
④ 统计:其下的子菜单有查看各批次统计情况,班统计,日统计,周统计,月统计,年统计,其中后5个子菜单中均可以统计生产量(包括合格品数量、次品数量、废品数量)、产品率(包括合格品率、次品率、废品率)和打印显示统计数据。
4)软件中某些对象的设置,例如:某对象的数据成员 A 的值分别对应的模拟动作如表 20-5 所示。
| A 值 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
| 模拟动作 | 复位 | 启动 | 提升 | 下降 | 前进 | 处理 | 停机 |
(2)综合设计要求(同第1题)。
20.2.2 思考题
- 在本章习题第1题的综合设计中:
1)如果要对任意个班级的学生成绩进行管理,该如何设计?
2)如果有任意个学生又如何设计?
3)如何增减科目?
- 在本章习题第2题的综合设计中:
1)如果要对任意个部门的职工工资进行管理,该如何设计?
2)可增加一些什么功能?
- 在本章习题第3题的综合设计中:
1)如果要对任意个部门的职工人事档案进行管理,该如何设计?
2)可增加一些什么功能?
- 在本章习题第4题的综合设计中:
1)如果要对任意个货架的货物进行管理,该如何设计?
2)可增加一些什么功能?
- 在本章习题第5题的综合设计中:
1)如果要对任意个文件柜进行管理,该如何设计?
2)可增加一些什么功能?
- 在本章习题第6题的综合设计中:
1)如果要对任意个班级的课程表进行编排,该如何设计?
2)可增加一些什么功能?
- 在本章习题第7题的综合设计中:
1)如果要对任意个分类的物品进行选购,该如何设计?
2)可增加一些什么功能?
- 在本章习题第8题的综合设计中:
1)如果要对超过还书期限的读者罚款,该如何设计?
2)可增加一些什么功能?
- 在本章习题第9题的综合设计中:
1)可增加一些什么功能?例如,增加查询和修改功能等。
2)请对该考勤打卡机的异常情况进行观察和考虑,并设计异常处理程序来解决这些异常问题。
- 在本章习题第10题的综合设计中:
1)通过该实验,你对 C++ 语言在自动控制中的初步应用有什么认识?
2)通过 C++ 综合程序设计实验,你对设计综合软件有什么认识?在设计软件方面有什么提高?
20.2.3 总结评分,继续提高
浏览体验了例题、习题和思考题之后,说说自己的体会和收获,并认真总结,按表20-6给自己评判一下可以得多少分。
| 成绩 | A | B | C | D | 不足的原因 | 改进的方法 | 备注 |
| C++知识 | 完全理解和会用 | 基本理解和会用 | 肤浅理解和会用 | 基本不理解和不会用 | |||
| 程序原创(独立编程)的比例(%) | ≥90 | 80~89 | 60~79 | <60 |
不论得分多少,大家都要总结经验,扬长避短,勤奋努力,不断提高。
最后浏览一下本章的第4节,可以先考考自己,然后再浏览,以便使重点知识掌握得更牢固。
20.3 面向对象的综合设计知识
前面学习了许多 C++ 的基础知识,是不完整的、分离的,基本不能解决复杂的实际问题。所以面对实际生产、生活中的一个个对象,要运用面向对象的综合设计方法,综合运用 C++ 各单元的知识,去设计开发软件,这些就是以下要叙述的问题。
20.3.1 在什么情况下用到面向对象的综合设计
最好在任何情况下都用面向对象的设计方法设计程序,复杂的问题就用综合设计方法。这对于提高程序的可读性、可移植性等是有益的,且可以提高编程的工作效率。
20.3.2 关于面向对象的综合设计
面向对象的综合设计还是按照 2.3.1 节中所述的流程进行开发,只不过添加了选择总体设计方案的部分,还要注意工程文件的各组成部分,具体介绍如下。
1. 用心分析人想通,机随人行写提纲
(1)选择总体设计方案
1)全面理解综合设计的内容,并将人的做法想通。
2)根据 C++ 面向对象的程序设计方法和综合设计的要求,结合综合设计的内容,用“顺瓜摸根”法找出基类及派生类,初步选择出最优方案,画出类的架构表,确定函数及数据成员,重新考虑类的继承关系是否合理,并确定最优方案,最终把程序设计成:
$$ \begin{aligned} 程序 &=( 对象 + 对象 +\cdots)\\&=( 类或某些类 + 类或某些类 +\cdots)\\&=\quad(( 算法 + 数据结构 )+( 算法 + 数据结构 )+\cdots)\end{aligned} $$
这样的形式。
(2) 画流程图
根据设计方案,画出主函数流程图,再画出各成员函数的流程图。然后对照综合设计的内容及要求,运用人脑跟踪运行法检验流程图,直至初步合理。
(3) 修改检查设计方案
对照综合设计的内容及要求,按照人的做法,从头到尾用人脑运行一遍,看是否有问题。然后根据 C++语言的知识,反复推敲验证上述各流程图的正确性、可行性、可靠性、可读性、交互性、方便性、可维护性和可移植性,直至符合要求。
2. 对号入座写文章,头脑运行改文章
根据 C++ 程序设计语言和流程图对号入座地编写 C++ 工程文件(参照第 11 章的编写方法及例 20-2)。
(1) C++工程文件的一般形式
一个主函数文件。
若干个用户自定义类库文件(即若干个用户自定义的类成员函数的源文件)。
若干个用户自定义函数文件(即若干个用户自定义的子函数的源文件)。若干个用户自定义类库或自定义函数的头文件。
(2)主函数文件的一般形式
#include<标准类库头文件>(若干个)
#include<标准函数头文件>(若干个)
#include"自定义类库头文件"(若干个)
#include"自定义函数头文件"(若干个)
函数原型(或函数原型及定义一体)(若干个)
全局数据定义(若干个)
void main() (一个主函数 main)
{
...
}
函数定义(若干个)
主函数文件的扩展名为cpp。
(3)子函数文件的一般形式(类成员函数文件的一般形式与此大致相同,只是要加上类名及作用域区分符:)
#include<标准类库头文件>(若干个)
#include<标准函数头文件>(若干个)
#include"自定义类库头文件"(若干个)
#include"自定义函数头文件"(若干个)
函数原型(或函数原型及定义一体)(若干个)
返回数据类型 子函数名 ([形式参数])
{
...
}
函数定义(若干个)
子函数文件(或类成员函数文件)的扩展名为cpp,可有若干个。
(4)自定义类库和自定义函数的头文件的一般形式
类型声明
函数声明
内联函数定义
常量定义
数据声明
枚举
包含指令
宏定义
注释
头文件的扩展名为h,也可有若干个,另外,不可对头文件进行编译。
以上各部分除了主函数外,子函数文件(或类成员函数文件)、自定义类库和自定义函数的头文件不一定全有(但至少要有一个子函数文件(或类成员函数文件)和一个头文件),另外,上述(2)、(3)、(4)中的各种细分成分也不一定全有。
在编写程序时要注意以下几点:
1)选择合适的数据类型构造软件中的数据结构。
2)采用友好的对话方式构造主菜单和各子菜单。
3)各种功能都选用较优的算法和操作。
4)打印格式要合理,方便观察。
将写出的程序与上述流程图进行分析比对,并用人脑跟踪运行,直至认为正确(即能完成题目的功能,也符合 C++ 的语法及规定)。
3. C++帮助且裁判,人定胜机凯歌扬
将程序输入计算机→编译→连接→无错→运行[→调试修改→如果无错→运行]。
详细记录运行的过程,包括记录数据、结果、出错现象、出错原因和解决办法,若达不到要求就重复上述步骤。
完善整个软件,直至形成程序能可靠运行、维护和使用方便、可读性好、交互性好、可移植性好的软件。
最后根据综合设计的内容、要求、方案选择、程序设计、调试、问题分析、修改等环节,编写总结报告,深刻体会,改进提高。
注意:方案选优体现在各个环节中,既有大方案的选优,又有小方案和技术、调试等方面的选优,总之,要善于运用 C++ 的知识,开阔思路,勇于创新,充分发挥你的聪明才智,尽力体现你的优势特长,相信你肯定能创作出优秀的作品,预祝你成功!
20.3.3 如何运用面向对象的综合设计
根据上节所讲的面向对象综合设计的开发流程及知识进行软件开发。
下面再举一个综合设计软件的例子。
【例 20-2】 在例 20-1 的基础上加入异常处理和文件存储的功能,并提高程序运行的可靠性、可行性和稳定性,请进行综合设计,编写该软件。
1. 在例20-1的源程序中加入异常处理和文件存储功能的理由
在运行例 20-1 设计的仓库材料管理软件时,发现了一些问题,即在要求输入数字时,误输入了非数字(如在中文输入方式下输入了汉字,在西文方式下输入了字母等),就会出现乱码的死循环。另外,运行操作既麻烦,又不现实,因为每次运行时,都要重新输入数据,如若采用初始化赋值,则修改的数据不能更新,添加的数据又不能加入。只是例 20-1 的程序比此例要简单,初学者易懂,而且设计、调试等也方便容易,故分为两步走,前面的程序初具雏形,此处的程序改进完善。
2. 在例20-1的源程序中加入异常处理和文件存储功能的设计思想
(1)加入异常处理功能的设计思想
按前期运行中发现的问题,拟设置2个异常处理:
1)判断输入了非数字的异常处理。
2)第一次使用此软件时打不开文件的异常处理。
把异常处理的成员函数设在基类 Mater 中。
通过多次运行和周密思考,将异常处理设置在有可能发生异常的多个语句处。
(2) 加入文件存储功能的设计思想
1)当进入运行主菜单时,在显示主菜单前的初始化部分的末尾就加上调用打开文件成员函数的语句,读出磁盘的数据文件中已保存的信息,以供软件运行时使用。
2)因为同时使用此软件的不止一个人,即在运行中数据随时会被更新,所以,在进入每个子菜单操作时均要打开文件读取最新的数据,假设操作中改变或添加了数据,结束此操作前还必须将数据写入到文件中。
3)在退出此软件之前,再次将数据写入到文件中,以防万一。
4)I/O 文件需要多少个?此例为 3 个,因为有 3 个材料大分类,所以机械、化工和电子分别有各自的数据文件。
5)I/O 文件采用何种文件?采用二进制文件,因为存取数据方便。
6)I/O 文件存储哪些数据?存储 3 个派生类(机械、化工、电子)存放材料的结构数组数据,即 mmate、cmate、emate。
7)把读文件和写文件的成员函数设在基类 Mater 中。
3. 提高程序运行的可靠性、可行性和稳定性
运行中发现,人工从键盘输入的速度与程序运行的速度不协调,以至于程序运行出错,故多处增加了调用延时成员函数的语句,此延时成员函数也加在基类 Mater 中。
其他的设计同例20-1,此处不再赘述。
把以上添加的功能程序均作为成员函数,是为了方便多次读/写和处理异常情况的操作,缩减不必要的程序段,更有利于达到题目的要求。
调试成功的“仓库材料管理新软件”源程序(含有异常处理和文件存储的功能)如下:
//材料类的头文件 mat.h
#include<iostream>
#include<string>
#include<iomanip>
#include<fstream>
#include<stdlib.h>
using namespace std;
#define MAX_ITEMS 6//主菜单中的子菜单数目
#define MAX_ITEMS1 3//分类状态的分类数目
#define NUM_10000//为定义堆空间初设的元素数目
#define SORTID 3//各子分类字符串的数目
#define MAX_ITline9 3//输出项目名称栏的最大行数
#define MAX_ITrow9 10//输出项目名称栏的最大列数
#define ASQ1 "没有此材料号," //一些字符串的定义
#define ASQ2 "没有此材料名称,"
#define ASQ3 "您还要修改吗?(y/n) "
#define ASQ4 "您还要查询吗?(y/n) "
#define ASQ5 "您记得要修改的"
#define ASQ6 "材料号吗? (y/n) "
#define ASQ7 "材料名称吗? (y/n) "
#define ASQ8 "您还要修改"
#define ASQ9 "其他项目吗? (y/n) "
#define ASQ10 "其他材料吗? (y/n) "
#define ASQ11 "请您从下表中查找,请按 y 键,再按 Enter 键"
#define ASQ12 "请您核对,"
#define ASQ13 "没有此材料或不记得此材料,"
struct Mt//声明材料结构
int sortid;//材料分类号
int matid;//材料号
char name[10]; //材料名称
double price;//材料单价
double datain;//收入材料数量
double amountin;//收入材料金额
double dataout;//发出材料数量
double amountout;//发出材料金额
double remain;//结存材料数量
double amremain;//结存材料金额
class Mater//声明材料类
public:
Mater(); //材料类的构造函数
int getdata(Mt *& mate, int mummax); //输入的成员函数
void modify(Mt *& mate, int mummax); //修改的成员函数
void inquiry(Mt *mate, int mummax); //查询的成员函数
void stati(Mt *& mate, int mummax); //统计的成员函数
void disp(Mt *mate, int nummin, int nummax); //输出的成员函数
char cyn(); //接收键盘输入的 y 或 n 字符并返回该字符的成员函数
char asq(const string ASQZ, const string ASQY); //询问的成员函数
void displaymenu(string menutitle, char * menuitems3], int menunum); //显示菜单的成员函数
int chooseoption(); //选择操作的成员函数
int fread(const char * rfile1, Mt * &mate); //文件数据读出
void fwrite(const char * wfile1, Mt * &mate, int mummax); //文件数据写入
double Mater::dig1(); //输入非数字的异常处理
void delay1(int dtime1); //延时成员函数
protected:
Mt *mate; //存放材料类的数据成员
int mummin, mummax; //材料种类的最小值、材料种类的最大值
string menutitle, menutitle1; // “主菜单”的形参、“查询子菜单”的字串
char * menuitems1[MAX_ITEMS1]; //存放查询子菜单的数据成员
string itemname[MAX_ITline9][MAX_ITrow9]; //输出各项目名称
int dtime1;//控制延迟时间
//机械、化工、电子类的头文件 che.h
#include"mat.h" //包括材料类的头文件
class Mac:public Mater //声明机械类,并公有继承材料类
{
public:
Mac();
Mt *mmate;//机械类材料的数据成员
int mnum;//机械类材料的种类总数
const char *mfile;//常字符指针,声明机械类二进制文件名
};
class Che:public Mater //声明化工类,并公有继承材料类
{
public:
Che();
Mt *cmate;//化工类材料的数据成员
int cnum;//化工类材料的种类总数
const char *cfile;//常字符指针,声明化工类二进制文件名
};
class Ele:public Mater //声明电子类,并公有继承材料类
{
public:
Ele();
Mt *emate;//电子类材料的数据成员
int elenum;//电子类材料的种类总数
const char *efile;//常字符指针,声明电子类二进制文件名
};
//菜单类的头文件 menu.h
#include"che.h"
class Menu:public Che,public Mac,public Ele
{
public:
Menu();
void displaysort();//显示分类状态
void run(); //运行成员函数
private:
char * sortnum[SORTID]; // 分类显示的各子类字符串
string menutitle0; // “主菜单”字符串
char * menuitems[MAX_ITEMS]; // 主菜单中的各子菜单字符串
// 材料类的源文件 mat.cpp
#include "mat.h"
Mater::Mater() // 材料类 Mater 的构造函数
{
menutitle1="查询子菜单"; // 一些用到的字符串
menuitems1[0]="1.按材料号查询";
menuitems1[1]="2.按材料名称查询";
menuitems1[2]="3.返回";
itemname[0][0]="分";
itemname[0][1]="材";
itemname[0][2]="材料";
itemname[0][3]="单";
itemname[0][4]="收入";
itemname[0][5]="收入";
itemname[0][6]="发出";
itemname[0][7]="发出";
itemname[0][8]="结存";
itemname[0][9]="结存";
itemname[1][0]="类";
itemname[1][1]="料";
itemname[1][2]="名称";
itemname[1][3]="价";
itemname[1][4]="数量";
itemname[1][5]="金额";
itemname[1][6]="数量";
itemname[1][7]="金额";
itemname[1][8]="数量";
itemname[1][9]="金额";
itemname[2][0]="号";
itemname[2][1]="号";
itemname[2][2]="__";
itemname[2][3]="(元)";
itemname[2][4]="(个)";
itemname[2][5]="(元)";
itemname[2][6]="(个)";
itemname[2][7]="(元)";
itemname[2][8]="(个)";
}
itemname[2][9]="(元)";
if((mate=new Mt[NUM])==NULL)//分配存放材料形参的堆空间
{
cout<<"can't allocate more memory,terminating.\n";
exit(1);
}
int Mater::getdata(Mt *& mate,int mnummax)//定义输入成员函数
{
int i=mnummax;
char ini='y';
while(ini=='y')
{
cout<<"请输入材料分类号(阿拉伯数字):";
mate[i].sortid=dig1();
cout<<"请输入材料号(阿拉伯数字):";
mate[i].matid=dig1();
cout<<"请输入材料名称(字符串):";
cin>>mate[i].name;
cout<<"请输入材料单价(保留小数点后两位):";
mate[i].price=dig1();
cout<<"请输入材料的收入数量:";
mate[i].datain=dig1();
cout<<"请输入材料的发出数量:";
mate[i].dataout=dig1();
i++;
cout<<"您还要输入吗?(y/n)"<endl;
ini=cyn();
}
mummax=i;//材料种数
return mummax;//返回材料种数
}
void Mater::disp(Mt *mate,int mnummin,int mnummax)//定义输出成员函数
{
int i,j;
for(i=0;i<MAX_ITline9;i++)
{
for(j=0;j<MAX_ITrow9;j++)
cout<<itemname[i][j];
cout<<endl;
}
cout<<setiosflags(ios::left);
cout.precision(10);
for(i=mnummin;i<mnummax;i++)
}
{
cout<<setw(3)<<mate[i].sortid
<<setw(3)<<mate[i].matid
<<setw(12)<<mate[i].name
<<setw(10)<<mate[i].price
<<setw(6)<<mate[i].datain
<<setw(10)<<mate[i].amountin
<<setw(6)<<mate[i].dataout
<<setw(10)<<mate[i].amountout
<<setw(6)<<mate[i].remain
<<setw(10)<<mate[i].amremain
<<endl;
}
void Mater::stati(Mt *& mate, int mummax) // 定义统计成员函数
{
for(int i=0; i<mummax; i++)
{
mate[i].remain = mate[i].datain - mate[i].dataout;
mate[i].amountin = mate[i].datain * mate[i].price;
mate[i].amountout = mate[i].dataout * mate[i].price;
mate[i].amremain = mate[i].remain * mate[i].price;
}
}
void Mater::inquiry(Mt *mate, int mummax) // 定义查询成员函数
{
int i, mtid, c, choiceinqu = 2000;
char d='y';
string name1;
while(choiceinqu != 3 || d == 'y')
{
displaymenu(menutitle1, menuitems1, MAX_ITEMS1);
choiceinqu = chooseoption();
switch(choiceinqu)
{
case 1: cout << "请输入材料号: " << endl;
mtid = dig1();
c = 1;
for (i = 0; i < mummax; i++)
if (mate[i].matid == mtid)
{
disp(mate, i, i + 1);
c = 0;
}
}
}
}
if(c!=0)
{
cout<<"对不起,查不到",;
d=asq(ASQ1,ASQ4);
}
break;
case 2:cout<<"请输入材料名称: "<<endl;
cin>>name1;
delay1(1000);
c=1;
for (i=0;i<mummax;i++)
if(mate[i].name==name1)
{
disp(mate,i,i+1);
c=0;
}
if(c!=0)
{
cout<<"对不起,查不到";
d=asq(ASQ2,ASQ4);
}
break;
case 3:cout<<"您要返回吗? (y/n) "<<endl;
d=cyn();
if(d==y')
d='n';
else
d='y';
break;
}
void Mater::modify(Mt *& mate,int mummax)//定义修改成员函数
{
int i,k,m,mtid;
string name1,cname;
char d='y';
char b,c,e='y',f='y';
while(d==y')
{
m=0;
b=asq(ASQ5,ASQ6);
if(b==y')
{
cout<<"请输入要修改的材料号:";
}
}
}
mtid=dig1();
for (i=0;i<mummax;i++)
if(mate[i].matid==mtid)
{
disp(mate,i,i+1);
m=1;
break;
}
}
else
{
c=asq(ASQ5,ASQ7);
if(c=='y')
{
cout<<"请输入要修改的材料名称:";
cin>>name1;
delay1(1000);
for (i=0;i<mummax;i++)
if(mate[i].name==name1)
{
disp(mate,i,i+1);
m=1;
break;
}
}
}
if(m!=1)
{
asq(ASQ13,ASQ11);
disp(mate,0,mummax);
f=n';
}
while(f=='y')
{
while(e=='y')
{
cout<<"请输入要修改的项目名称:";
cin>>cname;
delay1(1000);
if(cname=="收入金额"||cname="发出金额"||cname="结存数量"||cname="结存金额")
{
cout<<"这些项目不能修改,请您重新输入"<<endl;
continue;
}
if(cname="分类号")
k=1;
else if(cname="材料号")
k=2;
else if(cname="材料名称")
k=3;
else if(cname="单价")
k=4;
else if(cname="收入数量")
k=5;
else if(cname="发出数量")
k=6;
else {
cout<<"没有该项目名称,请重新输入"<<endl;
continue;
}
cout<<"请输入要修改的数据信息:";
switch(k)
{
case 1:mate[i].sortid=dig1();
break;
case 2:mate[i].matid=dig1();
break;
case 3:cin>>mate[i].name;
break;
case 4:mate[i].price=dig1();
break;
case 5:mate[i].datain=dig1();
break;
case 6:mate[i].dataout=dig1();
break;
}
e=asq(ASQ8,ASQ9);
if(e=='n')
break;
}
e='y';
while(m==1)
{
stati(mate,mummax);
disp(mate,i,i+1);
break;
}
f=asq(ASQ12,ASQ3);
if (f=='n')
break;
}
d=asq(ASQ8,ASQ10);
e='y';
f='y';
}
char Mater::cyn() //定义接收键盘输入的 y 或 n 字符并返回该字符的成员函数
{
char w;
cin>>w;
while(w!='y'&&w!='n')
{
cout<<"请输入小写字母 y 或 n"<<endl;
cin>>w;
}
return w;
}
char Mater::asq(const string ASQZ,const string ASQY) //定义询问返回答案成员函数
{
char b;
cout<<ASQZ;
cout<<ASQY;
b=cyn();
return b;
}
int Mater::chooseoption()//定义选择功能并返回选择结果成员函数
{
int choice;
cout<<"请您选择所需要的功能按下对应的数字键:";
choice=dig1();
return choice;
}
void Mater::displaymenu(string menutitle,char * menuitems3[],int menunum)
//定义显示菜单成员函数
{
cout<<endl;
cout<<"";
cout<<menutitle;
}
cout<<"__";
cout<<endl;
for(int i=0;i<menunum;i++)
cout<<menuitems3[i]<<endl;
int Mater::fread(const char* rfile1,Mt *&mate)//文件数据读出
{
long endpos,curpos;
ifstream infile(rfile1,ios::binary);
try //对文件进行异常处理的 try 语句块,判别文件是否能打开
{
char rf;
if(!infile)
{
cout<<"要打开该大类材料的文件吗?(y/n)"<<endl;
rf=cyn();
if(rf==y')
{
fwrite(rfile1,mate,mummax);
//如是首次进行该大类的软件操作,创建该大类的文件
}
else
throw(rf);//否则,抛掷文件打不开的异常
}
}
catch(char) //文件打不开的异常处理 catch 语句块
{
cerr<<"Don't open file!"<endl;//文件打不开
exit(1);
}
infile.seekg(0,ios::end); //读指针移到文件末尾
endpos=infile.tellg();//记录文件末尾位置
int i=0;
infile.seekg(0,ios::beg);//读指针移到文件头
curpos=infile.tellg();//记录读指针的当前位置
while(curpos!=endpos) //读出文件中的数据,直到最后一条记录
{
infile.read((char*)&mate[i],sizeof(Mt));//从文件读出数据
i++;
curpos=infile.tellg();
}
mummax=i;//保存文件中的材料种数值
infile.close();
return mummax;
}
void Mater::fwrite(const char* wfile1,Mt * &mate,int mummax)//文件数据写入
{
ofstream outfile(wfile1,ios::binary);
if(!outfile)
{
cout<<"Don't open file!"<<endl;
exit(1);
}
for(int i=0;i<mummax;i++)
outfile.write((char*)& mate[i],sizeof(Mt));
outfile.close();
}
double Mater::dig1()//输入非数字的异常处理
{
char c1[10];
char *strp;
char *endptr;
strp=c1;
size_t len1;
in1:try//异常处理的 try 语句块
{
cin>>c1;
strp=c1;
delay1(1000);
len1=strlen(strp);
for(int i=0;i<2;i++)
{
for(int j=0;j<len1;j++)
if((*strp>=48)&(&(*strp<=57)||(*strp==46))
//判别是否为阿拉伯数字0~9或小数点
strp++;
else
throw strp;
//如果输入的字符不是阿拉伯数字0~9或小数点,就抛掷此异常
strp=c1;
}
strp=c1;
return strtod(strp, &endptr);//字符串转换为双精度值,并返回该值
}
catch(char *)//异常处理的 catch 语句块
{
cout<<"输入了非数字,应该在西文方式输入数字,请重新输入"<<endl;//进行异常处理
goto in1;
}
void Mater::delay1(int dtime)//延时成员函数
{
for(int i=0;i<dtime;i++)
for(int j=0;j<100000;j++);
}
//机械、化工、电子类的源文件 che.cpp
#include"che.h"
Mac::Mac()//机械类的构造函数
{
if((mmate=new Mt[NUM])==NULL)//分配存放机械材料的堆空间
{
cout<<"can't allocate more memory,terminating.\n";
exit(1);
}
mfile="mmatf2.dat";//机械类二进制文件名
}
Che::Che()//化工类的构造函数
{
if((cmate=new Mt[NUM])==NULL)//分配存放化工材料的堆空间
{
cout<<"can't allocate more memory,terminating.\n";
exit(1);
}
cfile="cmatf2.dat";//化工类二进制文件名
}
Ele::Ele()//电子类的构造函数
{
if((emate=new Mt[NUM])==NULL)//分配存放电子材料的堆空间
{
cout<<"can't allocate more memory,terminating.\n";
exit(1);
}
efile="ematf2.dat";//电子类二进制文件名
//菜单类的源文件 menu.cpp
#include"menu.h"
Menu::Menu()/菜单类 Menu 的构造函数
{
menutitle0="主菜单";
menuitems[0]="1.输入";
menuitems[1]="2.查询";
menuitems[2]="3.修改";
menuitems[3]="4.统计";
menuitems[4]="5.输出";
menuitems[5]="6.退出";
sortnum[0]="机械——1";
sortnum[1]="化工——2";
sortnum[2]="电子——3";
}
void Menu::displaysort()//显示分类状态
{
cout<<endl;
cout<<"分类号:<<endl;
for(int i=0;i<SORTID;i++)
cout<<sortnum[i]<<endl;
cout<<"请输入分类号,";
}
void Menu::run()//运行
{
int choice1=1;
Mac m;
Che c;
Ele e;
int sort;
cout<<"欢迎您使用仓库材料管理软件<<endl;
mnum=m.fread(mfile,mmate);//读机械类文件
cnum=c.fread(cfile,cmate);//读化工类文件
elenum=e.fread(efile,emate);//读电子类文件
while(choice1!=6)
{
m.displaymenu(menutitle0,menuitems,MAX_ITEMS);//显示主菜单
choice1=m.chooseoption();//选择何种操作
if(choice1==6)//当选择“退出”时,询问“真的要退出吗”
{
cout<<"您真的要退出吗?(y/n)”;
char yn;
yn=m.cyn();
if(yn==n')//如果不退出
{
m.displaymenu(menutitle0,menuitems,MAX_ITEMS);//显示主菜单
choice1=m.chooseoption();//又选择何种操作
}
}
switch(choice1)//根据选择进入各项操作
{
case 1:displaysort();//显示分类状态
sort=c.chooseoption();
switch(sort)//输入
{
case 1:mnum=m.fread(mfile,mmate);//读机械类文件
m.delay1(1000);
mnum=m.getdata(mmate,mnum);
//进入机械分类进行输入操作
m.stati(mmate,mnum);//调用统计成员函数
m.disp(mmate,0,mnum);//调用输出成员函数
m.fwrite(mfile,mmate,mnum);//写机械类文件
break;
case 2:cnum=c.fread(cfile,cmate);
c.delay1(1000);
cnum=c.getdata(cmate,cnum);
//进入化工分类进行输入操作
c.stati(cmate,cnum);
c.disp(cmate,0,cnum);
c.fwrite(cfile,cmate,cnum);
break;
case 3:elenum=e.fread(efile,emate);
e.delay1(1000);
elenum=e.getdata(emate,elenum);
//进入电子分类进行输入操作
e.stati(emate,elenum);
e.disp(emate,0,elenum);
e.fwrite(efile,emate,elenum);
break;
default:cout<<"无效的选择,重新输入";
//处理超出1~3的数字的选择
cout<<endl;
}
break;
case 2:displaysort();//显示分类状态
sort=c.chooseoption();
switch(sort)//查询
{
case 1:mnum=m.fread(mfile,mmate);
m.delay1(1000);
m.inquiry(mmate,mnum);
break;
case 2:c.fread(cfile,cmate);
c.delay1(1000);
c.inquiry(cmate,cnum);
break;
case 3:elenum=e.fread(efile,cmate);
e.delay1(1000);
e.inquiry(cmate,elenum);
break;
default:cout<<"无效的选择,重新输入";
}
break;
case 3:displaysort();//显示分类状态
sort=c.chooseoption();
switch(sort)//修改
{
case 1:mnum=m.fread(mfile,mmate);
m.delay1(1000);
m.modify(mmate,mnum);
m.fwrite(mfile,mmate,mnum);
break;
case 2:cnum=c.fread(cfile,cmate);
c.delay1(1000);
c.modify(cmate,cnum);
c.fwrite(cfile,cmate,cnum);
break;
case 3:elenum=e.fread(efile,cmate);
e.delay1(1000);
e.modify(emate,elenum);
e.fwrite(efile,cmate,elenum);
break;
default:cout<<"无效的选择,重新输入";
//处理超出1~3的数字的选择
cout<<endl;
}
break;
case 4:displaysort();//显示分类状态
sort=c.chooseoption();
switch(sort)//统计
{
case 1: mnum=m.fread(mfile, mmate);
m.delay1(1000);
m.stati(mmate, mnum);
m.disp(mmate, 0, mnum);
m.fwrite(mfile, mmate, mnum);
break;
case 2: cnum=c.fread(cfile, cmate);
c.delay1(1000);
c.stati(cmate, cnum);
c.disp(cmate, 0, cnum);
c.fwrite(cfile, cmate, cnum);
break;
case 3: elenum=e.fread(efile, emate);
e.delay1(1000);
e.stati(emate, elenum);
e.disp(emate, 0, elenum);
e.fwrite(efile, emate, elenum);
break;
default:cout<="无效的选择,重新输入";
//处理超出1~3的数字的选择
cout<<endl;
}
break;
case 5: displaysort(); //显示分类状态
sort=c.chooseoption();
switch(sort)//输出
{
case 1: mnum=m.fread(mfile, mmate);
m.delay1(1000);
m.disp(mmate, 0, mnum);
break;
case 2: cnum=c.fread(cfile, cmate);
c.delay1(1000);
c.disp(cmate, 0, cnum);
break;
case 3: elenum=e.fread(efile, emate);
e.delay1(1000);
e.disp(emate, 0, elenum);
break;
default:cout<<"无效的选择,重新输入";
//处理超出1~3的数字的选择
cout<<endl;
}
break;
case 6:m.fwrite(mfile,mmate,mnum);//写机械类文件
c.fwrite(cfile,cmate,cnum);//写化工类文件
e.fwrite(efile,emate,elenum);//写电子类文件
break;//退出
default:cout<<"无效的选择,重新输入";//处理超出1~6的数字的选择cout<<endl;
}
//主函数的源文件m1.cpp
#include"menu.h"
void main();//主函数
{
Menu me;//定义菜单类Menu的对象me
me.run();//调用对象me的运行成员函数run
}
运行结果一(初次使用该软件或删除了3个数据文件):
欢迎您使用仓库材料管理软件
要打开该大类材料的文件吗?(y/n)
y
要打开该大类材料的文件吗?(y/n)
y
要打开该大类材料的文件吗?(y/n)
y
- 输入
- 查询
- 修改
- 统计
- 输出
- 退出
请您选择所需要的功能按下对应的数字键:5
分类号:
机械——1
化工——2
电子——3
请输入分类号,请您选择所需要的功能按下对应的数字键:1
| 分材材料 | 单价 | 收入数量 | 收入金额 | 发出数量 | 发出金额 | 结存数量 | 结存金额 |
| 类料名称 | (元) | (个) | (元) | (个) | (元) | (个) | (元) |
| 号号 |
结果正确。
运行结果二(多次使用该软件后):
| 王采单 |
| 1. 输入 |
| 2. 查询 |
| 3. 修改 |
| 4. 统计 |
| 5. 输出 |
| 6. 退出 |
| 请您选择所需要的功能按下对应的数字键:3 |
分类号:
机械——1
化工——2
电子——3
请输入分类号,请您选择所需要的功能按下对应的数字键:2
您记得要修改的材料号吗?(y/n) y
| 分材 | 材料 | 单 | 收入 | 收入 | 发出 | 发出 | 结存 | 结存 |
| 类 | 料 | 价 | 数量 | 金额 | 数量 | 金额 | 数量 | 金额 |
| 号 | 号 | (元) | (个) | (元) | (个) | (元) | (个) | (元) |
| 2 | 1 | 酒精 | 28.7 | 100 | 2870 | 10 | 287 | 90 |
请输入要修改的项目名称:发出数量
请输入要修改的数据信息:30.9
输入了非数字,应该在西文方式输入数字,请重新输入
| 分材 | 材料名称 | 单价(元) | 收入数量(个) | 收入金额(元) | 发出数量(个) | 发出金额(元) | 结存数量(个) | 结存金额(元) |
| 号 | 1 | 28.7 | 100 | 2870 | 30 | 861 | 70 | 2009 |
请您核对,您还要修改吗?(y/n)n
您还要修改其他材料吗?(y/n) n
___主菜单___
- 输入
- 查询
- 修改
- 统计
- 输出
- 退出
请您选择所需要的功能按下对应的数字键:5
分类号:___
机械——1
化工——2
电子——3
请输入分类号,请您选择所需要的功能按下对应的数字键:3
| 分 类 号 | 材 料 名 称 | 单 价 (元) | 收入 数量 (个) | 收入 金额 (元) | 发出 数量 (个) | 发出 金额 (元) | 结 存 数量 (个) | 结 存 金额 (元) |
| 3 | 1 平板电视 | 3500 | 20 | 70000 | 10 | 35000 | 10 | 35000 |
| 3 | 2 音箱 | 300.5 | 10 | 3005 | 2 | 601 | 8 | 2404 |
| 3 | 9 电风扇 | 400 | 20 | 8000 | 20 | 8000 | 0 | 0 |
| 3 | 13 电磁炉 | 356 | 10 | 3560 | 8 | 2848 | 2 | 712 |
| 3 | 41 VCD | 0 | 9 | 0 | 8 | 0 | 1 | 0 |
结果正确。
20.4 面向对象的综合设计的亮点
1. 在什么情况下用面向对象综合设计的亮点
2. 面向对象综合设计具体知识的亮点
最好在任何情况下都用面向对象的设计方法设计程序,复杂的问题就用综合设计方法。
面向对象的综合设计还是按照2.3.1节中所述的流程和第13章中面向对象程序设计方法的知识进行开发,只不过添加了选择总体设计方案的部分,还要注意工程文件的各组成部分。
3. 运用面向对象综合设计的亮点
在投入实际运行前要多运行、多调试,不单只运行程序中的各种情况,还要设想实际运行中会出现什么情况,尤其是一些异常情况。特别要多运行一些边界情况,如初始情况,末尾情况等,对这些妨碍程序可靠运行的情况进行预先处理,以保证程序具有优良的性能。