问题解决与软件工程.docx
- 文档编号:4039514
- 上传时间:2022-11-27
- 格式:DOCX
- 页数:23
- 大小:39.75KB
问题解决与软件工程.docx
《问题解决与软件工程.docx》由会员分享,可在线阅读,更多相关《问题解决与软件工程.docx(23页珍藏版)》请在冰豆网上搜索。
问题解决与软件工程
第1章问题解决与软件工程
如果我们真正理解了问题本身,自然就得到了问题的答案,因为答案从来不会背离问题。
——JidduKrishnamurti
人们总在努力获得他们想要的东西;但惟一的问题在于,在真正得到之前他们并不知道他们要的是什么。
——奥尔多·贺胥黎
这是我惟一能想到的融工程和艺术为一体的工作。
其中有令人难以置信的精密的技术成分,因为你必须要进行十分深入的思考;而另一方面,它具有广泛的创造空间,在那里惟一的限制只在于你的想象范围。
——安德鲁·赫茨菲尔德
本章目标
●揭示计算机广泛多样的应用。
●初识C++程序。
●阐明软件生命周期的各个基本阶段,包括以对象为中心的设计(Object-CenteredDesign)。
●(可选)突出了计算机专家们面临的难题,同时提出某些道德原则。
●(可选)初识类和面向对象设计。
从前一章的介绍中可知,在很多领域计算机已经成为人们必不可少的工具。
以下所列出的只是计算机诸多应用的一部分,所有这些应用都需要编写软件,而本书的重点则是教授如何使用C++来开发这些软件。
本章中我们来看看一个简单的C++例子,并且演示如何使用以对象为中心的设计思想(Object-CenteredDesign,OCD)来解决问题。
本书的第一个事例学习引入了一个更为实际的问题,在本书的Web站点上提供了包括OCD设计在内的完整解答。
同时提供了“对象化思维”这样的选学内容以方便那些希望对C++类有所了解的读者。
本章以一个相关知识作为结束,而相关知识将贯穿本书始终,它将向读者介绍计算机科学的主要领域。
下面例举一些计算机应用的主要领域:
(1)商业和金融
邮件列表和订单工资单和账单
库存控制预定系统(航班、座舱等)
文字处理数据管理
电子表格EFT(电子转账)
ATMs(自动柜员机)电子邮件
家庭银行理财
保险索赔处理
(2)工业
装配线上的机器人生产调度
CAD(计算机辅助设计)CAM(计算机辅助制造)
CIM(计算机集成制造)市场分析
工程管理和控制
(3)政府部门
国防系统航天计划
人口普查自动化交通控制系统
国家和地方彩票FBI的NCIS(国家刑事情报处)
NOAA(国家海洋和气象局)的天气预报
(4)医疗
生命维持系统监控专家诊断系统
CAT(计算机轴向X光摄影)扫描MR(磁共振)扫描
在线病历访问
(5)娱乐
电影动画电影特技
电影布景计算机和电视游戏
(6)科学
分子分析晶体结构研究
食物质量测试大型动态系统模拟
(7)信息科技
数字图书馆在线画廊
多媒体参考著作
开发适用于这些应用的软件是一个融科学和艺术于一炉的复杂过程,需要想象力、创造力和天赋,也需要一整套技术和方法。
软件工程正是解决问题的一整套技术和方法的应用。
本章将通过一个例子来讲解一些方法和软件开发过程的几个基本阶段。
1.1欢迎来到C++世界
一个程序就是一个用某种编程语言编写的语句集合。
正如英语的语法规定了英语句子怎样构成一样,C++的语法规则规定了如何书写基本语句以及如何将基本语句结合起来构成更为复杂的语句并最终构成程序。
本书的大部分内容都将讲解怎样书写C++语句以及如何将语句有机组合起来形成完整的程序。
在本节中,先看一个简单的C++例子。
例1.1是一个向用户问好的程序,它首先提示用户输入他(她)的名字,然后显示一条信息欢迎他(她)来到C++世界。
在该程序样本的运行中,用户输入的信息(sarah)被标以下划线从而与程序的输出相区分。
该程序用来演示C++程序的基本结构。
例1.1问候其用户
/*greeting.cpp问候其用户
*
*输入:
用户名
*输出:
个性化问候
*******************************************************************/
#include
#include
usingnamespacestd;
intmain()
{
cout<<"Pleaseenteryourfirstname:
";
stringfirstName;
cin>>firstName;
cout<<"\nWelcomtotheworldofC++,"< \n"; } 运行示例: Pleaseenteryourfirstname: Sarah用户输入 WelcometotheworldofC++,Sarah! 程序的第一行以字符对“/*”开始,而第五行以字符对“*/”结束;在C++程序中,位于/*和*/之间的内容都是注释。 程序开头这样的多行注释就是所谓的开放文档,用来描述程序的功能和输入/输出信息。 接下来以#include开头的两行叫编译指令,它们告诉编译器将iostream库中执行输入/输出操作的项目以及string库中字符处理的项目加入到程序中(这些项目以注释的形式列在//之后)。 再下一行告诉编译器这些库是称为std的命名空间中的标准库;如果不使用这一语句,则必须在每个引用的库项目(比如cout)前添加前缀std: : ,例如: std: : cout<<"Pleaseenteryourfirstname: "; 程序的其余部分形式如下: intmain() { 一系列C++语句 } 这实际上是一个名为main的函数,它被称为这个程序的主函数。 单词main前面的单词int是一个说明函数返回类型的C++关键字,在这里意味着主函数要向操作系统返回一个整数值。 返回0则意味着程序的正常结束,有些程序员习惯于(有些编译器要求这样做,比如: MircrosoftVisualC++)将一个返回语句return0;作为程序的最后一个语句,而一个非0的返回值则意味着程序的非正常结束。 C++程序的运行从main函数中花括号({和})之间的第一个语句开始依次往下执行,要注意每条语句都以分号结束。 在例1.1所示的程序中,第一个语句用<<操作符向屏幕(cout)输出一行信息,提示用户输入用户名: cout<<"Pleaseenteryourfirstname: "; 下一条语句是: stringfirstName; 声明了一个存储字符串的变量firstName,而语句 cin>>firstName; 使用>>操作符读入用户从键盘(cin)输入的字符串并将其存储到firstName变量中。 再下一条语句是: cout<<"\nWelcometotheworldofC++,"< \n"; 往屏幕输出一句个性化的问候信息。 这条语句由3部分组成: (1)特殊字符\n,它使得从一新行开始输出如下字符串: WelcometotheworldofC++, (2)变量firstName中存储的字符串。 (3)字符“! ”和紧跟它的一个换行符。 1.2用软件工程解决问题 正如在本章介绍中看到的那样,软件工程使用可靠而基本的方法来获得问题的解决方案。 尽管问题千差万别,但软件开发都遵循几个共同的阶段: ●设计: 分析问题和设计方案,得到解决问题的算法。 ●编码: 用高级语言(比如C++)编写解决问题的程序。 ●测试、运行和调试: 对程序进行严密的测试和排除所有错误(称为bug)。 ●维护: 必要时修改和更新程序以满足用户变化的需求。 在这一部分,将通过一个例子来演示软件生命周期的各个阶段。 这个例子非常简单,这样我们可以专注于每一阶段的主要思想而不用去顾及太多的细节。 1.2.1问题 Kansas的Cawker城有一个世界上最大的麻绳球,住在这里的人们从1953年开始就在这个球上绕麻绳了。 在写作本书的时候,该球的平均半径大约是61英尺。 来这里旅游的人们都会对下面两个问题感兴趣: (1)这个球有多重? (2)如果把这个麻绳球上的麻线展开能延伸多少英里? 这里将设计一个程序来回答第一个问题,而第二个问题则留作练习(见1.2.7节的练习4)。 1.2.2对象中心化设计 待解决的问题通常用自然语言描述,比如说英语,但常常不够精确,因此有必要对问题进行精确的分析和表达。 对1.2.1节的问题来说,这很简单,只需表达为: 给出麻绳球的半径,求球的重量。 然而,对于很多描述得不够清楚的问题来说,分析起来要复杂得多。 有时甚至连那些提出问题的人自己都没有很好地理解它们;他们既不知道如何去解决它们,也不知道计算机的能力和限制。 我们把这一套所用的如何设计软件解决方案的方法叫做对象中心化设计(Object-CenteredDesign,OCD)。 在其最简单的形式中,包含了下列步骤: (1)行为(Behavior): 尽可能清楚地描述这个程序该如何运转。 (2)对象(Objects): 确定问题描述中的现实对象,并对它们进行分类。 (3)操作(Operations): 确定解决这个问题需要的操作。 (4)算法(Algorithm): 安排好问题的对象和操作的合理顺序,从而解决这个问题。 第4步的结果将会产生解决这个问题的算法,它是我们编写程序的蓝图。 下面具体介绍这些步骤。 1.行为(Behavior) 首先需要确定这个程序是干什么的(即要求这个程序如何运转),设计的其余部分依赖于这一步骤,所以必须把它描述得尽可能精确。 行为(Behavior)程序应该在屏幕上显示球半径的提示信息,然后用户从键盘输入半径值供程序读取,最后程序计算球的重量并在屏幕上显示该值。 注意我们将问题推广到求任意球的重量,这个推广过程是分析问题时的一个重要方面。 这样将使得程序不仅能解决当前问题,更重要的是能在尽量不作改动的情况下解决所有类似的问题。 2.对象(Objects) 一旦知道了程序的行为,就可以开始确定问题所涉及的对象了。 一种方法是找出在行为描述中出现的名词,而应该忽略像用户和程序这样的名词。 如下: 行为(Behavior)程序应该在屏幕上显示球半径的提示信息,然后用户从键盘输入半径值供程序读取,最后程序计算球的重量并在屏幕上显示该值。 这样便得到下面一些对象球半径的提示信息、屏幕、球的半径、键盘、球的重量。 现实中的对象必须用程序设计语言表示成软件对象(有时也称为实体)。 C++中的软件对象必须属于某种可知其值范围的类型。 有些对象可以取不同值,它们被称为变量(variables)并且必须被命名;而那些值保持不变的对象可以命名也可以不命名。 在上面的例子中,可以将对象进行分类,如表1-1所示。 表1-1 现实对象 软件对象 类型 类别 名字 球半径的提示信息 string 常量 无 屏幕 ostream 变量 cout 球的半径 double 变量 radius 键盘 istream 变量 cin 球的重量 double 变量 weight 第一个软件对象(即提示信息)没有被命名,因为它在程序的执行过程中乃至以后都不会改变其值。 C++中字符序列是字符串(string)类型的值,并且在程序中字符串常量(也称为字符符号)需用双引号括起来。 第二个软件对象,即屏幕(或称为窗口),有一个C++中预定义的名字cout并且属于预定义的ostream(输出流)类型。 由于程序执行中每次往屏幕输出的内容是变化的,故其值也是变化的。 第三个软件对象,即球的半径被命名为radius。 由于每次用户从键盘上输入的内容不同,故其值是不断变化的。 在C++中,存储实型(有小数点的数字)值的数值对象属于double(或float)型。 第四个软件对象,即键盘在C++中,键盘有一个预定义的名字cin且属于预定义的类型istream(输入流);由于程序的执行中需要从键盘输入数据,故这个对象的值也是变化的。 最后一个软件对象,即球的重量被命名为weight。 因为它保存实型值,所以是double类型的;又因为其值由程序计算得到,故它也是一个变量。 3.操作(Operations) 一旦确定了程序中的对象,并将其分类以后,下一步就是确定解决问题所需要的操作。 为了确定对象,可以从行为描述中的名词入手。 这里为了确定操作,也可以从行为描述中的动词入手。 如下: 行为(Behavior)程序应该在屏幕上显示球半径的提示信息,然后用户从键盘输入半径值供程序读取,最后程序计算球的重量并在屏幕上显示该值。 使用刚刚确定的对象,可以这样描述这些操作: (1)向cout输出一条信息,提示输入球的半径。 (2)从cin中读入一个实型值并将其存储在radius变量中。 (3)计算重量weight。 (4)把weight值输出到cout。 C++提供了一个输出操作符<<来向cout中插入字符串和数值,然后cout将这些内容显示在屏幕,这里可以使用这个操作符输出提示信息和计算结果weight。 类似地,C++提供输入操作符>>从cin(也就是键盘)中读取值并将其存储在变量对象中,这里可以用这个操作符从键盘输入实型值然后存储在radius变量中。 计算球的重量需要一点额外的工作,这可以通过如下公式算出: 重量(weight)=密度(density)×体积(volume) 一个半径为r的球体积V为: 结合以上两个公式得到重量的公式: 这意味着需要列一个详细的操作列表,如下: (1)向cout输出球半径的提示信息,提示输入球的半径。 (2)从cin输入一个实型值并存储在radius变量中。 (3)向cout输出球密度的提示信息,提示输入球的密度。 (4)从cin输入一个实型值并存储在density变量中。 (5)计算weight: ①计算radius的3次方; ②做实数乘法(作3次); ③做实数除法。 (6)向cout输出weight。 同很多编程语言一样,在C++中实数的乘法和除法运算符分别是*和/;尽管没有指数运算符,但标准库中提供了函数pow()来做指数运算;因此所有解决问题所需要的操作都可以顺利进行。 这样,计算球重的公式就增加了6个新的对象,如表1-2所示。 表1-2 现实对象 软件对象 类型 类别 名字 提示球半径信息 string 常量 无 续表 现实对象 软件对象 类型 类别 名字 屏幕 ostream 变量 cout 球的半径 double 变量 radius 键盘 istream 变量 cin 提示信息(density) string 常量 无 球的密度 double 变量 density 球的重量 double 变量 weight 4.0 double 常量 无 double 常量 PI 3 integer 常量 无 3.0 double 常量 无 这里给 取一个名字,因为这样既增加了程序的可读性,又使得当精度要求变化时修改程序更加容易。 4.算法(Algorithm) 当确定了所有的对象和操作以后,就可以将这些操作组合起来形成算法。 如果前面的步骤正确无误,这一步非常简单。 算法: (1)初始化常量PI。 (2)向cout输出提示信息,提示输入半径。 (3)从cin中读入一个实型值并将其存储在radius变量中。 (4)向cout输出提示信息,提示输入密度(density)。 (5)从cin中读入一个实型值并将其存储在density变量中。 (6)计算: weight=density*4.0* *radius3/3.0。 (7)向cout输出weight。 上述操作序列有时也被称做伪码算法,因为它不用任何一种程序设计语言编写,却非常像程序代码。 这个算法是下一阶段开发的蓝图。 1.2.3用C++编码 一旦为这个问题设计好了算法,就可以用像C++这样的高级语言来编写程序。 步骤如下: (1)创建一个程序框架,它包含开放文档、包含对象和操作所需要库代码的编译指令、空的main函数。 (2)把每一个算法步骤转换成代码。 如果它用到了没有声明的软件对象,则需添加一条声明语句指明对象的名字和类型。 对于上面的例子,程序框架如下: /*sphereWeight.cpp计算球的重量 * *输入: 球的半径(英尺)和密度(磅/立方英尺) *输出: 球重(磅) **********************************************/ #include #include usingnamespacestd; intmain() { } 这里用#include编译指令将提供了注释后的这些对象和方法的库iostream和cmath包含到程序中,这个程序框架其实是一个可以正确编译和执行的完整程序。 下面把算法的每个步骤转换成代码。 (1)初始化常量PI 可以转换成如下C++语句: constdoublePI=3.14159; 然后将这个语句插入到main函数中: ... intmain() { constdoublePI=3.14159; } (2)向cout输出提示信息,提示输入半径 可以用C++写为: cout<<"Enterthesphere'sradius(feet): "; 然后把这个语句加到main函数中: ... intmain() { constdoublePI=3.14159; cout<<"Enterthesphere'sradius(feet): "; } (为了增加可读性,在这个语句与前面的常量声明语句间增加一个空行) (3)从cin中读入一个实型值并将其存储在radius变量中 这里使用了两个对象cin和radius。 第一个对象cin由iostream库提供,并且已经被#include编译指令加入到了程序当中;然而对radius来说,必须增加一条声明语句以说明它的类型和名称: doubleradius; 然后把实现了算法步骤(3)的语句添加到main函数中 ... intmain() { constdoublePI=3.14159; cout<<"Enterthesphere'sradius(feet): "; doubleradius; cin>>radius; } 按此方法继续下去,把算法的每一个步骤转换为C++代码,就得到了例1.2所示的完整程序。 例1.2还给出了一个输入值为radius=6.5,density=14.6的运行示例。 例1.2球重量的计算 /*sphereWeight.cpp计算球的重量 * *输入: 球的半径(英尺)和密度(磅/立方英尺) *输出: 球重(磅) **********************************************/ #include #include usingnamespacestd; intmain() { constdoublePI=3.14159; cout<<"Enterthesphere'sradius(feet): "; doubleradius; cin>>radius; cout<<"Enteritsdensity(pounds/cubicfeet): "; doubledensity; cin>>density; doubleweight=density*4.0*PI*pow(radius,3)/3.0; cout<<"\nTheweightofthesphereisapproximately"< "pounds.\n"; } 运行示例: Enterthesphere'sradius(feet): 6.5 Enteritsdensity(ponds/cubicfeet): 14.6 Theweightofthesphereisapproximately16795pounds. 可以使用一个文本编辑器将程序输入内存,在软件开发的下一阶段,仍要用文本编辑器来排除程序的错误。 1.2.4测试、运行和调试 很多原因会导致程序的错误,最常见的3种是: (1)违反高级语言的语法规则。 (2)程序执行时的错误。 (3)算法设计的错误。 程序排错的过程就叫做调试(Debugging)。 第一类错误也叫语法错误(syntaxerror)。 编译器负责将高级语言程序转换成机器能够识别的功能相同的机器语言程序。 在转换过程中,编译器检查程序是否符合高级语言的语法规则,如果程序违反了语法规则,编译程序就会产生一条提示出现问题的诊断信息。 例如,如果忘记了语句末的分号,即将“doubleradius;”写成“doubleradius”,编译器将给出这样一条诊断信息: Error: ';'expected SphereWeight.cppline18cin>>radius 不同的编译器可能会输出不同的诊断信息,如: sphereWeight.cpp: Infunction'intmain()': shpereWeight.cpp: 18: parseerrorbefore'>' 编译器仅仅显示其处理过程中遇到错误行的下一行行号,第二条诊断信息同样没有包含详细的信息,它仅仅指示语法分析器(编译器的一部分)碰到了非法字符。 学习理解特定编译器的这些错误信息是一个很重要的技能。 第二类错误只有在运行时才能被检测到,所以叫做运行时错误(run-timeerror)。 运行时错误包括试图在算术运算中把0作为除数,或者试图求一个负数的平方根,或者在计算时发生了越界溢出等。 描述这类错误的信息通常显示在屏幕上,或者包含在用户文档中。 一旦找到错误原因,应该立即改正错误的语句或表达式,然后重新编译和执行修改后的程序。 第三类错误叫做逻辑错误(logicerror),它意味着程序员在算法设计上出现了错误。 例如,例1.2包含下面的语句: doubleweight=density*4.0*PI*pow(radius,3)/3.0; 如果因一时粗心而将第一个*写成了+: doubleweight=density+4.0*PI*pow(radius,3)/3.0; 因为这条语句没有违反任何C++语法规则,编译器无法捕获这个错误,因而这个程序能够编译和运行,但永远得不到正确的结果,因为计算重量的公式错了。 看一个程序是否有逻辑错误,可以用样本数据作为输入看能否得到正确的输出结果。 这种测
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 问题解决 软件工程
![提示](https://static.bdocx.com/images/bang_tan.gif)