面向对象程序设计课程设计指导书.doc_第1页
面向对象程序设计课程设计指导书.doc_第2页
面向对象程序设计课程设计指导书.doc_第3页
面向对象程序设计课程设计指导书.doc_第4页
面向对象程序设计课程设计指导书.doc_第5页
已阅读5页,还剩174页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

面 向 对 象 程 序 设 计课 程 设 计 指 导 书刘 平 山 宁 黎 华桂 林 电 子 科 技 大 学目 录 第一章 课程设计目标1.1目的本次课程设计的综合训练能帮助学生建立面向对象思想的思维方式,加深对面向对象理论和基本知识的理解,掌握使用C+语言进行面向对象程序设计的基本方法;培养学生利用面向对象技术解决实际问题的能力。从而使得学生增加对面向对象方法和思想的感性认识,最终能够让学生能够利用C+语言以面向对象的思维方式编写出一些小型可靠的面向对象程序,帮助学生系统地掌握面向对象程序设计技术,切实提高面向对象的思维能力和程序设计能力。1.2课程设计要求1 利用CRC卡片设计类和类中的方法,并使用UML绘制类图,然后实现该程序。2 编写的程序要具有良好的可读性,在适当的地方要加上注释,命名数据成员和方法应取一些有意义的名词,养成良好的编程习惯。3 所编写出的程序要能正确运行,具有友好的操作方式。4 撰写课程设计报告。课程设计报告的格式见附录A。1.3本书内容介绍第一章说明课程设计目标和考核标准。第二章讲述进行面向对象程序设计的方法。学生按照本书所介绍的方法进行训练能够有效提高以面向对象思维思考的能力。还提供了一个实例演示整个过程。第三章提供了五个课程设计题目,学生可以通过这5个题目来学习,并完成扩展部分,达到课程设计的要求。第四章提供了六个可供选择的课程设计题目,进一步丰富学生的选择性。前四个题目提供了源代码参考,并要求有相应的扩展。后面两道题目没有提供相应的源代码。附录A介绍了向量vector。附录B给出了课程设计报告的格式。附录C给出了第四章四个题目的参考源代码。1.4评价标准1对于已经提供源代码的程序,如果没有实现扩展功能,最高成绩为良。如果实现了扩展功能,最高成绩为优。2对于没有提供源代码的程序,实现后最高成绩为优。3程序能正常运行。在演示答辩时,概念准确,能够对程序功能进行充分的验证。5课程设计说明书格式规范,图表完整,字迹工整、整齐。第二章 预备知识2.1软件生命周期软件生命周期的定义是:一个软件从构思到最终停止使用所经历的所有活动。大多数软件工程师把软件开发过程分解为如下5个阶段。下面对这5个阶段做一个概括性的描述:l 分析l 设计l 实现l 测试l 运行在分析(analysis)阶段,需要明确项目将完成什么任务(目标),但并不考虑程序具体如何实现这些功能。分析阶段需要生成一份需求文档(requirement document),在其中详细地描述了程序将要实现的各种功能。作为需求文档的一部分,用户手册用来说明用户如何操作软件以使用这些功能。在需求文档中也应该包括系统的稳定规定,例如程序必须在给定时间内处理多少输入,或者对于系统内存和磁盘空间的最大需求方面的规定。在设计(design)阶段,要为系统的实现做必要的设计。首先需要分析所面临问题的结构。在此基础上,如果采用面向对象设计,则需要设计出所使用的类以及这些类的主要成员函数。相应地,本阶段的产品是对所采用的类及其主要成员函数的描述,以及用来描述类之间关系的图表。在实现(implementation)阶段,编写程序代码来具体实现所设计的类及其成员函数。本阶段最终产生一个完整的程序。测试(testing)阶段的工作就是通过测试来验证程序完成了所要的功能。在这个阶段,测试人员提交一份测试报告,说明所进行的测试和测试的结果。在运行(deployment)阶段将程序交付给用户,用户安装并使用系统以获得所需的功能。2.2 CRC卡片在软件开发的设计阶段,主要目的是构造适当的结构,使得在计算机上实现既定的任务成为可能。当采用面向对象的设计过程时,需要完成以下任务:1.确定需要哪些类;2.确定每一个类的职责,即需要做什么样的动作;3.描述类之间的关系。一个类表示了一些有用的概念。我们已经使用一些类来表示有形的实体,例如产品、圆、时钟等;另一些类用来表示抽象的概念,例如:流、串。一个确定类的简单法则是,从任务描述的名词中寻找可能的构造的类。例如,如果需要完成的工作是打印如图2.1所示的发票,很明显可以构造的类有:发票(invoice)、项目(item)和客户(customer)。将所有可能需要构造的类记录在一个列表中是一个好习惯。在进行讨论的时候,将所有关于类的设计构思记下来并添加到该列表中;最后对该类列表进行筛选,去掉没有价值的候选项。INVOICESams Small Applications100 Main StreetAnytown,CA 98765AMOUNT DUE:$154.78ITEM Qty Price TotalToaster 3 $29.95 $89.85Hair Dryer 1 $24.95 $24.95Car Vacuum 2 $19.99 $39.98图2.1 发票一旦确定了系统需要构造的的类之后,接下来需要为每一个类定义行为。换句话说,需要确定每个类需要什么样的成员函数,从而完成程序的功能。相应地,确定成员函数的一般方法是关注任务描述中的动词,并将其作为成员函数分配到适当的类中去。仍以上面的发票程序为例,程序中应当有一个类用来计算合计金额。接下来,应当考虑在哪一个类中完成这个功能:是由客户类计算自己的应付款项?还是由项目类自己统计?或者由发票类来计算该数据?在本例中,最好是由发票类来负责实现合计金额的计算。可以采用CRC卡片方法来很好地完成上述设计任务。CRC表示类(Class)、职责(Responsibilities)和协作(Collaborators)。简单地说,这种方法工作过程如下:为每一个类构造一个如图2.2所示的索引卡片,称为CRC卡片;当在任务描述中碰到一些动词时,则应考虑将该动作指定给某个类去完成,即在该类中设计相应的成员函数完成该动作;将动作对应类的CRC卡片去处,并把其职责记录在卡片中;如果在完成该动作的过程中需要用到其他类,则将这些其他类构成该类的协作者,也将被记录在卡片中。再来考虑上例:假设将计算合计金额的职责分配给发票类完成,那么就要在发票类的CRC卡片的左边标记“计算合计金额”这样一个指责。如果一个类可以独立地完成指派给它的职责,则不需要做进一步的工作。反之,如果一个类在完成指定职责的过程中必须借助别的类,则要将这些类写在该类的CRC卡片的右边。在本例中,要计算发票的合计金额,则需要每个项目的金额(单项小计);所以项目类便成为发票类的协作者。这时,需要检查对应项目类的CRC卡片,确认其中已经有了“单项小计”这一职责功能。如果没有,则增加该职责。如何知道正在做正确的事情?对于每一个动作对应的职责功能,应通过各个CRC卡片中已记录的职责,来分析它具体做什么事情。一个较为有效的做法是将CRC卡片分类,将相互有联系的卡片放到一起,然后通过移动一个标记来模拟任务的执行,即通过标记在不同卡片中的移动来指示当前活动的对象。这样,不但可以确认设计的正确性,还可以帮助理解各个类之间的协作关系,从而达到更好的设计目的。需要注意的是,在CRC卡片上列出的职责都是高层的(即粗粒度的)。有时,单个职责可能在类中对应两个或更多的成员函数来实现。一些研究者认为,一个CRC卡片中不应包含超过三个不同的职责。CRC卡片是作为非正式目的的而使用的,用于更好地构造类和及其属性。如果需要,可以对卡片中的职责进行删除、移动、分解或者合并。如果发现目前CRC卡片中的内容已经比较混乱,完全可以丢弃,因为这是一个非正式的过程。如果在检查了所有主要任务兵发现它们都可以通过类和职责来解决时,基于CRC卡片方法的设计工作便完成了。图2.2 CRC卡片2.3 UML类图在设计一个程序时,了解类之间的关系是十分重要的,这将在多方面有助于设计。例如,当发现一些类具有相同的行为时,完全可以将这个行为提取出来放到一个基类中,从而使设计更合理并可节省精力。除此之外,如何一些类之间已经被确认相互不存在关系,则可以将这些类分派给不同的程序设计人员去实现,而不必担心它们之间是否有足够的沟通或协调。我们已经学过了类的继承关系。继承关系是一种非常重要的类关系,但绝非唯一有用的关系,而且在实践中常有被滥用的嫌疑。继承关系存在于一般类(基类)和具体类(派生类)之间,这种关系常被描述成isa关系。例如:每一辆卡车都是车辆,每一个存储账户都是银行账户,每一个正方形都是矩形(等宽并等高),等等,它们描述的正是这种关系。但对继承关系的滥用确实存在。例如,考虑一个表示汽车轮胎的Tire类作为Circle类的派生类吗?似乎是合理的,因为Circle类中的一些方法对Tire类也是很有用的,例如:Tire类可以继承Circle类中关于计算半径、周长和圆心的这些方法。的确,这些方法在考虑一个圆形时是必须具备的。虽然这种继承关系可以为程序员带来便利,但是就这两个类所代表的概念来讲,它们之间并不存在这种继承关系。汽车轮胎并不一定就是圆的。轮胎是汽车的一部分,而圆是几何对象。但是轮胎和圆之间还是存在某种关系,一个轮胎有一个圆形轮廓。C+允许构造这种关系,其方法如下: class Tire . private: string rating; Circle boundary; ;这种处理的技术被称为“关联”(association),每一个Tire对象与一个Circle对象关联。再看另一个例子。如果要设计一个程序对高速公路的交通进行图形模拟,则程序应当为轿车、卡车以及其他车辆构造相应模型。每一辆轿车都是(isa)车辆,每一辆轿车也都有轮胎(并且数量是4个,如果加上备用胎,则是5个)。因此,可以将Car类作为Vehicle类的派生类,同时建立Tire类与Circle类之间的关联关系: class Car : public Vehicle . private: vector tires; ;在UML表示中,关联关系用带开口箭头的实线表示。图2.3是一个有继承关系和关联关系的类图。图2.3 类图中的属性和方法如果一个类的对象能操作另一个类的对象,则该类与另一个类关联。例如,对于一个Car类对象,通过简单地访问Tire类数据成员来操作Tire类对象,而Tire类对象通过一个成员变量指向Circle类的一个对象;所以类Car与类Tire、类Tire与类Circle之间就存在着关联关系。实际上,当一个类的数据成员的类型是另一个类时,则这两个类是关联的。需要说明的是,关联关系与前面讲到的依赖关系是相互联系的。如果一个类的成员函数以某种方式使用到另一个类对象时,则该类就依赖于另一个类。而关联关系是一种程度更深的依赖关系,如果一个类与另一个类存在关联关系,则它们之间必定存在依赖关系。但是,反之则不成立。如果一个类与另一个类存在关联关系,则该类对象包含其关联类对象的位置,这通常是由于该类中包含了其关联对象的类对象(数据成员)。当一个类与另一个类存在依赖关系,则该类以某种方式与另一个类的对象发生联系;但它并不要求另一个类对象作为其数据成员。例如,Purse类与Coin类存在依赖关系,但并不一定就和Coin类发生关联。对于一个Purse类对象,不必包含Coin类对象,只需在Purse类的合计金额计算方法中加上硬币的值,而不必在Purse类对象中存储一个Coin类对象。在前面的章节中,介绍了用UML来表示依赖关系,它是一个带开口箭头的虚线。至此,已经介绍了依赖、关联、继承等三种关系的UML表示。为了进一步区分和记忆这三种容易混淆的UML表示,表列出了这三种UML关系符号。 表3-1 UML类图中的属性和成员函数有时,用类图描述类的属性和成员函数(又称为方法)是很有用的。这里所说的属性是指从外部可见的对象特征。例如,name和price就是类Product的属性。一般来说,类属性对应类的数据成员。但是,类Time应该有seconds,minutes和hours这三个属性,但实际上该类中并没有将他们存储为相应的数据成员。相反,只在类中设置了一个从午夜到现在的总秒数、而在需要时计算出上面三个数值。在类图中,代表类的矩形框被分割成上中下三部分,分别填入该类的类名、属性和成员函数。类名在最上面,属性在中间,成员函数在最下面。有时,在类图中并不需要列出该类的所有属性和成员函数。这类类图可用于理解设计该类图的用意。另外,如果一个类的某一个属性是另一个类对象,从而使该类与其他类构成关联关系,则将其作为关联关系画出,而不必作为类的一个属性列出。例如,由于Vehicle类型对象包含Tire类型对象成员而表示成关联关系,不必在Vehicle类的属性中列出属性tires。在UML类图中,关联关系是最为复杂的关系,而且表示方法尚有待进一步标准化。在阅读其他相关书籍时,常常可以看到多种不同的表示关联关系的方法。在本书中使用的关联关系称为单向关联(directed association)关系。其含义是,可以通过一个类操作另一个类的对象,但反之则不行。例如,给定一个Vehicle类,则可以操作Tire类对象;反之,给定一个Tire类对象,却不能确定它属于哪一个Vehicle类对象。当然,如果在Tire类对象中设置一个指针,用于指向其所属的Vehicle类对象,则称这种关联关系为双向(bidirectional)关联。将类Tire和类Vehicle设计成这种双向关联也许有些牵强,但是要考虑类Employee和类Company之间的关系,则是一个很好的双向关联关系的范例:即一个公司需要维护一个员工列表,而每名员工对象也应维护一个指向对应公司的指针。在UML中,表示双向关联关系的符号是一条不带箭头的实线。但是,一些设计者将这种没有方向的关联关系视为“未定”关联,即目前还不能确定操作方向。有些设计人员习惯为关联关系加上修饰,包括关联的名称、角色和重数。关联的名称描述了该关联的特征;角色用来标注关联双方针对对方所扮演的角色;重数则表示关联一方对应对方的对象数目。一个Tire类对象与一个或0个Vehicle类对象相关联;而一个Vehicle类对象与4个或更多的Tire类对象相关联。聚集(aggregation)关系是一种程度更深的关联关系。如果关联的双方存在着“整体-部分”(whole-part)的关系,则称这种关联为聚集关系。例如,类Company和类Employee之间就是一种聚集关系。因为公司(作为一个整体)是由员工(部分)构成的,即公司由员工和雇工构成。但是,类BankAccount和类Person之间并不构成聚集关系,尽管可以从一个银行账户中获取一个客户,即账户所有者,但从概念上讲,二者之间并不构成“整体-部分”关系。组成(composition)关系是一种比聚集关系更强的关联关系,即聚集关系中的“部分”在某一个时间点上只属于一个“整体”。也就是说,如果对应的“整体”消亡了,那么相应的“部分”也随之不复存在。例如,一个轮胎在一定时间只属于某一车辆,它们构成组成关系;而一个员工则可以同时为两家公司工作,不能构成组成关系。事实上,关联、聚集和组成之间的区别很微妙,即使是有经验的设计者都很难区分。如果觉得区分它们是有帮助的,则可以按照其含义使用它们。但在此并不提倡花费精力对这几个概念进行严格的区分。2.4 实例:打印发票在本章中,建议采用如下5个开发过程:1.收集需求2.利用CRC卡片技术来找出类、类的职责及类之间的协作关系;3.利用UML类图来描述类关系;4.给出类及其成员函数;5.根据上述步骤实现程序。这5个步骤对于初学编程的人来说特别有效。在这个过程中并不需要学习大量的符号表示,也比较容易画出类图。设计阶段的成果马上就能应用于实现阶段。当然,如果实际遇到的项目很复杂,那么上述步骤就显得不够用了,此时读者需要学习更多的正规设计方法。例如,有许多技术可以用来描述对象场景。调用序列及程序的整体框架,等等,这些技术对于相对简单的系统也是很有帮助的。在本节中,将通过一个简单的例子完整地实现面向对象的设计方法。在此,所给出的方法可能有大材小用之嫌,但这对于让读者更好地领会这些步骤中所用到的方法是非常有用的。这对于读者在实际更为复杂的系统中应用这些方法也是很有帮助的。在进一步简介如何解决程序设计问题的方法时,应当注意,在此所给出的解决方法只是众多可供选择的开发方法中的一种。读者也可以尝试用其他方法来取代下面的步骤,并比较二者之间的效果。2.4.1 需求分析下面程序的任务是打印发票。一个发票列出了一定数量产品的费用。在此,不考虑实际发票中应包含的日期、税、发票和客户编号等复杂项。程序将打印票据地址、产品项列表、合计金额。其中项列表中每行包括产品的名称、单价、数量以及小计。例如: Sams Small Appliances 100 Main Street Anytown, CA 98765 Description Price Qty Total Toaster 29.95 3 89.95 Hair dryer 24.95 1 24.95 Car vacuum 19.99 2 39.98 AMOUNT DUE: $154.78同时为了简化问题,程序不提供相互用户接口。只需简单地在测试驱动中提供发票所需的项,然后打印即可。2.4.2 CRC卡片首先需要找出系统中存在哪些类。类对应问题描述中的名词。在本问题中,出现的名词有:发票(Invoice)地址(Address)产品项(Item)产品(Product)产品描述(Description)单价(Price)数量(Quantity)小计(Total)合计金额(Amount Due)(显然,Toaster这个名词不能列入其中,因为Toaster是一个具体的产品描述,它是一个数据值,不可能构成一个类。)考虑上述名词:产品名称和单价是Product类的属性;但数量不是Product类的一个属性,如何处理数量?可以设立一个Item类来记录产品和产品数量。小计和合计金额是由计算得到的,不能固定地存储于某一个地方,所以它们不构成类。在进行了这样的分析之后,现在有如下4个候选类:发票(Invoice)地址(Address)产品项(Item)产品(Product)上述每项各自都代表了一个单独的概念,从而可以为它们设计4个类。下面将分析各个类的职责。因为程序的目的是打印发票,可在相应类的CRC卡片上做如下记录:发票如何实现打印功能?打印包括票据地址、所有产品项和合计金额。发票要实现地址打印功能则需要借助Address类的帮助,所以在Address类在CRC卡片上做如下记录:类似地,打印产品项应该是类Item的职责。因此,类Invoice的成员函数print要调用类Address和类Item的成员函数print。按照CRC卡片的使用要求,应该将这种协作关系表现在卡片上。即,在类Invoice的协作者一栏中添加类Address和类Item:作为发票的一部分,类Invoice还需要计算合计金额。要得到该合计金额,需要提取每一个产品项的金额数据。那么如何获得产品项的小计金额呢?首先应查询相应产品的单价,再与产品的数量相乘即可得到该小计金额。这要求类Product具有提供产品价格的功能,同时该类又是产品项类item的一个协作者。最后,在发票中必须能够增加产品及其数量,并将其打印在结果中。因此,这也是类Invoice的一个职责。至此,已经有了一个CRC卡片集,并完成了CRC卡片中相应的内容。2.4.3 UML图从CRC卡片中的协作者一列,可以得到类之间的依赖关系,每个类依赖于与其有协作关系的类。在本例中,类Invoice依赖于类Address、类Item和类Product;而类Item依赖于类Product。接下来要判断这些依赖关系中哪些类又进一步构成关联关系。一个Invoice类对象是如何知道与其相关的地址、产品项以及产品对象的呢?首先,一个Invoice类对象必须保存一个地址以及相关的产品项,以便于打印发票。但是一个Invoice类对象在添加一个产品时并不需要保存产品类对象,因为产品作为一个产品项对象中的一部分已经存在,并由产品项对象来负责保护它。因此,类Invoice与类Address和类Item之间构成关联关系,但与类Product之间没有关联关系,即从一个Invoice类对象无法直接操作类Product对象。类Product对象存储在Item类对象中,而不是直接存储在类Invoice类对象中。从上面的分析中也可以看出,在类Item和类Product之间存在关联关系。在本例中不存在继承关系,图2.4显示了发票类之间的关系。ItemProductAddressInvoice图2.4 发票类之间关系2.4.4类及其方法的注释设计阶段的最后一步是对所发现的类及其相应类的职责文档化,即写出类及其成员函数的注释文档。对于类可以简单地给出注释。而对于类成员函数,则需要做进一步的工作。在CRC卡片中仅包含类的职责,即类成员函数的高层描述,因此,还需要进一步给出其参数和返回类型。下面是范例中发票类的注释文档: /* Describes an invoice for a set of purchased products. */ class Invoice public: /* Adds a charge for a product to this invoice. param aProduct the product that the customer ordered param quantity the quantity of the product */ void add(Product p, int qunatity); /* Prints the invoice. */ void print() const; ; /* Describes a quantity to an article to purchase and its price */ class Item public: /* Computes the total cost of this item return the total price */ double get_total_price() const; /* Prints this item */ void print() const; ; / etc.可以通过一个注释提取程序从上述注释文档中获得相应的格式化HTML文档。doxygen便是一个注释提取应用程序。可以参见与本书相应的web网站来了解更多的信息。对类进行文档化的工作可以带来一些好处。首先,可以在开发团对中共享这份文档;其次,文档格式遵循了C+类编写的形式,所以很容易进行编码工作;最重要的是注释文档为类中的关键成员函数提供了注释,而这项工作通常由程序员在实现阶段完成,但往往由于太忙而忽略了这项工作。2.4.5 实现最后,可以开始实现这些类了。上面的步骤已经得到成员函数名及其注释,现在需要参照UML图来为各个类添加数据成员。首先,从类Invoice开始,类Invoice与类Address和Item类关联,所以每个Invoice类应包含一个Address类对象和若干个Item类对象。为了存储多个Item类对象,可以使用一个向量,下面是类Invoice的数据成员: class Invoice private: Address billing_address; Vector items; ;从UML图中可以看出,Item类与Product类关联时,还需要存储相应产品的数量。因此,得到Item类的数据成员如下: class Item private: Product prod; int quantity; ;对于成员函数的视线就比较容易。例如,我们已经知道类Item中的成员函数get_total_price的功能,它通过产品单价和数量相乘来计算产品的小计金额。其实现如下: Double Item:getTotalPrice() return prod.get_price() * quantity; ;其他成员函数的实现也同样直观,在此就不详细讨论了。最后,还需要为每一个类提供构造函数。这样就实现了一个完整的程序。建议读者从头到尾完整地对照CRC卡片和UML类图了解类及其成员设计的方法。下面给出了该范例的完整程序:001: #include 002: #include 003: #include 004: 005: using namespace std;006: 007: /*008: Describes a product with a description and a price.009: */010: class Product011: 012: public: 013: Product();014: Product(string d, double p);015: /*016: Gets the product description.017: return the description018: */019: string get_description() const;020: 021: /*022: Gets the product price.023: return the unit price024: */025: double get_price() const;026: 027: private: 028: string description;029: double price;030: ;031: 032: Product:Product()033: 034: price = 0;035: 036: 037: Product:Product(string d, double p)038: 039: description = d;040: price = p;041: 042: 043: string Product:get_description() const044: 045: return description;046: 047: 048: double Product:get_price() const049: 050: return price;051: 052: 053: /*054: Describes a quantity of an article to purchase and its price.055: */056: class Item057: 058: public:059: Item();060: Item(Product p, int q);061: /*062: Computes the total cost of this item.063: return the total price064: */065: double get_total_price() const;066: 067: /*068: Prints this item.069: */070: void print() const;071: private:072: Product prod;073: int quantity;074: ;075: 076: 077: Item:Item()078: 079: quantity = 0;080: 081: 082: Item:Item(Product p, int q)083: 084: prod = p;085: quantity = q;086: 087: 088: double Item:get_total_price() const089: 090: return prod.get_price() * quantity;091: 092: 093: void Item:print() const094: 095: const int COLUMN_WIDTH = 30;096: string description = prod.get_description();097: 098: cout description;099: 100: / pad with spaces to fill column101: 102: int pad = COLUMN_WIDTH - description.length();103: for (int i = 1; i = pad; i+)104: cout ;105: 106: cout prod.get_price()107: quantity 108: get_total_price() n;109: 110: 111: /*112: Describes a mailing address.113: */114: class Address115: 116: public: 117: Address();118: Address(string n, string s,119: string c, string st, string z);120: /*121: Prints the address.122: */123: void print() const;124: private:125: string name;126: string street;127: string city;128: string state;129: string zip;130: ;131: 132: Address:Address() 133: 134: Address:Address(string n, string s,135: string c, string st, string z)136: 137: name = n;138: street = s;139: city = c;140: state = st;141: zip = z;142: 143: 144: void Address:print() const145: 146: cout name n street n147: city , state zip n; 148: 149: 150: /*151: Describes an invoice for a set of purchased products.152: */153: class Invoice154: 155: public:156: Invoice(Address a);157: /*158: Adds a charge for a product to this invoice.159: param aProduct the product that the customer ordered160: param quantity the quantity of the product161: */162: void add(Product p, int quantity);163: /*164: Prints the invoice.165: */166: void print() const;167: private:168: Address billing_address;169: vector items;170: ;171: 172: Invoice:Invoice(Address a)173: 174: billing_address = a;175: 176: 177: void Invoice:add(Product p, int q)178: 179: Item it(p, q);180: items.push_back(it);181: 182: 183: void Invoice:print() const184: 185: cout I N V O I C Enn;186: billing_address.print();187: cout 188: nnDescription Price Qty Totaln;189: for (int i = 0; i items.size(); i+)190: itemsi.print();191: 192: double amount_due = 0;193: for (int i = 0; i items.size(); i+)194: amount_due = amount_due + itemsi.get_total_price();195: 196: cout nAMOUNT DUE: $ amount_due;197: 198: 199: int main()200: 201: Address sams_address(Sams Small Appliances,202: 100 Main Street, Anytown, CA, 98765);203: 204: Invoice sams_invoice(sams_address);205: sams_invoice.add(Product(Toaster, 29.95), 3);206: sams_invoice.add(Product(Hair dryer, 24.95), 1);207: sams_invoice.add(Product(Car vacuum, 19.99), 2);208: 209: sams_invoice.print(); 210: return 0;211: 第三章 课程设计题目3.1 菜单选择趣味程序菜单是应用程序的界面,控制语句用来改变程序执行的顺序,是实现结构化程序设计的基础。本章的任务是设计一个比较实用的菜单,通过菜单选择不同的功能。本章的设计分为两步:首先设计一个含有多个菜单项的菜单演示程序,然后再为这些菜单配上相应的功能。3.1.1设计一个菜单程序首先设计一个菜单程序,其设计要求如下:1菜单内容程序运行后,给出4个菜单项的内容和输入提示。1解一元二次方程2出圈游戏之一3出圈游戏之二4退出程序选择1-4:2.设计要求使用数字1-4来选择菜单项,其他输入则不起作用。下面是测试运行的例子:1解一元二次方程2出圈游戏之一3出圈游戏之二4退出程序选择1-4:1解一元二次方程1解一元二次方程2出圈游戏之一3出圈游戏之二4退出程序选择1-4:2出圈游戏之一1解一元二次方程2出圈游戏之一3出圈游戏之二4退出程序选择1-4:3出圈游戏之二1解一元二次方程2出圈游戏之一3出圈游戏之二4退出程序选择1-4:5输入错误,重选1-4:a输入错误,重选1-4:0输入错误,重选1-4:4再见!菜单程序的设计思想:首先编写一个菜单驱动程序,输入1-4之间的任意一个数字,即可进入相应选择项。从程序测试结果可知,当选择相应选择项时,其输出信息分别为:解一元二次方程、出圈游戏之一、出圈游戏之二和退出程序。1.实现循环和功能选择假设输入选择用变量cn存储,它作为menu_select()函数的返回值提供给switch语句。使用for循环实现重复选择,并在函数handle_menue()中实现。/*菜单处理函数*/void handle_menu(void) for(; ;) switch(menu_select() case 1: coutt解一元二次方程n; break; case 2: coutt出圈游戏之一n; break; case 3: coutt出圈游戏之二n; break; case 4: coutt再见!n; return; 实际使用时,只有选择4,程序才能结束运行,这就要使用循环控制。这里使用for循环语句实现菜单的循环选择,为了结束程序的运行,使用“return”语句即可,也可以使用“exit(0);”语句。2得到cn的合理值如前所述,应该设计一个函数用来输出提示信息和处理输入,这个函数应该返回一个数值cn,以便供给switch语句使用。假设函数名为menu_select,设计的参考程序如下:/* *菜单选择函数 */int menu_select()char s2;int cn; coutt1.解一元二次方程n;coutt2.出圈游戏之一n;coutt3.出圈游戏之一n;coutt4.退出程序n;coutt1选择1-4:; for(; ;) gets(s); cn=atoi(s); if(cn4) printf(nt输入错误,重选1-4); else break; return cn;语句“cn=atoi(s)”是为了使输入的字符串转变为数字,以便使switch中的c

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论