C应用与开发案例教程下实用实用教案

上传人:人*** 文档编号:589969827 上传时间:2024-09-12 格式:PPT 页数:238 大小:3.06MB
返回 下载 相关 举报
C应用与开发案例教程下实用实用教案_第1页
第1页 / 共238页
C应用与开发案例教程下实用实用教案_第2页
第2页 / 共238页
C应用与开发案例教程下实用实用教案_第3页
第3页 / 共238页
C应用与开发案例教程下实用实用教案_第4页
第4页 / 共238页
C应用与开发案例教程下实用实用教案_第5页
第5页 / 共238页
点击查看更多>>
资源描述

《C应用与开发案例教程下实用实用教案》由会员分享,可在线阅读,更多相关《C应用与开发案例教程下实用实用教案(238页珍藏版)》请在金锄头文库上搜索。

1、 有时候,你可能面临并非所有的事情都是完美的事实,偶而,甚至有时候,你可能面临并非所有的事情都是完美的事实,偶而,甚至最好的计划也会失败。不管怎么说,是人就会犯错。为了防范运行最好的计划也会失败。不管怎么说,是人就会犯错。为了防范运行时的错误,时的错误,C+环境给予程序员试运行的机会,如果运行失败,它环境给予程序员试运行的机会,如果运行失败,它提供了一个预防机制。异常处理就是这种机制。提供了一个预防机制。异常处理就是这种机制。 异常是发生在运行期间的诸如零作分母、数组的溢出以及异常是发生在运行期间的诸如零作分母、数组的溢出以及(yj)空闲空闲空间的耗尽这样的错误事件。假如这些错误没有被捕获,则

2、程序会空间的耗尽这样的错误事件。假如这些错误没有被捕获,则程序会突然地停止执行,而没有提供任何指示给使用者,告诉他发生了什突然地停止执行,而没有提供任何指示给使用者,告诉他发生了什么。处理这样的异常,不同的程序员有不同的风格,这导致了代码么。处理这样的异常,不同的程序员有不同的风格,这导致了代码的多样性。这种多样性随着用户自定义类的使用而增长,因为每一的多样性。这种多样性随着用户自定义类的使用而增长,因为每一种这样的类都带有其潜在的特定类的异常结构。种这样的类都带有其潜在的特定类的异常结构。 当一个异常发生时,当一个异常发生时,C+以下列方式做出反应:以下列方式做出反应:1. 发生异常的函数可

3、以产生一个系统定义的消息;发生异常的函数可以产生一个系统定义的消息;8.1概述(i sh)第1页/共237页第一页,共238页。8.1概述(i sh)2.函数可以完全终止执行;3.函数可以跳过中间层继续执行其他的部分。 C+语言提供内建的对于意外情况处理的支持,这就是异常(ychng)处理。通过C+语言的异常(ychng)处理,你的程序能够使意外的事件与高层次的执行上下文进行通信,它能够从这种异常(ychng)事件中恢复过来。 C+处理异常(ychng)的机制是灵活的,因此它能处理任何类型的异常(ychng)。在C+中,产生一个异常(ychng)被称为引发一个异常(ychng)。 第2页/共2

4、37页第二页,共238页。 8.2 何时使用异常(ychng)处理 在在程程序序运运行行期期间间调调用用一一个个函函数数会会产产生生三三种种结结果果。它它们们(t men)是:是:1.正常执行正常执行 在执行过程中,函数正常地执行并返回到调用的程序中在执行过程中,函数正常地执行并返回到调用的程序中.一一些函数把结果代码返回给调用者。返回的代码表明执行的结些函数把结果代码返回给调用者。返回的代码表明执行的结果。果。2.错误执行错误执行 当当调调用用者者在在变变量量传传递递过过程程中中犯犯错错或或调调用用的的函函数数超超出出上上下下文文的的范围时,会导致一个错误,这会终止程序的执行。范围时,会导致

5、一个错误,这会终止程序的执行。3.异常执行异常执行 在在执执行行过过程程中中出出现现异异常常的的一一种种典典型型情情况况是是内内存存不不足足;另另一一种种典典型型情情况况是是一一个个I/O操操作作的的异异常常。例例如如,当当打打开开一一个个存存在在的的文文件件时时,存存储储媒媒介介的的设设备备驱驱动动器器可可能能会会出出错错。这这种种情情况况不不能能通通过过简简单单的的查查找找文文件件是是否否存存在在来来处处理理,引引发发并并捕捕捉捉异异常常是是最最佳佳的的处处理方法。理方法。 第3页/共237页第三页,共238页。 8.2 何时使用(shyng)异常处理 在开发需要照顾意外情形的应用程序时,

6、异常处理是必需的。发生在程序执行时的意外情形有:运行内存不够、资源分配错误(cuw)、不能找到/打开文件等。假如这些错误(cuw)没有被捕获,那么,在没有给予用户任何有关发生什么情况的提示下,程序将被中断。异常可以被定义为在程序执行中意外情况的出现和正常指令流的中断。 第4页/共237页第四页,共238页。8.3 异常(ychng)处理的基本语法 异常处理是C+的一个特征,它提供了处理运行期间异常的标准工具。一种一致性语法可以应用于这种目的,它能够被程序员很好的协调校正。一些常见的异常有分母为零、数组溢出(y ch)以及NULL指针(即一个包含0值的指针)的引用。 在C+语言中用try、thr

7、ow和catch语句实现异常处理,在程序的某个函数中发现异常时使用throw表达式抛出这个异常,这个异常被抛给该函数的调用者,调用者用catch捕获该异常并进行相应的处理。当预测到某段程序将可能出现问题时,则该段程序放在try语句之后,使该段程序得以有机会抛出异常。第5页/共237页第五页,共238页。8.3.1 异常(ychng)处理的语法 异常处理的语法如下: throw 表达式语法: throw 表达式 try 表达式语法: try 受保护的程序段语句 catch(异常类型) 异常处理语句; catch(异常类型) 异常处理语句; 其中,catch括号中异常类型与throw抛出的异常类型

8、相匹配,当某个异常发生后,catch语句将逐个被检查(jinch),直到某个异常类型与throw抛出的异常类型相匹配,然后执行catch后面的第6页/共237页第六页,共238页。8.3.1 异常(ychng)处理的语法异常处理程序。若catch括号中是省略号(),则该catch可以捕获所有的异常类型,所以这样的语句一般放在所有catch语句的最后一个,否则其他catch语句就没有机会捕捉相应的错误类型了。 当某个异常被捕捉并被相应的程序段处理后,系统将继续执行捕捉函数(hnsh)的其余部分。产生异常的函数(hnsh)和直到捕捉到异常的函数(hnsh)之间的所有调用链上的函数(hnsh)将从栈

9、中删除。如果一个异常没有被任何函数(hnsh)捕捉到,则运行函数(hnsh)terminate将被调用,该函数(hnsh)的默认功能是调用abort函数(hnsh)终止程序的运行。 一个异常处理的过程可以如下表示: void fun( ) int i; double f; 第7页/共237页第七页,共238页。8.3.1 异常(ychng)处理的语法 char c; /程序的其他部分 try /预期可能出现问题的地方,保护(boh)起来 throw i; /如果出现问题1,抛出一个整数(只是假设) throw f;/如果出现问题2,抛出一个双精度数(只是假设) throw c; /如果出现问题

10、3,抛出一个字符(只是假设) catch(int ii) /相应处理 catch(double ff) 第8页/共237页第八页,共238页。8.3.1 异常(ychng)处理的语法/相应处理(chl)catch(charcc)/相应处理(chl)/程序其他部分【例8-1】#includevoidmain()try第9页/共237页第九页,共238页。8.3.1 异常(ychng)处理的语法intage;coutage;if(age100|age1)throwInvalidage!;coutAfterthethrowstatementendl;catch(char*msg)coutError!

11、msgendl;coutAfterthecatchhandlerendl;程序(chngx)的输出结果为:第10页/共237页第十页,共238页。8.3.1 异常(ychng)处理的语法 Enter the age:: 46After the throw statementAfter the catch handleEnter the age:: 116Error! Invalid age!After the catch handle第11页/共237页第十一页,共238页。8.3.2 异常(ychng)的类型 异常有两种类型:同步异常和异步异常。1.同步异常 发生在运行期间,并且能够使用th

12、row表达式产生。仅有这种类型的异常能够使用C+中的异常处理器处理。控制不必返回异常引发处。2.异步异常 因为一个键盘(jinpn)或鼠标的中断而产生。C+程序不能使用try和catch语句直接处理这种类型的异常。一次不得不产生一个自动调用与键盘(jinpn)或鼠标中断相关的例程。第12页/共237页第十二页,共238页。8.4 Try、catch和throw语句(yj) 在在C+语语言言中中执执行行异异常常处处理理的的是是Try 、catch和和 throw语语句句。通通过过C+的异常处理,你的程序能够探测到异常事件并从中恢复过来。的异常处理,你的程序能够探测到异常事件并从中恢复过来。 一个

13、包含一个包含try 、catch和和 throw语句的程序的执行过程如下:语句的程序的执行过程如下:1.控制通过正常的连续执行到达控制通过正常的连续执行到达try语句,在语句,在try模块内的语句被保护执行;模块内的语句被保护执行;2.如如果果在在被被保保护护的的执执行行期期间间没没有有异异常常被被引引发发,try模模块块之之后后的的catch语语句句不不会会执执行行。在在引引发发异异常常的的try模模块块后后面面的的最最后后(zuhu)的的catch语语句句之之后后继续执行;继续执行;3.如如果果在在被被保保护护的的执执行行过过程程中中有有一一个个异异常常被被引引发发,程程序序搜搜寻寻一一个

14、个能能够够处处理被引发类型的异常的理被引发类型的异常的catch语句;语句;4.如如果果没没有有找找到到一一个个类类型型匹匹配配的的处处理理器器,那那么么调调用用预预定定义义的的运运行行期期间间的的函数函数terminate();第13页/共237页第十三页,共238页。8.4 Try、catch和throw语句(yj)5.如果找到了类型匹配的catch处理器,初始化它的参数并执行(zhxng)catch处理器中的指令。 如果程序终止,释放堆栈中的所有值。一个基类的处理器也能够处理它的子类的异常。如果在catch表达式中遇到了一个“”,它将处理所有的异常而不管它们的数据类型。 【例8-2】#i

15、nclude void main( ) coutbefore the throw statementendl; try throw 25.6f ; /引发一个浮点值第14页/共237页第十四页,共238页。8.4 Try、catch和throw语句(yj)catch(char*str)coutCaughtastringendl;catch(inti)coutCaughtanIntegerendl;catch(.)coutUnknowndatatypeendl;coutAfterthethrowstatementendl;第15页/共237页第十五页,共238页。8.4 Try、catch和th

16、row语句(yj)在上面的代码中,一个浮点值从try模块中被引发。然而,没有为接受一个浮点值而特意设计的catch处理器。因此程序的输出是:beforethethrowstatementUnkonwndatatypeAfterthethrowstatement新的运算符new引发了一个bad_alloc异常。新的头文件声明了bad_alloc类,它从异常类继承而来。What()函数在异常类中被声明。【例8-3】检查内存分配(fnpi)操作。#include#includevoidmain()第16页/共237页第十六页,共238页。8.4 Try、catch和throw语句(yj)char*b

17、uff;trybuff=newchar1000000000;/声明在新的头文件中的新的运算符bad_alloc引发了一个类的对象catch(std:bad_alloc&obj)cout:obj.what()endl;该程序(chngx)是关于一个try模块和与它相联系的catch处理器的第17页/共237页第十七页,共238页。8.4 Try、catch和throw语句(yj)一个实例。该实例检查一个内存分配操作的错误,如果内存分配操作成功,则catch处理器不执行。在一个内存分配错误的情况下,程序的输出是:Exceptionraised:bad_alloc如果在一个try模块执行过程中没有引

18、发异常,在try模块后的catch语句不被执行。程序将在引发异常的try模块之后的最后一条catch语句继续执行。控制器只能够通过(tnggu)一个引发的异常来输入一个catch处理器,而不能通过(tnggu)一个switch语句中的一个case标号来进行。在前面提到的实例中,在try模块后仅存在一个catch处理器。然而,并不是一直这样的。也会存在其他的catch处理器。如果throw语句准备仅引发内建的数据类型(在这种情况下使用字符型),catch处理器的数量不能超过语言支持第18页/共237页第十八页,共238页。8.4 Try、catch和throw语句(yj)的内建数据类型的数量。为

19、了解决(jiju)这个问题,一个用户定义类型的不同的对象能够引发给处理器。如下例:【例8-4】#include#includeclassMyExceptionpublic:charcause21;MyException(char*in=0)strcpy(cause,in);第19页/共237页第十九页,共238页。8.4 Try、catch和throw语句(yj)voidprintMessage()coutendlError:causeendl;classAclassintage;public:voidget()coutage;if(age100)第20页/共237页第二十页,共238页。8.

20、4 Try、catch和throw语句(yj)MyExceptione(Problemwithage);throwe;elsecoutCORRECTAGE!endl;voidmain()Aclassobject;第21页/共237页第二十一页,共238页。8.4 Try、catch和throw语句(yj)tryobject.get();catch(MyException&x)x.printMessage();【例8-5】异常的抛出和捕捉(bzhu)在同一函数中。#include#includeclassPerson第22页/共237页第二十二页,共238页。8.4 Try、catch和thro

21、w语句(yj)protected:charName20;/姓名intOld;/年龄unsignedlongID;/身份证号charSex;/性别(xngbi)public:Person(char*theName,inttheOld,unsignedlongtheId,chartheSex);/类Person的构造函数;Person:Person(char*theName,inttheOld,unsignedlongtheId,chartheSex)if(Name=)/有效性检查第23页/共237页第二十三页,共238页。8.4 Try、catch和throw语句(yj)throwInvalid

22、Personsname!;if(Old200)/有效性检查(jinch)throwOld;if(Sex!=M)&(Sex!=m)&(Sex!=F)&(Sex!=f)/有效性检查(jinch)throwSex;voidfun()trycoutfunline1endl;Personp1(zhang,43,1234566L,M);/类Person的对象p1coutfunline2endl;Personp2(,-1,22222222L,F);/类Person的对象p2coutfunline3endl;第24页/共237页第二十四页,共238页。8.4 Try、catch和throw语句(yj)Pers

23、onp3(,-1,33333333L,M);/类Person的对象(duxing)p3coutfunline4endl;Personp4(,-1,44444444L,F);/类Person的对象(duxing)p4catch(char)/捕捉错误并进行处理coutInvalidSex!endl;catch(int)/捕捉错误并进行处理coutInvalidOld!endl;catch(char*Msg)/捕捉错误并进行处理第25页/共237页第二十五页,共238页。8.4 Try、catch和throw语句(yj)coutInvalidName!endl;voidmain()coutbefor

24、efun.endl;fun();coutendfun.endl;coutinthemainfunction!endl;在本程序中,异常的抛出和捕捉都在函数fun中,在实际应用中,异常的引发和处理一般在不同函数中,这样低层函数可以专注于具体问题(wnt),上层调用函数可以在恰当的位置设计对不同类型第26页/共237页第二十六页,共238页。8.4 Try、catch和throw语句(yj)的异常(ychng)进行各种处理而不考虑低层函数是如何产生这个异常(ychng)的。【例8-6】对【例8-5】稍加改动,使异常(ychng)的抛出和捕捉在不同函数中进行。【例8-6】异常(ychng)的抛出和捕

25、捉在不同函数中。#include#includeclassPersonprotected:charName20;/姓名intOld;/年龄unsignedlongID;/身份证号charSex;/性别第27页/共237页第二十七页,共238页。8.4 Try、catch和throw语句(yj)public:Person(char*theName,inttheOld,unsignedlongtheId,chartheSex);/类Person的构造函数;Person:Person(char*theName,inttheOld,unsignedlongtheId,chartheSex)if(Nam

26、e=)/有效性检查(jinch)throwInvalidPersonsname!;if(Old200)/有效性检查(jinch)throwOld;if(Sex!=M)&(Sex!=m)&(Sex!=F)&(Sex!=f)/有效性检查(jinch)第28页/共237页第二十八页,共238页。8.4 Try、catch和throw语句(yj)throwSex;voidfun()coutfunline1endl;Personp1(zhang,43,1234566L,M);/类Person的对象(duxing)p1coutfunline2endl;Personp2(,-1,22222222L,F);/

27、类Person的对象(duxing)p2coutfunline3endl;Personp3(,-1,33333333L,M);/类Person的对象(duxing)p3coutfunline4endl;Personp4(,-1,44444444L,F);/类Person的对象(duxing)p4第29页/共237页第二十九页,共238页。8.4 Try、catch和throw语句(yj)voidmain()trycout”beforefun”endl;fun();cout”endfun”endl;catch(char)/捕捉(bzhu)错误并进行处理coutInvalidSex!endl;ca

28、tch(int)/捕捉(bzhu)错误并进行处理第30页/共237页第三十页,共238页。8.4 Try、catch和throw语句(yj)coutInvalidOld!endl;catch(char*Msg)/捕捉错误并进行处理coutInvalidName!endl;coutendl;coutinthemainfunction!endl;下面这个例子演示了如何(rh)用异常处理纠正程序运行期错误。【例8-7】纠正如下程序运行期错误。#include#includeclassString第31页/共237页第三十一页,共238页。8.4 Try、catch和throw语句(yj)privat

29、e:char*str;public:String()str=0;String(char*inString)str=newcharstrlen(inString)+1;strcpy(str,inString);voidreplace(charsearch,charrepl)第32页/共237页第三十二页,共238页。8.4 Try、catch和throw语句(yj)intcounter;for(counter=0;strcounter!=0;counter+)if(strcounter=search)strcounter=repl;voiddisplay()coutstr;第33页/共237页第

30、三十三页,共238页。8.4 Try、catch和throw语句(yj);voidmain()StringstrObject;/该对象不包含任何东西strObject.replace(+,);strObject.display();上面的代码产生下面的运行期错误:Segmentationfault(coredumped)分析:要想纠正如上程序运行期错误,首先要找到出现异常的原因,然后采用异常处理机制去处理异常。因此,下面分两步进行介绍。1标识异常的原因根据(gnj)分析知道,在main()函数中,String类的一个空对象被第34页/共237页第三十四页,共238页。8.4 Try、catch

31、和throw语句(yj)创建。replace()函数将遍历字符串直到空字符(0)出现(chxin),但如果字符串为空,那么操作失败。2标识异常处理的机制采用try、throw、catch语句进行处理。修改上面程序得如下程序:#include#includeclassStringprivate:char*str;intcheck()if(str=NULL)第35页/共237页第三十五页,共238页。8.4 Try、catch和throw语句(yj)return0;elsereturn1;public:String()str=0;String(char*inString)str=newcharst

32、rlen(inString)+1;strcpy(str,inString);第36页/共237页第三十六页,共238页。8.4 Try、catch和throw语句(yj)voidreplace(charsearch,charrepl)if(check()=0)throwNULLpointerexception;intcounter;for(counter=0;strcounter!=0;counter+)if(strcounter=search)strcounter=repl;第37页/共237页第三十七页,共238页。8.4 Try、catch和throw语句(yj)voiddisplay(

33、)coutstr;voidmain()StringstrObject;/对象不能包含任何的trytrystrObject.replace(+,);/引起(ynq)replace函数异常strObject.display();第38页/共237页第三十八页,共238页。8.4 Try、catch和throw语句(yj)catch(char*message)coutException:messageendl;程序的输出结果(jigu)如下:Exception:NULLpointerexception第39页/共237页第三十九页,共238页。8.5 标准(biozhn)C+库中的异常类标准C+库中

34、包含9个异常类,它们可以分为运行时异常和逻辑异常:length_error/运行时异常,长度(chngd)异常domain_error/运行时异常,域异常out_of_range_error/运行时异常,越界异常invalid_argument/运行时异常,参数异常range_error/逻辑异常,范围异常overflow_error/逻辑异常,溢出(上)异常underflow_error/逻辑异常,溢出(下)异常标准C+库中的这些异常类并没有全部被显式使用,因为C+标准库中很少发生异常,但是这些标准C+库中的异常类可以为编程人员,特别是自己类库的开发者提供一个指导。下面程序简单说明C+标准异

35、常类的使用。【例8-8】演示标准异常类的使用。第40页/共237页第四十页,共238页。8.5 标准(biozhn)C+库中的异常类#include#includeusingnamespacestd;voidmain()tryexceptiontheError;/声明一个C+标准异常类的对象throw(theError);/抛出该异常类的对象catch(constexception&theError)/捕捉C+标准异常类的对象couttheError.what()endl;/用what()成员(chngyun)函数显示出错原因第41页/共237页第四十一页,共238页。8.5 标准(biozh

36、n)C+库中的异常类trylogic_errortheLogicError(LogicError!);/声明一个C+标准异常类logic_error的对象throw(theLogicError);/抛出(poch)该异常类的对象catch(constexception&theError)/捕捉C+标准异常类的对象couttheError.what()endl;/用what()成员函数显示出错原因第42页/共237页第四十二页,共238页。8.6 程序(chngx)实例【例8-9】设计一个异常Exception抽象类,在此基础上派生一个OutOfMemory类响应内存不足,派生一个RangeEr

37、ror类响应输入的数不在指定范围(fnwi)内,实现并测试这两个类。程序如下:/EG8_8.CPP#includeclassExceptionpublic:Exception()virtualException()第43页/共237页第四十三页,共238页。8.6 程序(chngx)实例virtualvoidPrintError()=0;classOutOfMemory:publicExceptionpublic:OutOfMemory()OutOfMemory()第44页/共237页第四十四页,共238页。8.6 程序(chngx)实例virtualvoidPrintError();void

38、OutOfMemory:PrintError()coutOutofMemory!endl;classRangError:publicExceptionpublic:RangError(unsignedlongnumber)BadNum=number;第45页/共237页第四十五页,共238页。8.6 程序(chngx)实例RangError()virtualvoidPrintError();virtualunsignedlongGetNumber()returnBadNum;virtualvoidSetNumber(unsignedlongnumber)BadNum=number;第46页/共

39、237页第四十六页,共238页。8.6 程序(chngx)实例private:unsignedlongBadNum;voidRangError:PrintError()coutNumberOutofrange.YouusedGetNumber()!n;voidfn1();unsignedint*fn2();voidfn3(unsignedint*);voidmain()try第47页/共237页第四十七页,共238页。8.6 程序(chngx)实例fn1();catch(Exception&theException)theException.PrintError();unsignedint*f

40、n2()unsignedint*n=newunsignedint;if(n=0)throwOutOfMemory();第48页/共237页第四十八页,共238页。8.6 程序(chngx)实例returnn;voidfn1()unsignedint*p=fn2();fn3(p);coutThenumberis:*pendl;deletep;voidfn3(unsignedint*p)longNumber;coutNumber;第49页/共237页第四十九页,共238页。8.6 程序(chngx)实例if(Number1000|Number0)throwRangError(Number);*p=

41、Number;程序的输出结果为:Enteraninteger(0-1000):78Thenumberis:78Enteraninteger(0-1000):1500Numberoutofrange.Youused1500!下面给出一个接近实用的例子,假设开发一个人员管理系统,并且声明了人这个基本类Person,它包含姓名、性别、年龄(ninlng)、证件号码等数据,我们可以事先估计一下可能出现的异常情况,如用户忘记输入姓名,年龄(ninlng)不在正常范围内、证件号码不符合要求、性别不符合要求等等,这要求有一个可以报告这类错误第50页/共237页第五十页,共238页。8.6 程序(chngx)

42、实例的类InvalidPerson。同时,用户输入数据进行(jnxng)处理完成后需要存盘,下一次可以从磁盘中调出这些数据,这个过程中可能的异常是输入输出文件打开出错、输入数据被破坏等,要求有一个可以报告错误的类IOError。看下面的例子并体会异常处理的用法:【例8-10】人员管理系统中常用的异常处理。/EG8_9.H#ifndefEG8_9.H#defineEG8_9.Husingnamespacestd;classPerson;classError/声明出错类第51页/共237页第五十一页,共238页。8.6 程序(chngx)实例public:Error(constchar*theWh

43、ere,constchar*theWhy):why(theWhy),where(theWhere)virtualvoiddisplay(ostream&out)const;/显示出错内容protected:conststringwhy;/错误(cuw)原因conststringwhere;/错误(cuw)地点;#endif/EG8_9.CPP#include#include第52页/共237页第五十二页,共238页。8.6 程序(chngx)实例#include#EG8_9.HclassInvalidPerson:publicError/从类Error派生类InvalidPersonpubli

44、c:InvalidPerson(constPerson*thePerson,constchar*theWhy):Error(Person:InvalidCheck,theWhy),pPerson(thePerson)/InvalidPerson类构造函数virtualvoiddisplay(ostream&out)const;/派生类中的出错(chcu)内容显示protected:constPerson*pPerson;/派生类中新增数据成员;classIOError:publicError/从类Error派生类IOError第53页/共237页第五十三页,共238页。8.6 程序(chngx

45、)实例public:IOError(constchar*theWhere,constchar*theWhy,constchar*theFileName):/IOError构造函数Error(theWhere,theWhy),FileName(theFileName)virtualvoiddisplay(ostream&out)const;/派生类中的出错内容(nirng)显示protected:StringFileName;/文件名;classPersonpublic:第54页/共237页第五十四页,共238页。8.6 程序(chngx)实例Person(conststring&theName

46、,inttheOld,unsignedlongtheId,chartheSex);/Person类构造函数voiddisplay(ostream&out)const;/类Person的显示函数voidoutput(ostream&out)const;/类Person的输出函数staticPerson*input(istream&in);/类Person的输出函数voidInvalidCheck()const;/类Person的有效性检查(jinch)protected:stringName;/姓名intOld;/年龄unsignedlongId;/身份证号码charSex;/性别;ostrea

47、m&operator(ostream&out,constPerson&thePerson);/重载运算符第55页/共237页第五十五页,共238页。8.6 程序(chngx)实例voidError:display(ostream&out)const/Error:display函数的实现out!ErrorRepurt-where:whyendl;/显示错误(cuw)原因和地点voidInvalidPerson:display(ostream&out)const/InvalidPerson:display函数的实现Error:display(out);/调用基类的显示函数outPersonobje

48、ct=(*pPerson)endl;/显示本类的新增特性voidIOError:display(ostream&out)const/IOError:display函数的实现第56页/共237页第五十六页,共238页。8.6 程序(chngx)实例Error:display(out);/调用基类的显示函数(hnsh)outFile=FileNameendl;/显示本类的新增特性Person:Person(conststring&theName,inttheOld,unsignedlongtheId,chartheSex):Name(theName),Sex(theSex),Old(theOld)

49、,ID(theId)/Person类构造函数(hnsh)voidPerson:InvalidCheck()const/Person:InvalidCheck函数(hnsh)的实现if(Name.length()=0)/如果姓名为空,人员信息无效throwInvalidPerson(this,Invalidpersonsname);第57页/共237页第五十七页,共238页。8.6 程序(chngx)实例/抛出InvalidPersonif(Old200)/如果人员年龄(ninlng)不在0-200之间,该人员信息无效throwInvalidPerson(this,InvalidpersonsO

50、ld);/抛出InvalidPersonif(Id0L)/如果身份证号码小于0,该人员信息无效throwInvalidPerson(this,InvalidpersonsId);/抛出InvalidPersonif(Sex!=M)&(Sex!=m)(Sex!=F)&(Sex!=f)/如果性别不是字符“M、m、F、f”,该人员信息无效第58页/共237页第五十八页,共238页。8.6 程序(chngx)实例throwInvalidPerson(this,InvalidpersonsSex);/抛出InvalidPersonvoidPerson:display(ostream&out)const/

51、Person:display函数(hnsh)的实现outName-Old-ID-Sex;/输出人员信息if(out.fail()/如果输出文件出错,则抛出IOErrorthrowIOError(Person:display),Outputfile,displayerror);第59页/共237页第五十九页,共238页。8.6 程序(chngx)实例voidPerson:output(ostream&out)const/Person:output函数的实现InvalidCheck();/首先(shuxin)进行有效性检查,该函数在对象无效时可以抛出InvalidPersonoutNameOldI

52、DSexn;/输出人员信息if(out.fail()/如果输出文件出错,则抛出IOErrorthrowIOError(Person:output),Outputfile,outputerror);第60页/共237页第六十页,共238页。8.6 程序(chngx)实例voidPerson:input(istream&in)const/Person:input函数的实现(shxin)Person*TempPerson=0;/用于保存从in流中输入的对象stringTempPersonName;/保存从in流中输入的对象数据intTempPersonOld;unsignedlongTempPers

53、onID;charTempPersonSex;tryif(in.get()!=);/将到为止(wizh)的流in中内容保存到TempPersonName中inTempPersonOldTempPersonIDTempPersonSex;/从流in中依次输入到各个变量中in.get();/略过本行中剩余部分,到达下一行TempPerson=newPerson(TempPersonName,TempPersonOld,TempPersonID,TempPersonSex);第62页/共237页第六十二页,共238页。8.6 程序(chngx)实例/用于输入数据构造(guzo)临时对象TempPer

54、son-InvalidCheck();/有效性检查catch(Error&theError)/捕捉错误进行初步处理coutErrorininput:endl;theError.display(cout);/显示错误deleteTempPerson;/删除该临时对象TempPerson=(Person*)0;throwError(Person:input,inputerror);/抛出Error类的对象returnTempPerson;第63页/共237页第六十三页,共238页。8.6 程序(chngx)实例/EG8_9.CPP#include#include#include#EG8_9.Hos

55、tream&operator(ostream&out,constPerson&thePerson);voidOutputPersons(char*theFileName);voidInputPersons(char*theFileName);voidmain()tryOutputPerson(d:C+tempperson.txt);/将类Person的若干个对象(duxing)输出到文件中,可放于自己指定的目录下第64页/共237页第六十四页,共238页。8.6 程序(chngx)实例InputPerson(d:C+tempperson.txt);/从文件中输入类Person对象并显示catc

56、h(Error&theError)/捕捉错误(cuw)类型,由于InvalidPerson和类IOError都是类Error的/子类,所以在此处也可以捕捉到这两种错误(cuw)类型coutFatalerrorinprogram:endl;theError.display(cout);/错误(cuw)信息显示ostream&operator(ostream&out,constPerson&thePerson);/重载运算符的实现第65页/共237页第六十五页,共238页。8.6 程序(chngx)实例thePerson.dispaly(out);returnout;voidOutputPerso

57、ns(char*theFileName)/将人员信息输出(shch)到文件的函数ofstreamout(theFileName);if(out.fail()/如果文件打开出错,抛出IOError类型的对象throwIOError(OutputPersons,cantopenoutputfile,theFileName);Personwang(wang,25,750308206L,M);/类Person的对象wangwang.output(out);/输出(shch),可能抛出类IOError的对象,以下同第66页/共237页第六十六页,共238页。8.6 程序(chngx)实例Personzh

58、ang(zhang,35,700308205L,F);zhang.output(out);Personyang(yang,26,800808107L,F);yang.output(out);Personzhao(zhao,25,40600211004L,M);zhao.output(out);voidInputPersons(char*theFileName)/从文件中获得类Person对象并进行(jnxng)显示的函数inti=0;ifstreamin;in.open(theFileName,ios:in);if(in.fail()/如果文件打开出错,抛出IOError类型的对象第67页/共

59、237页第六十七页,共238页。8.6 程序(chngx)实例throwIOError(InputPersons,cantopeninputfile,theFileName);Person*TempPerson;while(!in.eof()/从文件中输入对象(duxing)并显示该对象(duxing)if(TempPerson=Person:input(in)coutPersonNo.+i:(*TempPerson)b? a:b; char max(char a, char b) return ab? a:b; 第72页/共237页第七十二页,共238页。9.2.1 函数(hnsh)模板和模

60、板函数(hnsh)doublemax(doublea,doubleb)returnab?a:b;floatmax(floata,floatb)returnab?a:b;可以看出,这样的四个函数的函数体都是相同的,其功能几乎完全一样,只是返回值或者参数不同。对不同的数据类型,相同的代码必须重写多次,而执行的是相同的功能。这是对时间和精力的浪费,为避免这种浪费,C+为我们提供了一个方便的语法规则:函数模板。利用函数模板,可以建立一个具有(jyu)通用功能的函数,支持不同的函数参数和返回值。第73页/共237页第七十三页,共238页。 9.2.1 函数(hnsh)模板和模板函数(hnsh)函数模板的

61、语法形式如下:template/函数定义其中(qzhng)T代表在函数模板中要使用的通用类型,在该函数的调用过程中,T被具体化。例如对上面的重载函数,我们只要声明一个函数模板就可以了:templateTmax(Ta,Tb)returnab?a:b第74页/共237页第七十四页,共238页。 9.2.1 函数(hnsh)模板和模板函数(hnsh)关键字template表明正在(zhngzi)声明一个模板,数据类型参数T由模板参数给出。该模板的含义为:无论模板参数T实例为int、float、char或任意其他类型,包括类类型时,函数max()就为实例化了的参数求最大值。这样定义的max()函数在进

62、行求最大值的操作时,首先必须将模板参数T实例化,从这个意义上说,这里定义的max()函数并不是一个完全的函数,我们称它为函数模板。因此,函数模板代表了一类函数,但是它不是一个完全的函数,必须将其模板参数T实例化后,才能完成具体函数的功能。将T实例化的参数常常称为模板实参。用模板实例化的函数称为模板函数,例如:voidfun()inti;Mclassx,y;第75页/共237页第七十五页,共238页。 9.2.1 函数(hnsh)模板和模板函数(hnsh)intj=max(i,0);/模板实参为整数类型Mclassm=max(x,y);/模板实参为Mclass类型这里生成了两个模板函数max(i

63、,0)和max(x,y)。max(i,0)用模板实参int将类型参数T实例化,而max(x,y)将T实例化为Mclass类类型。一个函数模板提供一类函数的抽象,它以任意类型T为参数。由一个函数模板产生的函数称为模板函数,它的函数模板的具体实例。就象类与对象一样(yyng),函数模板将具有相同程序正文的一类函数抽象出来,可以适应任意类型T。函数模板对某一特定类型的实例就是模板函数。函数模板代表了一类函数,模板函数表示某一具体的函数。图9-1给出了函数模板和模板函数的关系。第76页/共237页第七十六页,共238页。 9.2.1 函数(hnsh)模板和模板函数(hnsh)实例化实例化实例化函数模板

64、max(Ta,Tb)模板函数max(inta,intb)模板函数max(doublea,doubleb)模板函数max(Xa,Xb)图9-1第77页/共237页第七十七页,共238页。 9.2.1 函数(hnsh)模板和模板函数(hnsh)【例9-1】编写函数模板(mbn)max()使得能找出任意类型的两个数中的最大数。#includetemplatetypemax(typea,typeb)returnab?a:b;voidmain()coutmax(A,a):max(A,a)endl;coutmax(30,40):max(30,40)endl;coutmax(45.67f,12.32f):m

65、ax(45.67f,12.32f)endl;第78页/共237页第七十八页,共238页。 9.2.1 函数(hnsh)模板和模板函数(hnsh)程序的输出结果为:max(A,a):amax(30,40):40max(45.67f,12.32f):45.67【例9-2】编写能完成计算(jsun)任意类型数的平方的函数模板。#includetemplatetypesquare(typea)typeb;b=a*a;returnb;voidmain()第79页/共237页第七十九页,共238页。 9.2.1 函数(hnsh)模板和模板函数(hnsh) coutsquare(23.45f) :squar

66、e(23.45f) endl;coutsquare(43) :square(43) endl;程序的输出(shch)结果为:square(23.45f) :549.903square(43) :1849第80页/共237页第八十页,共238页。 9.2.2 重载(zhn zi)函数模板 在有些特殊情况(qngkung)下需要对函数模板进行重载,C+允许函数模板被一个或多个同名的非模板函数重载。考虑下面的例子:【例9-3】templateT max(T a, T b) return (ab)?a:b;void f(int i, char c) max(i,i); max(c,c); max(i,

67、c); /错误:max(Int,char)无法匹配 第81页/共237页第八十一页,共238页。 9.2.2 重载(zhn zi)函数模板max(c,i);/错误这里出现的错误在于:模板类型并不知道int和char之间能进行隐式类型转换。但是,这样(zhyng)的转换在C+中是很普通的。为了解决这个问题,C+允许函数模板可以参与重载。用户可以用一个非模板函数重载一个同名的函数模板,例如,可以这样(zhyng)定义:templateTmax(Ta,Tb)return(ab)?a:b;intmax(int,int);/显式地声明函数max(int,int),不是模板函数第82页/共237页第八十二

68、页,共238页。 9.2.2 重载(zhn zi)函数模板voidf(inti,charc)max(i,i);/调用函数max(int,int)max(c,c);/调用模板max(char,char)max(i,c);/调用函数max(Int,int)max(c,i);/调用函数max(int,int)这里,非模板函数max(int,int)重载(zhnzi)了上述的函数模板max(Ta,Tb),当出现调用语句max(i,c);和max(c,i);时,它执行的是重载(zhnzi)的非模板函数版本max(int,int)。还可以定义如下函数:第83页/共237页第八十三页,共238页。 9.2.

69、2 重载(zhn zi)函数模板charmax(char*x,char*y)return(strcmp(x,y)0)?x:y;非模板函数max(ichar*x,char*y)也重载了上述的函数模板,当出现调用语句(yj)max(a,b);时,它执行的是这个重载的非模板函数的版本,其中a和b都是字符串变量。在C+中,函数模板与同名的非模板函数的重载方法遵循下列约定:寻找一个参数完全匹配的函数,如果找到了,就调用它;寻找一个函数模板,将其实例化产生一个匹配的模板函数,如果找到了,就调用它;试一试低一级的对函数的重载方法,如通过类型转换可第84页/共237页第八十四页,共238页。 9.2.2 重载

70、函数(hnsh)模板产生(chnshng)参数匹配等,如果找到了,就调用它。如果1、2、3均未找到匹配的函数,那么这个调用是一个错误。如果在第一步有多于一个的选择,那么这个调用是意义不明确的,也会产生(chnshng)一个错误。以上重载模板函数的规则,可能会引起许多不必要的函数定义的产生(chnshng),但一个好的实现应该是充分利用这个功能的简单性来抑制不合逻辑的回答。第85页/共237页第八十五页,共238页。9.3 类模板(mbn)和模板(mbn)类一个类模板(也称类属类或类生成类)允许用户(yngh)为类定义一种模式。考虑如下向量类(一维数组)的例子。不管整形向量还是任何其他类型的向量

71、,在所有类型上进行的基本操作是相同的(如插入、删除、检索等)。由于将每个元素的类型当做一个类的类型参数来对待,系统可快速生成类型安全的类定义。类模板定义语法:templateclassclass_namepublic:type1var1;第86页/共237页第八十六页,共238页。9.3 类模板(mbn)和模板(mbn)类;【例9-4】#includetemplateclassVectorT*data;intsize;public:Vector(int);Vector()deletedata;第87页/共237页第八十七页,共238页。9.3 类模板(mbn)和模板(mbn)类T&operat

72、or(inti)returndatai;其中,关键字template表示正在声明一个模板,其类属参数由模板参数给出。这时,类Vector声明了一个数组类,当T被实例化为int、char、float、string或complex甚至任意类型(lixng)Myclass时,Vector被实例化为整形数组、字符数组、浮点数数组、字符串数组或复数数组甚至任意类型(lixng)Myclass的数组。从这个意义上说,Vector是一个不完全的类。这时Vector被称为类模板,Vector是该类模板的名字。将模板参数实例化的参数常称为模板实参,例如:int、char等。用第88页/共237页第八十八页,共2

73、38页。9.3 类模板(mbn)和模板(mbn)类模板实参生成的类称为模板类。例如,Vector是一个模板类。因此(ync),类外成员函数定义的语法为:templateVector:Vectordata=newTn;size=n;模板外的成员函数定义都由template开始,表示是一个类模板的成员函数,其类模板的类名为Vector。下面的main程序说明了如何使用类模板:voidmain()第89页/共237页第八十九页,共238页。9.3 类模板(mbn)和模板(mbn)类Vectorx(5);/产生一个整形向量for(inti=0;i5;+i)xi=i;for(inti=0;i5;+i)c

74、outxi;coutn;程序的输出(shch)结果为:01234语句Vectorx(5)由模板类Vector声明一个对象x,它是具有5个元素的整形向量。由于在Vector中重载了运算符“”,所以与一般数组的使用方法没有什么区别。Vector还可以这样用:Vectorv1(10);第90页/共237页第九十页,共238页。9.3 类模板(mbn)和模板(mbn)类Vectorv2(20);TypedefVectorcvec;cvecv3(30);v13=7;v23=complex(7,8);这里Vector和Vector都是模板类。它说明(shumng)了一个整形向量v110,两个复数类型的向量

75、v220和v330。图9-2给出了类模板与模板类的关系。第91页/共237页第九十一页,共238页。9.3 类模板(mbn)和模板(mbn)类实例化实例化实例化类模板Vector模板类Vector模板类Vector模板类Vector图9-2第92页/共237页第九十二页,共238页。9.3 类模板(mbn)和模板(mbn)类尽管上述例子都只使用了一个模板参数,实际上允许使用多个参数。模板参数可以是类型,也可以是非类型的数据。综上所述,一个类模板说明了单个类怎样建立,就好像类型声明说明了单个对象是怎样建立的一样。当用户需要编写几乎相等(xingdng)的代码时,可以使用模板。可以看出,定义一个模

76、板是一件简单的事。不管是函数模板还是类模板,必须明确规定其模板参数。因此,模板说明语句template中的关键字template表示正在声明一个模板,模板参数规定了类属参数。模板参数可以由一个或多个由逗号隔开的参数组成,参数可以是类型,如classT(class后跟一个标志符组成),也可以是非类型参数(即一般的参数)。第93页/共237页第九十三页,共238页。9.3 类模板(mbn)和模板(mbn)类从语法上讲,要说明一个函数模板,只需将模板说明语句放在一个函数说明的前面,并将相应的参数改为模板参数即可。要说明一个类模板,除了将模板说明语句冠以类说明之前以及设置类中相应的模板参数之外,还要将

77、类模板的名字与模板参数(用尖括号括起来的参数串)一起使用。例如:Vector代表类模板名Vector代表模板类名(limn)假设需要对同一数据类型定义两个不同的类,下面代码可以实现:【例9-5】#includetemplateclassw第94页/共237页第九十四页,共238页。9.3 类模板(mbn)和模板(mbn)类public:Ta;w(Tq)a=z+q;couta=aendl;voidmain()wone(100);w*twoptr=&one;/没有(miyu)创建对象wthree=200;第95页/共237页第九十五页,共238页。9.3 类模板(mbn)和模板(mbn)类wfou

78、r=100.45;程序的输出结果为:a=110a=230a=140.45注意:在该实例中,给出了一个基本(jbn)数据类型作为模板参数。在模板类中,这是允许的。在main()函数的第一和第三行创建的对象属于同一个类。第四行用了一个float型的参数。使用这种表达式,基本(jbn)数据类型值可以用在对象声明中。第96页/共237页第九十六页,共238页。9.4 程序(chngx)实例用模板进行程序设计对许多人是陌生的,【例9-6】从一个简单问题入手,介绍(jisho)了怎样将系统的各个部分按概念特性的不同而划分成块(pieces)。当研究这些块时,应该考虑如何将这里所用的技术也应用到更大的程序中

79、。【例9-6】将一个数组的元素进行累加。intsum(int*p,intn)intresult=0;for(inti=0;in;i+)result+=pi;returnresult;可以使用这样的函数:第97页/共237页第九十七页,共238页。7.2.4 用友元函数(hnsh)重载运算符#includeintsum(int*p,intn)intresult=0;for(inti=0;in;i+)result+=pi;returnresult;voidmain()intx10;for(inti=0;i10;i+)xi=i;第98页/共237页第九十八页,共238页。7.2.4 用友元函数(hn

80、sh)重载运算符coutsum(x,10)endl;这个例子输出45,它是小于10的非负整数的和。sum函数知道三件事:它将一组东西加在一起;正在相加的东西是整数;正在相加的整数按一种特殊的方法存储。看一看怎样划分该程序,以便上述每个特性都能用模板的方法来表达。1。分离出迭代操作(cozu)(iteration)首先假定要把被相加的元素存于数组中,为了遍历数组,即在这个数组上进行迭代操作(cozu),要遵循标准的C+技术:使迭代成为一个类。显然,迭代所需的操作(cozu)为:第99页/共237页第九十九页,共238页。7.2.4 用友元函数(hnsh)重载运算符1.一个构造函数,它建立(jin

81、l)要被处理的数据;2.请求数组中下一个元素的方法;3.区分迭代什么时候结束的方法;4.赋值运算符函数、拷贝构造函数和析构函数。迭代对象常常用于C+类库,它们常常被称为迭代算子(iterators)。有许多种迭代算子,这里仅仅给出它们最基本的轮廓。将至今所知道的关于迭代算子的操作写出来:classInt_iteratorpublic:Int_iterator(int*,int);intvalid()const;intnext();第100页/共237页第一百页,共238页。7.2.4 用友元函数(hnsh)重载运算符Int_iterator(constInt_iterator&);Int_it

82、erator&operator=(constInt_iterator&);Int_iterator;这个类称为Int_iterator而不是iterator,因为它确实表达了一个(y)整数序列的迭代,后面将推广到任意类型。构造函数有两个参数变元:数组的第一个(y)元素的地址和元素的数目。valid成员函数的功能是:如果数组中还有元素,返回非0值。当数组中还有元素时,next成员函数取下一个(y)元素,这里假定当数组中没有元素时将不调用next。在进一步细化迭代算子之前,重写sum函数:intsum(Int_iteratorir)intresult=0;第101页/共237页第一百零一页,共23

83、8页。7.2.4 用友元函数(hnsh)重载运算符while(ir.valid()result+=ir.next();returnresult;使用(shyng)这个sum函数的main程序可能会是这样的:#includevoidmain()intx10;for(inti=0;i10;i+)xi=i;coutsum(Int_iterator(x,10)0;intnext()-len;return*data+;private:int*data;intlen;第105页/共237页第一百零五页,共238页。7.2.4 用友元函数(hnsh)重载运算符2.在任意类型上进行迭代 名字Int_itera

84、tor非常受限制,它只能描述整数数组的迭代,使用它已失去了抽象的机会(j hu)。 将上述的Int_iterator类抽象为一般的Iterator类模板。template class Interatorpublic:Interator(T * p,int c):data(p),len(c) int valid()constreturn len0;第106页/共237页第一百零六页,共238页。7.2.4 用友元函数(hnsh)重载运算符Tnext()-len;return*data+;private:T*data;intlen;Int_iterator模板(mbn)类可说明为:typedefI

85、teratorInt_iterator;这样,可以用Iterator替换Int_iterator而得到sum函数和main程序:第107页/共237页第一百零七页,共238页。7.2.4 用友元函数(hnsh)重载运算符intsum(Iteratorir)intresult=0;while(ir.valid()result+=ir.next();returnresult;voidmain()intx10;for(inti=0;i10;i+)xi=i;coutsum(Iterator(x,10)endl;第108页/共237页第一百零八页,共238页。7.2.4 用友元函数(hnsh)重载运算符

86、既然能在任意类型的数组上进行迭代,它也能够求出任意类型的值的和。将sum函数(hnsh)写为函数(hnsh)模板能容易做到:templateTsum(Iteratorir)Tresult=0;while(ir.valid()result+=ir.next();returnresult;现在可以计算任意类对象数组的和,但要求这些类对象满足以下条件:可以将0转换为这个类的对象;第109页/共237页第一百零九页,共238页。7.2.4 用友元函数(hnsh)重载运算符运算符“+=”在这个类中有定义;对象具有类似值(value_like)的语义,使得sum函数能返回它们作为值。所有数值类型(lixn

87、g)都满足这些要求。当然,其他类要这样做也是容易定义的。现在已经解决了三件事情中的两件,第三件事呢?3.抽象出存储技术正在寻找不同种类的迭代算子来反映不同的数据结构。至今仅有一个迭代算子,它将元素存储在数组中,但是,如果元素存储在链表中呢?存储在文件中呢?抽象这些是可能的吗?解决这个问题的“标准”方法是将Interator类转换成一个抽象基类,它能描述大量不同迭代类中的任意一个:第110页/共237页第一百一十页,共238页。7.2.4 用友元函数(hnsh)重载运算符templateclassInteratorpublic:virtualintvalid()const=0;virtualTn

88、ext()=0;virtualInterator();然后,上面(shngmin)所说的迭代算子Array_iterator是Interator的一种:templateclassArray_iterator:publicInterator第111页/共237页第一百一十一页,共238页。7.2.4 用友元函数(hnsh)重载运算符public:Array_iterator(T*p,intc):data(p),len(c)intvalid()constreturnlen0;Tnext()-len;return*data+;第112页/共237页第一百一十二页,共238页。7.2.4 用友元函数(

89、hnsh)重载运算符private:T*data;intlen;同时,将sum函数的参数变元定义为Interator的引用(ynyng),以便允许动态匹配:templateTsum(Iterator*ir)Tresult=0;while(ir-valid()result+=ir-next();returnresult;第113页/共237页第一百一十三页,共238页。7.2.4 用友元函数(hnsh)重载运算符这时,要累加一个数组元素(yuns)的和,仅仅需要创建一个适当的Array_iterator来描述它,并将其传给sum函数:#includevoidmain()intx10;for(in

90、ti=0;i10;i+)xi=i;Array_iteratorit(x,10);Interator*I_it;I_it=⁢coutsum(I_it)endl;第114页/共237页第一百一十四页,共238页。7.2.4 用友元函数(hnsh)重载运算符这里的差别是显式地创建了一个Array_iterator对象it,用它来表达在数组x进行的迭代。也可以这样表达:coutsum(Array_iterator(x,10)endl;由于sum函数的变元使用了动态(dngti)匹配,sum函数中的每个内循环都需要虚函数调用,这样开销太大了,特别对于像这样的简单类型来说,这个开销难以接收。显然,可

91、以采用另一种方法来解决问题,sum函数用两个类型参数变元:迭代算子的类型以及要被相加的对象的类型。不幸的是,这又有麻烦了,如果将sum函数用下述方式定义为函数模板:templateObjsum(Iterit).第115页/共237页第一百一十五页,共238页。7.2.5 几种(j zhn)特殊操作符的重载我们发现所定义(dngy)函数的返回类型与其变元类型无关。也就是说,sum(x)的返回类型Obj与x的类型无关。这是不合法的。因此,只有再次采用C+的标准技术,使sum成为一个类。换句话说,不是定义(dngy)sum为一个函数,而是定义(dngy)一个sum类,它的目的是将迭代算子和返回给它的

92、值相加在一起。这表达起来很容易:templateclasssumpublic:sum(Ititer):ir(iter)第116页/共237页第一百一十六页,共238页。7.2.5 几种特殊(tsh)操作符的重载operatorS();private:Itir;类提供了一个(y)构造函数将It的对象转换为sum类型,一个(y)类型转换函数operatorS()将sum对象转换为S的类型,这样求和就容易多了:templatesum:operatorS()Iti=ir;Sresult=0;while(i.valid()result+=i.next();第117页/共237页第一百一十七页,共238页

93、。7.2.5 几种(j zhn)特殊操作符的重载returnresult;可见,operatorS()与前面定义(dngy)的sum函数没有太多的差别,因此,用起来也差不多。至此,sum类模板表达的概念是非常高级的,它有两个模板参数:被相加的对象的类型(classS)和迭代算子的类型(classIt)。模板参数classS表示sum能将任意类型S的对象进行相加,模板参数It表示sum能用类属迭代算子It对任意数据结构进行迭代提取(或称遍历操作)。当创建一个sum对象时,首先通过构造函数将模板实参(一个迭代类对象)与形参iter相结合,对私有成员ir初始化,这意味着迭代算子的实例化。其次,隐含地

94、使用类型转换函数operatorS(),对初始化了的ir进行迭代求和,并将结果值转换为S类型。整个求和过程是在创建一个sum对象时自动进行的。第118页/共237页第一百一十八页,共238页。7.2.5 几种(j zhn)特殊操作符的重载下面是sum类的使用方法:#includevoidmain()intx10;for(inti=0;i10;i+)xi=i;coutsumint,Array_iterator(Array_iterator(x,10)endl;如果从里到外读这个复杂的表达式,比较容易理解。首先,Array_iterator(x,10)创建一个Array_iterator对象(迭代

95、类对象),它描述了对数组x进行迭代;其次(qc),构造一个sumint,Array_iterator的对象,它将那个数组的元素第119页/共237页第一百一十九页,共238页。7.2.5 几种(j zhn)特殊操作符的重载求和,结果值为int类型;最后sumint,Array_iterator的结果打印出来。这种风格需要一些多余的代码,但换来了许多额外的灵活性,如果改成(ichn)sumdouble,Array_iterator,则调用双精度浮点数相加。当然,还可以缩写成普通的格式:templateTsum(T*p,intn)returnsumT,Array_iterator(Array_it

96、erator(p,n);这样使用起来就容易多了:#includevoidmain()第120页/共237页第一百二十页,共238页。7.2.5 几种特殊(tsh)操作符的重载intx10;for(inti=0;i10;i+)xi=i;coutsum(x,10)endl;以一个简单的sum函数为例,说明怎样将它分离成三部分,每部分都是独立的代码,得到了很大的灵活性。随着模板技术的广泛采用,这种技术将改进系统的设计方法,特别(tbi)是类库的设计。接下来让我们用类模板实现通用链表类。在这里,将链表类结点的数据类型参数化,构成了一个通用模板,可以用来生成结点数据为任意类型的链表。【例9-7】用模板实

97、现通用链表类/EXAMPLE9-7.H第121页/共237页第一百二十一页,共238页。7.2.5 几种(j zhn)特殊操作符的重载#ifndef EXAMPLE9-7-H#define EXAMPLE9-7-H#include #includetemplateclass ListNode /结点(ji din)类public:ListNode() /结点(ji din)类构造函数 ListNode(const T& nItem,ListNode *ptrNext=NULL) ;/结点(ji din)类带参数的构造函数 第122页/共237页第一百二十二页,共238页。7.2.5 几种特殊(

98、tsh)操作符的重载T&ShowDate()/返回本结点(jidin)数据的引用returnDate;voidInsertAfter(ListNode*ptr);/插入新结点(jidin)作为本结点(jidin)的后续结点(jidin)ListNOde*DeleteAfter(void);/删除本结点(jidin)的后续结点(jidin)ListNOde*NextListNode()const;/获得本结点(jidin)的后续结点(jidin)的指针voidSetNext(ListNode*ptr)/设置本结点(jidin)的后续结点(jidin)的指针ptrNext=ptr;第123页/共2

99、37页第一百二十三页,共238页。7.2.5 几种(j zhn)特殊操作符的重载private:TDate;/本结点的数据ListNode*ptrNext;/指向本结点的后续结点的指针;templateclassLinkedList/链表类的声明及其实现public:LinkedList(void);LindedList(constLinkedList&list);/拷贝构造函数LinkedList(void)/析构函数,释放链表占用(zhnyn)的资源DeleteAll();第124页/共237页第一百二十四页,共238页。7.2.5 几种(j zhn)特殊操作符的重载LinkedList&

100、operator=(constLinkedList&list);/“=”号运算符的重载voidNext();/指向链表的下一结点intEndOfList()const/判断链表当前位置是否是表尾return(!ptrCurr);intCurrPosition()const/获得(hud)当前位置指针在链表中的位置return(nPosition);voidInsertFront(constT&nItem);/将数据为nItem的结点插入到链表头第125页/共237页第一百二十五页,共238页。7.2.5 几种(j zhn)特殊操作符的重载voidInsertTail(constT&nItem)

101、;/将数据为nItem的结点(jidin)插入到链表尾voidInsertAt(constT&nItem);/将数据为nItem的结点(jidin)插入到链表的当前位置voidInsertAfter(constT&nItem);/将数据为nItem的结点(jidin)插入到链表的当前位置之后voidInsertOrder(TnItem);/将数据为nItem的结点(jidin)插入到排序链表中,并构成新的排序链表intDeleteHead();/删除链表头结点(jidin)voidDeleteCurr();/删除链表当前结点(jidin)voidDelete(Tkey);/删除链表中数据为ke

102、y的结点(jidin)voidDeleteAll();/删除链表中所有结点(jidin)T&GetDate();/得到链表中的当前结点(jidin)数据第126页/共237页第一百二十六页,共238页。7.2.5 几种特殊(tsh)操作符的重载voidDisplayList();/显示链表中所有结点的数据intFind(T&nItem);/在链表中找到数据为nItem的结点intListLength()const/求链表的长度returnnListLength;intListEmpty()const/判断链表是否为空returnnListLength;voidReset(intnPos=0);

103、/重新设置(shzh)链表的当前指针的位置private:ListNOde*ptrFront,/链表的头结点指针第127页/共237页第一百二十七页,共238页。7.2.5 几种(j zhn)特殊操作符的重载*ptrTail,/链表的尾结点指针*ptrPrev,/链表的当前(dngqin)结点的前一个结点指针*ptrCurr,/链表的当前(dngqin)结点指针intnListLength;/链表的长度intnPosition;/链表的当前(dngqin)结点指针的位置ListNode*GetListNode(constT&nItem,ListNode*ptrNext=NULL);/获得链表的

104、下一个结点指针voidFreeListNode(ListNode*ptr)/释放结点资源deleteptr;voidCopyList(constLinkedList&list);/逐项拷贝链表;第128页/共237页第一百二十八页,共238页。7.2.5 几种(j zhn)特殊操作符的重载#endif/EG9_7B.H#ifndefEG9_7B_H#defineEG9_7B_H#include#includeEG9_7.H/结点类带参数构造函数的实现(shxin)templateListNode:ListNode(constT&nItem,ListNode*ptrNext:Date(nItem

105、),ptrNext(ptrNext)/返回指向后续结点的指针第129页/共237页第一百二十九页,共238页。7.2.5 几种(j zhn)特殊操作符的重载templateListNode*ListNode:NextListNode()constreturnptrNext;templatevoidListNode:InsertAfter(ListNode*ptr)ptr-ptrNext=ptrNext;/将ptr的ptrNext指针指向本结点(jidin)的后续结点(jidin)ptrNext=ptr;/本结点(jidin)的ptrNext指针指向ptrtemplateListNOde*Lis

106、tNode:DeleteAfter()第130页/共237页第一百三十页,共238页。7.2.5 几种(j zhn)特殊操作符的重载ListNode*ptrTemp=ptrNext;if(ptrNext=NULL)/处理本结点为尾结点时的情况returnNULL;ptrNext=ptrTemp-ptrNext;/一般情况returnptrTemp;/链表类构造函数,4个私有指针设置为空,链表的初始长度设置为0。/初始当前(dngqin)结点位置为-1templateLinkedList:LinkedList(void):ptrFront(NULL),ptrTail(NULL),ptrPrev(

107、NULL),ptrCurr(NULL),nListLength(),nPosition(-1)第131页/共237页第一百三十一页,共238页。/重载(zhnzi)“=”号运算符templateLinkedList&LinkedList:operator=(constLinkedList&list)if(this!=&list)DeleteAll();CopyList(list);return*this;/拷贝构造函数9.4 程序(chngx)实例第132页/共237页第一百三十二页,共238页。7.2.5 几种特殊(tsh)操作符的重载templateLinkedList:LinkedLis

108、t(constLinkedLIst&list)CopyList(list);/重新设置当前指针的位置templatevoidLinkedList:Reset(intnPos)intnStartPos;if(!ptrFront)/如果当前指针为空,链表为空直接(zhji)返回return;第133页/共237页第一百三十三页,共238页。7.2.5 几种(j zhn)特殊操作符的重载if(nPos=nListLength|nPos0)/位置越界检查(jinch)cerrInvalidPosition!NextListNode();ptrPrev=ptrFront;nStartPos=1;for(

109、nPosition=nStartPos;nPosition!=nPos;nPosition+)ptrPrev=ptrCurr;ptrCurr=ptrCurr-NextListNode();/当前指针指向当前结点(jidin)的后续结点(jidin)templatevoidLinkedList:Next()第135页/共237页第一百三十五页,共238页。7.2.5 几种特殊(tsh)操作符的重载if(ptrCurr)ptrPrev=ptrCurr;ptrCurr=ptrCurr-NextListNode();nPosition+;/将数据(shj)为nItem的结点插入到链表头template

110、voidLinkedList:InsertFront(constT&nItem)ListNode*newListNode=GetListNode(nItem);/获得一个封装有该数据(shj)的结点第136页/共237页第一百三十六页,共238页。7.2.5 几种(j zhn)特殊操作符的重载newListNode-SetNext(ptrFront);ptrFront=newListNode;nListLength+;/将数据为nItem的结点插入到链表尾templatevoidLinkedList:InsertTail(constT&nItem)ListNode*newListNode;if

111、(ptrCurr=NULL)InsertFront(nItem);/若链表为空,使之成为(chngwi)头结点(也是尾结点)else/一般情况第137页/共237页第一百三十七页,共238页。7.2.5 几种特殊(tsh)操作符的重载while(ptrCurr-NextListNode()/寻找尾结点prtCutt=ptrCurr-NextListNode();newListNode=GetListNode(nItem);ptrCurr-InsertAfter(newListNode);/将数据为nItem的结点插入到链表的当前(dngqin)位置之前templatevoidLinkedLis

112、t:InsertAt(constT&nItem)ListNode*newListNode;if(!ptrPrev)/插入到头结点newListNode=GetListNode(nItem,ptrFront);第138页/共237页第一百三十八页,共238页。7.2.5 几种特殊(tsh)操作符的重载newListNode-SetNext(ptrFront);ptrFront=newListNode;nListLength+;else/一般(ybn)情况newListNode=GetListNode(nItem);ptrPrev-InsertAfter(newListNode);if(ptrPr

113、ev=ptrTail)ptrTail=newListNode;nPosition=nListLength;第139页/共237页第一百三十九页,共238页。7.2.5 几种(j zhn)特殊操作符的重载ptrCurr=newListNode;/将数据(shj)为nItem的结点插入到链表当前结点之后templatevoidLinkedList:InsertAfter(constT&nItem)ListNode*newListNode;if(!ptrCurr)/处理空链表的情况newListNode=GetListNode(nItem);ptrCurr=newListNode;ptrFront=

114、ptrCurr;第140页/共237页第一百四十页,共238页。7.2.5 几种(j zhn)特殊操作符的重载else/一般(ybn)情况newListNode=GetListNode(nItem);ptrCurr-InsertAfter(newListNode);if(ptrPrev=ptrTail)ptrTail=newListNode;nPosition=nListLength;ptrCurr=newListNode;nListLength+;第141页/共237页第一百四十一页,共238页。7.3 类特有(t yu)的操作符new和delete/删除链表中的当前结点templatevo

115、idLinkedList:DeleteCurr()ListNode*ptr; if(!ptrCurr)/处理(chl)空链表的情况cerrThisListisempty!NextListNode();ptr=ptrPrev-DeleteAfter();if(ptr=ptrTail)ptrTail=ptrPrev;nPosition-;ptrCurr=ptr-NextListNode();FreeListNode(ptr);nListLength-;/删除链表中所有(suyu)结点并释放资源第143页/共237页第一百四十三页,共238页。4.8 程序(chngx)实例templatevoidL

116、inkedList:DeleteAll()ListNode*ptrCurrPos,*ptrNextPos;ptrCurrPos=ptrFront;while(ptrCurrPos)ptrNextPos=ptrCurrPos-NextListNode();FreeListNode(ptrCurrPos);ptrCurrPos=ptrNextPos;ptrFront=NULL;ptrTail=NULL;第144页/共237页第一百四十四页,共238页。4.8 程序(chngx)实例ptrPrev=NULL;ptrCurr=NULL;nListLength=0;nPosition=-1;/删除(sh

117、nch)链表的头结点templatevoidLinkedList:DeleteHead()ListNode*ptr=ptrFront;if(ptrFront)ptrFront=ptrFront-NextListNode();deleteptr;第145页/共237页第一百四十五页,共238页。4.8 程序(chngx)实例nListLength-;return1;else/删除链表为空的情况coutTheListisempty!endl;return0;/获得链表中当前结点(jidin)的数据templateT&LinkedList:GetDate()if(nListLength=0|!ptr

118、Curr)/空链表的处理第146页/共237页第一百四十六页,共238页。4.8 程序(chngx)实例cerrInvalid!ShowDate();/逐项拷贝链表中的各个结点(jidin)templatevoidLinkedList:CopyList(constLinkedList&list)ListNode*ptr=list.ptrFront;ptrCurr=NULL;while(ptr)/遍历list并创建新表第147页/共237页第一百四十七页,共238页。4.8 程序(chngx)实例InsertAfter(ptr-ShowDate();ptr=ptr-NextListNode();

119、if(nPosition=-1)/list为空return;ptrPrew=NULL;ptrCurr=ptrFront; for(intnPos=0;nPos!=list.CurrPosition();nPos+)/将新链表的各个数据(shj)成员设置与原链表相同ptrPrev=ptrCurr;ptrCurr=ptrCurr-NextListNode();第148页/共237页第一百四十八页,共238页。4.8 程序(chngx)实例nPosition=nPos;nListLength=list.ListLength();/获得下一个(y)新结点,返回新结点地址templateListNode

120、*LinkedList:GetListNode(constT&nItem,ListNode*preNext)ListNode*newListNode;newListNode=newListNode(nItem,preNext);if(!newListNode)cerrMemoryallocationfailure!endl;exit(1);第149页/共237页第一百四十九页,共238页。4.8 程序(chngx)实例returnnewListNode;/输出链表中的各个结点数据(shj)templatevoidLinkedList:DisplayList()ptrCurr=ptrFront;

121、while(ptrCurr)/遍历链表coutShowDate()NextListNode();/在链表中查找数据(shj)第150页/共237页第一百五十页,共238页。4.8 程序(chngx)实例templateintLinkedList:find(T&nItem)ptrCurr=ptrFront;ptrPrev=NULL;while(ptrCurr)if(ptrCurr-ShowDate()=nItem)return1;ptrPrev=ptrCurr;ptrCurr=ptrCurr-NextListNode();return0;第151页/共237页第一百五十一页,共238页。4.8

122、程序(chngx)实例/删除链表中满足条件的结点templatevoidLinkedList:Delete(Tkey)ptrCurr=ptrFront;ptrPrev=NULL;if(!ptrCurr)return;while(ptrCurr&ptrCurr-ShowDate()!=key)/查找(chzho)相应结点ptrPrev=ptrCurr;ptrCurr=ptrCurr-NextListNode();nPosition+;第152页/共237页第一百五十二页,共238页。7.3.1 数组操作符new和deleteif(ptrCurr)/如果找到该结点(jidin),删除它if(!pt

123、rPrev)ptrFront=ptrFront-NextListNode();elseptrPrev-DeleteAfter();deleteptrCurr;/在排序链表中插入新结点(jidin)构成新的排序链表templatevoidLinkedList:InsertOrder(TnItem)第153页/共237页第一百五十三页,共238页。4.8 程序(chngx)实例ListNode*newListNode,*next,/用于遍历链表*prev;/next指向结点的前一个结点的指针ptrPrev=NULL;ptrCurr=ptrFront;prev=ptrCurr;next=ptrCur

124、r-NextListNode();while(prev-ShowDate()=next-ShowDate()&(next)/判断原链表的排序方式(fngsh),升序或者降序prev=next;next=next-NextListNode();第154页/共237页第一百五十四页,共238页。4.8 程序(chngx)实例if(!next)InsertFront(nItem);elseif(prev-ShowDate()next-ShowDate()/降序排列时while(ptrCurr)/寻找插入(chr)位置if(nItem=ptrCurr-ShowDAte()break;ptrPrev=p

125、trCurr;ptrCurr=ptrCurr-NextListNode();if(!ptrPrev)InsertFront(nItem);else第155页/共237页第一百五十五页,共238页。4.8 程序(chngx)实例newListNode=GetListNode(nItem);ptrPrev-InsertAfter(newlistNode);else/升序排列(pili)时while(ptrCurr)if(nItemShowDate()break;ptrPrev=ptrCurr;ptrCurr=ptrCurr-NextListNode();第156页/共237页第一百五十六页,共23

126、8页。4.8 程序(chngx)实例if(!ptrPrev)InsertFront(nItem);elsenewListNode=GetListNode(nItem);ptrPrev-InsertAfter(newListNode);#endif在应用类模板过程中,在类外实现(shxin)成员函数时要注意不要漏写template。同时,所有涉及类模板的地方都要用。第157页/共237页第一百五十七页,共238页。第第10章章 流库流库第158页/共237页第一百五十八页,共238页。在自然界中,流是气体或液体运动的一种状态,C+借用它表示数据的传输工作。流是C+为输入输出提供的一组类,都放在流

127、库中。流总是与某一设备相联系(例如键盘、屏幕或硬盘等),通过使用流库中定义的方法,就可以完成对这些设备的输入输出操作。简单(jindn)地说:在C+中,表示数据从内存传送到某个载体或设备中的流,叫做输出流;表示数据从某个载体或设备传送到内存缓冲区变量中的流,叫做输入流。虽然输入和输出是所有高级语言都必须具备的基本功能。但是像C语言一样,C+语言中也没有输入输出语句。C+语言是通过I/O流来实现输入/输出的。I/O流不是C+语言的一部分,而是标准C+库的一部分,是C+类的一个集合。C+的流类比C语言的输入输出函数具有更大的优越性。首先它是类型安全的,可以防止用户输出数据与类型不一10.1 概述(

128、i sh)第159页/共237页第一百五十九页,共238页。10.1 概述(i sh)致的错误。另外,在C+中可以重载运算符和”和“open(“filename”,iosmode);/用对象指针调用open函数打开文件2.在调用构造(guzo)函数建立文件流对象时,指定文件名和模式,在第173页/共237页第一百七十三页,共238页。 10.3.1 构造输入(shr)流对象构造(guzo)过程中打开该文件:ifstreammyFile(“filename”,iosmode);第174页/共237页第一百七十四页,共238页。10.3.2 使用(shyng)提取运算符提取运算符()对于所有标准C

129、+数据类型都是预先设计好的,它是从一个输入流对象中获取字节最容易的方法。提取运算符是用于格式化文本输入的,在提取数据时,以空白符为分隔。如果要输入一段包含空白符的文本,用提取运算符就很不方便。在这种情况下,可以选择使用非格式化输入成员函数getline,这样就可以读一个包含有空格(kn)的文本块,然后再对其进行分析。另一种方法是派生一个输入流类,带有一个成员函数如GetNextToken,它调用ifstream成员提取和格式化字符数据。第175页/共237页第一百七十五页,共238页。10.3.3 输入(shr)流操纵符很多操纵符,如setprecision都定义在ios类中,因此可以应用于输

130、入流。但是只有少数几个操纵符对输入流对象具有实际影响,其中最重要的是进制操纵符dec、oct和hex。在提取中,hex操纵符可以接收处理(chl)各种输入流格式,例如c、C、0xC、0Xc和0XC都将被解释为十进制数12。任何除0到9、A到F、a到f和x之外的字符都将引起数值变换。例如,序列124n5将变换成数值124,并设置ios:fail位。第176页/共237页第一百七十六页,共238页。10.3.4 输入流成员(chngyun)函数输入流成员函数用于从磁盘文件中输入,这些成员函数包括:open函数get函数getline函数read函数seekg函数和tellg函数close函数1.o

131、pen函数如果要使用一个输入文件流(ifstream),必须在构造函数中或者使用open函数把该流与一个特定磁盘文件关联起来。无论哪种方式,参量(cnling)是相同的。在本章后面详细介绍open成员函数。2.get函数第177页/共237页第一百七十七页,共238页。10.3.4 输入流成员(chngyun)函数非格式化get函数的功能与提取运算符()很相像,主要的不同点是get函数在读入数据时包括空白字符,而提取运算符在默认情况下拒绝接受空白字符。3.getline函数getline函数的功能是允许从输入流中读取多个字符,并且允许指定输入终止字符(默认值是换行字符),在读取完成后,从读取的

132、内容中删除该终止字符。4.read函数read函数从一个文件读字节(zji)到一个指定的存储器区域,由长度参数确定要读的字节(zji)数。如果给出长度参数,当遇到文件结束或者在文本模式中遇到文件结束标记字符时读结束。read函数的语法:read(char*)addr,intsize);第一个参数addr表示将要被读取的数据变量的地址;第二个第178页/共237页第一百七十八页,共238页。10.3.4 输入(shr)流成员函数参数size表示变量的大小。5.seekg函数和tellg函数(1)seekg()成员函数在输入文件流中,保留着一个内部指针,指向(zhxin)文件中下一个将读数据的位置

133、,可以用seekg函数来设置这个指针。使用seekg函数可以实现面向记录的数据管理系统,用固定长度的记录大小乘以记录号便得到相对于文件末尾的字节位置。get指针指明下一个读操作在文件中将要出现的位置。seekg()成员函数有两个参数:指针将要指向(zhxin)位置后面的字节数;在文件中,get指针位置的参考。例子:第179页/共237页第一百七十九页,共238页。10.3.4 输入(shr)流成员函数ifstreamifil;ifil.seekg(10,ios:end);上面(shngmin)的代码在文件结束时指定get指针的位置。在ios类中将有三个引用指针被定义:ios:begbeginn

134、ingofthefileios:curcurrentpositionofthefilepointerios:endendofthefile(2)tellg()成员函数例子:intfileSize;ifstreamifil1;ifil.seekg(0,ios:end);第180页/共237页第一百八十页,共238页。10.3.4 输入流成员(chngyun)函数fillSize=ifil.tellg();上面的代码决定了文件的大小。6.close函数close函数关闭(gunb)与一个输入文件流关联的磁盘文件。虽然ifstream类的析构函数可以自动关闭(gunb)文件,但是如果需要使用同一流对

135、象打开另一文件,则首先要用close函数。第181页/共237页第一百八十一页,共238页。10.4 输出(shch)流一个输出流对象是信息流动的目标,最重要的三个输出流类是ostream、ofstream和ostrstream。cout:标准(biozhn)输出;cerr:标准(biozhn)错误输出,没有缓冲,发送给它的内容立即被输出;clog:类似于cerr,但是有缓冲,缓冲区满时被输出。ostrstream类支持磁盘文件输出。如果需要一个仅输出的磁盘文件,可以构造一个ofstream类的对象,在打开文件之前或之后可以指定ofstream对象接受二进制或文本模式数据。很多格式化选项和成员

136、函数都可以应用于ofstream对象。如果在构造函数中指定一个文件名,那么当构造这个文件时,文件是自动打开的。否则,可以在调用默认构造函数之后使用open函数打开文件,或者在一个由文件指示符标识的打开文件基础上构造一个ofstream对象。第182页/共237页第一百八十二页,共238页。10.4.1 构造(guzo)输出流对象构造输出文件流的常用方式如下:1使用默认构造函数,然后调用open成员函数,例如:ofstreammyFile;/建立一个静态输出文件流对象myFile.open(“filename”,iosmode);/打开文件filename,使流对象与文件建立联或者ofstrea

137、m*pmyFile=newifstream;/动态建立一个输出文件流对象,获得对象指针(zhzhn)pmyFile-open(“filename”,iosmode;/打开文件,使流对象与文件建立联系2在调用构造函数时,指定文件名和模式ofstreammyFile(“filename”,iosmode);第183页/共237页第一百八十三页,共238页。10.4.2 使用插入(ch r)运算符和控制格式插入运算符与预先定义的操纵符一起工作(gngzu),用来控制输出格式。在本章后面10.4节详细介绍控制格式。第184页/共237页第一百八十四页,共238页。10.4.3 输出文件(wnjin)流

138、成员函数open函数put函数write函数seekp函数和tellp函数close函数错误处理函数1.open函数如果要使用一个输出文件(wnjin)流(ofstream),必须在构造函数中或者使用open函数把该流与一个特定磁盘文件(wnjin)关联起来。无论哪种方式,参量是相同的。在本章后面详细介绍open成员函数。2.put函数put函数把一个字符写到输出流中,下面两条语句默认是相同的,但第2条语句受该流的格式化参量的影响:第185页/共237页第一百八十五页,共238页。10.4.3 输出(shch)文件流成员函数cout.put(A;);/精确地输出一个字符coutA;/输出一个字

139、符,但此前设置的宽度和填充方式在此起作用3.write函数write函数把一个从内存中的一块容量写到一个输出文件流中,长度参数指出写的字节数。write函数的语法:write(char*)addr,intsize);第一个参数addr表示将要(jingyo)被写到文件中去的对象的地址;第二个参数size表示被写到文件中去的对象的大小。4.seekp函数和tellp函数(1)seekp()函数一个输出文件流保存一个内部指针指出下一次写数据的位置。seekp函数设置这个指针,因此可以以随机方式向磁盘文件第186页/共237页第一百八十六页,共238页。10.4.3 输出文件流成员(chngyun)

140、函数输出。put指针指明下一个写操作在文件中将要出现的位置。seekp()成员函数有两个参数:指针将要被放置处后面的字节(zji)数;在文件中,put指针将要被放置处的引用。例子:ofstreamofil;ofil.seekp(10,ios:beg);上面的代码把put指针放置在文件开始以后的十个字节(zji)处。在ios类中将有三个引用指针被定义:ios:beg-beginningofthefileios:cur-currentpositionofthefilepointer第187页/共237页第一百八十七页,共238页。10.4.3 输出(shch)文件流成员函数ios:end-endo

141、fthefile(2)tellp()函数tellp()函数将返回(fnhu)put指针的当前位置。例子:intposition;ofstreamofil;ofil.seekp(0,ios:end);position=ofil.tellp();if(position=0)cout”Writingthefirstrecord.”;第188页/共237页第一百八十八页,共238页。10.4.3 输出文件流成员(chngyun)函数如果文件是空的,上面的例子将显示Writingthefirstrecord.5.close函数close函数关闭与一个输出文件流关联的磁盘文件。文件使用完毕后必须(bx)将

142、其关闭以完成磁盘输出。虽然ofstream类的析构函数可以自动关闭文件,但是如果需要使用同一流对象打开另一文件,则首先要用close函数。如果构造函数或open成员函数打开了该文件,输出流析构函数自动关闭一个流的文件。6.错误处理函数这些函数如下:bad():如果出现一个不可恢复的错误,则返回一个非0值。第189页/共237页第一百八十九页,共238页。10.4.3 输出(shch)文件流成员函数fail():如果出现一个不可恢复的错误或一个预期的条件,例如文件未找到,则返回一个非0值。good():如果没有错误条件和没有设置文件结尾标志,则返回一个非0值。eof():遇到文件结尾条件,则返回

143、一个非0值。clear():设置内部错误状态,如果用默认参量调用,则清除所有(suyu)的错误位。rdstate():返回当前错误状态。第190页/共237页第一百九十页,共238页。10.4.4 二进制输出(shch)文件默认的输出模式是文本方式。在以文本模式输出时,若遇到换行符(十进制10),便自动被扩充(kuchng)为回车换行符(十进制13)。使用二进制模式输出时,字符不作这种转换。使用二进制模式输出到文件有下列几种方法:1以通常方式构造一个流,然后使用setmode成员函数,在文件打开后改变模式,例如:ofstreamofs(fd);ofs.setmode(filebuf:binar

144、y);ofs.write(char*)iarry,4);/向二进制文件中写入4字节数据2使用ofstream构造函数中的模式参量指定二进制输出模式,例如:ofstreamofs(“file.dat”,ios:binary);ofs.write(char*)iarry,4);/向二进制文件中写入4字节数据3使用open函数带一个二进制模式标志打开文件,例如:第191页/共237页第一百九十一页,共238页。10.4.4 二进制输出(shch)文件filedescfd=open(“file.dat”,OBINARY|OCREAT|OWRONLY);ofstreamofs(fd);ofs.write

145、(char*)iarry,4);/向二进制文件中写入4字节(zji)数据第192页/共237页第一百九十二页,共238页。10.5 格式(g shi)控制在很多情况下,对计算机的输入输出格式进行控制是非常有用的,C+提供了比较灵活的方式控制输入输出的格式。在C+中,可以用C中的printf和scanf语句进行格式化I/O,这是C程序员比较熟悉的方法。除此之外,C+还提供了两种进行控制的方法,一种是使用ios类有关格式控制的成员函数,另外一种是使用称为操纵(cozng)符的特殊类型的函数,下面介绍这两种格式控制的方法。第193页/共237页第一百九十三页,共238页。10.5.1 用iso类成员

146、(chngyun)函数格式化输入/输出的格式由各种格式状态标志来确定,这些状态标志在状态量中各占一位(bit),它们在ios类中定义为枚举量。见课本表10-1。ios类提供成员函数对流的输入输出操作进行格式控制。1.设置状态标志ios供成员函数setf设置状态标志。格式状态标志存放(cnfng)在一个long整数中,每个状态标志是这个long整数中的一位(bit)。要设置一个状态标志,用setf函数,其最一般的格式为:longios:setf(longflags)使用方法为:stream.setf(ios:showbase)这里stream.是要被影响的流对象。第194页/共237页第一百九十

147、四页,共238页。10.5.1 用iso类成员(chngyun)函数格式化【例10-1】#includevoidmain()cout.setf(ios:showpos|ios:scientific);cout123123.23;程序的输出结果为:+123+12323e+02由于每个状态(zhungti)标志是这个long型整数中的一位(bit),因此,setf的参数可用位运算符进行运算。设置showpos使得每个函数前面都加上“+”号,设置scientific使浮点数按科学表示法(指数形式)进行显示。第195页/共237页第一百九十五页,共238页。10.5.1 用iso类成员(chngyun

148、)函数格式化2清除状态标志 要清除一个状态标志,用unsetf函数,它的一般(ybn)格式为:long ios:unsetf(long flags)3取状态标志取一个状态标志,用函数flag。flag有两种形式:long ios: flag()long ios: flag(long flags)第一种形式返回与流相关的当前的状态标志值。第二种形式将流的状态标志值设置为flags,并返回设置前的状态标志值。【例10-2】#include void showflags(long f);void main( )第196页/共237页第一百九十六页,共238页。10.5.1 用iso类成员(chngy

149、un)函数格式化longf;f=cout.flags();showflags(f);cout.setf(ios:showpos|ios:scientific);f=cout.flags();showflags(f);cout.unsetf(ios:scientific);f=cout.flags();showflags(f);voidshowflags(longf)第197页/共237页第一百九十七页,共238页。10.5.1 用iso类成员(chngyun)函数格式化longi;for(i=0x8000;i;i=i1)if(i&f)cout1;elsecout0;coutn;如果当前cout

150、的状态(zhungti)标志skipws和unibuf为真,即格式状态(zhungti)量为0010000000000001程序的输出结果为:第198页/共237页第一百九十八页,共238页。10.5.1 用iso类成员(chngyun)函数格式化0010000000000001001011000000000100100100000000014设置域宽除了格式(gshi)标志外,ios还提供了设置域宽、填充字符和设置精度的成员函数:intios:width(intlen);/设置域宽,并返回原来的域宽intios:width();/返回当前域宽,缺省时域宽为0charios:fill(char

151、ch);/填充字符intios:precision(intnum);/设置显示精度【例10-3】#includevoidmain()第199页/共237页第一百九十九页,共238页。10.5.1 用iso类成员(chngyun)函数格式化cout.setf(ios:showpos);cout.setf(ios:scientific);cout123123.23n;cout.precision(2);cout.width(10);cout123123.23n;cout.fill(#);cout.width(10);cout123123.23n;程序的输出(shch)结果为:+123+1.2323

152、00e+002+123+1.23e+002#+123+1.23e+002第200页/共237页第二百页,共238页。10.5.1 用iso类成员(chngyun)函数格式化使用成员函数ios:width所设置的宽度仅对下一个流输出操作有效,在一次输出操作完成后,宽度又回到了0。C+还提供了另外一种控制格式的方法,称为操纵(cozng)算符的方法,它的原型出现在中,下面介绍这种方法。第201页/共237页第二百零一页,共238页。10.5.2 用操纵(cozng)函数控制格式改变格式变量比较简单的方法是使用特殊的、但类似于函数的运算符,C+称之为操纵符。操纵符以一个流引用作为其参数,并返回同一流

153、的引用,因此,它可嵌入到输入(shr)或输出操作的链中。例如,操纵函数setw(intw)是将域宽设置为w。【例10-4】#include#includevoidmain()inti=6789;intj=1234;intk=10;coutsetw(6)ijkn;coutsetw(6)isetw(6)jsetw(6)kn;第202页/共237页第二百零二页,共238页。10.5.2 用操纵函数(hnsh)控制格式程序的输出结果为:67891234106789123410在第一条输出语句中,setw(6)将下一次输出(i)的域宽设为6,但域宽马上恢复为0,故j、k的输出域宽都为0。而第二条输出语句

154、每个变量的输出域宽为6。这里,设置域宽的操作与ios:width是完全相同的,它仅对下一个流输出操作有效。可见,操纵符函数仅仅改变流的状态标志。C+提供了标准(biozhn)的操纵符函数,也提供了用户建立自己的操纵符函数的方法,后者对用户控制一些特殊的输出设备提供了有效的表达方法。C+提供的标准(biozhn)(或称预定义)的操纵符见课本表10-2。第203页/共237页第二百零三页,共238页。10.5.2 用操纵(cozng)函数控制格式操纵符endl输出一换行字符并刷新流,也可用flush在任何时候刷新流ostream:ostreamflush用户也可以建立自己的操纵符函数,所有不带参数

155、的输出操纵符函数均有以下形式:ostream&manip_name(ostream&stream)returnstream;其中,manip_name是操纵函数的名字,虽然操纵函数带有一个被操作(cozu)流引用的参数,但在早期实现版本,它用于输出操作(cozu)时不带参数。例如:【例10-5】第204页/共237页第二百零四页,共238页。10.5.2 用操纵(cozng)函数控制格式#includeostream&money(ostream&output)returnoutputt$;voidmain()floatowed=2.35,earned=23.9;coutmoneyowedmon

156、eyearned;程序的输出结果为:$2.35$23.9操纵函数之所以有用的原因有两个:第一(dy),当要对预先未定义的设备(如绘图仪)进行操作时,定义自己的操纵函数第205页/共237页第二百零五页,共238页。10.5.2 用操纵函数(hnsh)控制格式使得这类设备的输出变得方便;第二,当多次重复相同的操作序列时,可以将这些操作合并在一个(y)操纵函数中。【例10-6】#include#includeostream&setup(ostream&stream)stream.setf(ios:left);streamsetw(10)setfill($);returnstream;voidmai

157、n()第206页/共237页第二百零六页,共238页。10.5.2 用操纵函数控制(kngzh)格式cout500setup500;程序(chngx)的输出结果为:500500$第207页/共237页第二百零七页,共238页。10.6 文件(wnjin)I/O写入到文件和从文件中读出的过程可分解为3个抽象的概念:往流中加入一个字符;从流中取出一个字符;一旦建立(jinl)一个流,把它与文件相关联以便用来读和写。因此,在C+中,要进行文件I/O,首先必须创建一个流,然后将这个流与文件相关联(称为打开文件),这时才能进行读和写操作,使用完后,需关闭文件。第208页/共237页第二百零八页,共238

158、页。10.6.1 文件的打开(d ki)和关闭C+有3种类型的文件流:输入文件流、输出文件流和输入/输出文件流。要打开一个输入文件流,必须(bx)说明类型为ifstream的对象;要打开一个输出文件流,必须(bx)说明一个类型为ofstream的对象;要建立输入和输出的文件流必须(bx)说明一个类型为fstream的对象。例如:ifstreamin;/inputofstreamout;/outputfstreamboth;/inputandoutput一旦建立了一个流,将它与文件相关联的一种方法是使用函数open()。ofstreamofile;/创建输出文件流ofile.open(“payr

159、oll”)/ofile流与文件“payroll”相关联第209页/共237页第二百零九页,共238页。10.6.1 文件(wnjin)的打开和关闭/对文件“payroll”进行访问ofile.close();/关闭“payroll”ofile.open(“employee”);/重用ofile上述程序段也可写为:ofstreamofile(“payroll”);/创建输出文件流并与文件“payroll”相关联/对文件“payroll”进行访问ofile.close();ofstreamofile(“employee”);说明ofstream类还具有自动打开文件的构造函数,该构造函数的参数(cn

160、sh)和缺省值与open()函数相同。open函数的原型为:第210页/共237页第二百一十页,共238页。10.6.1 文件(wnjin)的打开和关闭voidopen(constchar*filename,intfilemode,int=filebuf:openprot)第一个参数表示相关联的文件名;第二个参数表示文件的打开方式;第三个参数是文件的保护方式,与操作系统(cozuxtn)有关,用户一般只使用缺省值。见课本表10-3。filemode表示文件的打开方式,可以将几种方式通过“或”操作结合起来。如:打开一个供读和写的文件,其方式可以定义为ios:in|ios:out.。filemod

161、e可以是一个缺省参数,打开输入文件时,它缺省为ios:in;当打开输出文件时,缺省为ios:out。缺省情况下,文件使用文本方式打开。这就是说,在输入时,回车/换行序列要转换为字符“n”。在输出时,字符“n”转换为回车/换行序列。这些转换在二进制方式下是不第211页/共237页第二百一十一页,共238页。10.6.1 文件的打开(d ki)和关闭发生的。这是文本方式和二进制方式主要的区别。例如,可以打开(dki)一个二进制文件并进行追加写操作:ofstreamofile(“binary_ofile”,ios:binary|ios:app);/对文件“binary_ofile”进行写操作ofil

162、e.close();第212页/共237页第二百一十二页,共238页。10.6.2 文件(wnjin)的读写文件读操作是从流中取一个元素,文件写操作是向流中写一个元素。ofstream类从ostream中继承了输出(shch)操作,而ifstream类从istream中继承了输入操作。当一个输入文件流、输出(shch)文件流或输入/输出(shch)文件流建立后,对文件的读写就象控制台读写一样的方便。【例10-7】将文件file1拷贝到文件file2。#includevoidmain()charch;ifstreamf1(file1);if(!f1)第213页/共237页第二百一十三页,共238

163、页。10.6.2 文件(wnjin)的读写coutcannotopenfile1forinput;return;ofstreamf2(file2);if(!f2)coutcannotopenfile2foroutput;return;while(f2&f1.get(ch)f2.put(ch);f1.close();f2.close();下列程序(chngx)是把一个整数、一个浮点值和一个串写到file文件第214页/共237页第二百一十四页,共238页。10.6.2 文件(wnjin)的读写中。【例10-8】#include#includevoidmain()ofstreamout(file)

164、;if(!out)coutcannotopenfile;return;out10456.45;outThisisashorttextfile.;第215页/共237页第二百一十五页,共238页。10.6.2 文件(wnjin)的读写out.close();【例10-9】本程序从上面程序建立的file文件(wnjin)中读入一个整数、一个float数、一个串。#include#includevoidmain()charch;inti;floatf;charstr80;ifstreamin(file);if(!in)第216页/共237页第二百一十六页,共238页。10.6.2 文件(wnjin)

165、的读写coutifchstr;coutifchn;cout”运算符跳过空白,然后读入对应于输入对象类型的字符。第217页/共237页第二百一十七页,共238页。10.6.2 文件(wnjin)的读写【例10-10】通过文件指针的位置对文件进行读写操作。#includevoidmain()doubledbl;fstreammyio;/声明输入输出流streampospos20;/声明保存(bocn)文件指针位置的数组myio.open(myfile,ios:in|ios:out|ios:binary);/以读写方式打开文件for(inti=0;i10;i+)dbl=i/10.0;myio.wri

166、te(char*)&dbl,sizeof(double);/向文件中写数据第218页/共237页第二百一十八页,共238页。10.6.2 文件(wnjin)的读写posi=myio.tellp();/保存文件指针当前(dngqin)的位置for(i=10;i20;i+)dbl=i/10.0;myio.write(char*)&dbl,sizeof(double);/向文件中写数据posi=myio.tellp();/保存文件指针当前(dngqin)的位置for(i=0;i20;i=i+2)myio.seekg(posi);/移动文件指针位置到指定位置myio.read(char*)&dbl,s

167、izeof(double);/读数据coutThedatais:dblendl;第219页/共237页第二百一十九页,共238页。10.6.2 文件(wnjin)的读写myio.seekp(0,ios:beg);/将文件指针(zhzhn)置于文件开始for(i=100;i120;i+)dbl=i/10.0;myio.write(char*)&dbl,sizeof(double);/向文件中写数据for(i=1;i20;i=i+2)myio.seekg(posi);/移动文件指针(zhzhn)到指定位置myio.read(char*)&dbl,sizeof(double);/从文件中读数据cou

168、tThedatais:dblendl;第220页/共237页第二百二十页,共238页。【例10-11】编写一个程序,在二进制文件file.dat中写入三条记录,显示其内容,然后(rnhu)删除第2个记录,要显示删除记录后的文件内容。#include#include#includestructworkerintno;charname10;doublesalary;structworkerwor3=1,杨华,600.50,5,李丽,620.5,8,孙英,760;10.7 程序(chngx)实例第221页/共237页第二百二十一页,共238页。10.7 程序(chngx)实例voidmain()in

169、ti;fstreamifile,ofile;ofile.open(file.dat,ios:out|ios:trunc|ios:binary);/文件打开时,其长度(chngd)截取为0if(!ofile)coutfile.dat文件不能打开endl;abort();for(i=0;i3;i+)ofile.write(char*)&wori,sizeof(wori);第222页/共237页第二百二十二页,共238页。10.7 程序(chngx)实例ofile.close();cout文件file.dat的记录如下:endl;ifile.open(file.dat,ios:in|ios:bina

170、ry);for(i=0;i3;i+)/显示file.dat的所有(suyu)记录ifile.read(char*)&wori,sizeof(wori);coutwori.notwori.nametwori.salaryendl;ifile.close();cout删除第2个记录后的文件内容:endl;ofile.open(file.dat,ios:out|ios:trunc|ios:binary);/文件打开时,其长度截除为0for(i=0;i3;i+)/删除第2个记录if(i!=1)/不为第2个记录时第223页/共237页第二百二十三页,共238页。10.7 程序(chngx)实例ofile

171、.write(char*)&wori,sizeof(wori);ofile.close();ifile.open(file.dat,ios:in|ios:binary);for(i=0;i2;i+)/显示删除记录后的文件内容ifile.read(char*)&wori,sizeof(wori);coutwori.notwori.nametwori.salaryendl;ifile.close();程序的输出(shch)结果为:文件file.dat的记录如下:1杨华600.5第224页/共237页第二百二十四页,共238页。10.7 程序(chngx)实例5李丽620.58孙英760删除第2个记

172、录后的文件内容:1杨华600.58孙英760【例10-12】作为某公司的客户跟踪系统的一部分,创建包含以下功能的菜单驱动应用程序:(1)接收用户(yngh)信息:(2)在文件中保存用户(yngh)信息;(3)显示已经存在用户(yngh)的信息;(4)查询并显示相关信息;(5)退出应用程序。#include#includeclassPersonprotected:第225页/共237页第二百二十五页,共238页。10.7 程序(chngx)实例charname26;chardateOfBirth11;charcity26;charphoneNo11;voidaccept()coutendlNam

173、e:;cin.getline(name,25);coutendldateOfBirth;cin.ignore();coutendlCity:;cin.getline(city,25);第226页/共237页第二百二十六页,共238页。7.2.5 几种特殊(tsh)操作符的重载coutendlmobileNo;cin.ignore();coutendlphoneNo;cin.ignore(); voiddisplay()coutendlName:name;coutendlDateofbirth:dateOfBirth;coutendlCity:city;第227页/共237页第二百二十七页,共2

174、38页。10.7 程序(chngx)实例coutendlMobilenumber:mobileNo;coutendlResidencenumber:phoneNo;public:charmobileNo11;classCustomer:publicPersonprivate:classFileRead;classFileWrite;friendFileRead;friendFileWrite;第228页/共237页第二百二十八页,共238页。10.7 程序(chngx)实例charbillingAddress51;floatamountOutstanding;public:voidaccept

175、()coutendlendlENTERCUSTOMERSDETAILS;Person:accept();coutendlCustomersbillingaddress:;cin.getline(billingAddress,50);coutendlamountOutstanding;cin.ignore();第229页/共237页第二百二十九页,共238页。10.7 程序(chngx)实例voiddisplay()coutendlendlCUSTOMERSDETAILS;Person:display();coutendlBillingaddress:billingAddress;coutend

176、lOutstandingamount:amountOutstandingendl;classFileWriteprivate:fstreamfile;public:第230页/共237页第二百三十页,共238页。10.7 程序(chngx)实例voidaccept(Customer&custobj)custobj.accept();file.open(customer.dat,ios:out|ios:app);file.write(char*)&custobj,sizeof(custobj);file.close();classFileReadprivate:fstreamfile;publi

177、c:voiddisplay_all(Customer&custobj)第231页/共237页第二百三十一页,共238页。10.7 程序(chngx)实例file.open(customer.dat,ios:in);file.read(char*)&custobj,sizeof(custobj);while(file.eof()custobj.display();file.read(char*)&custobj,sizeof(custobj);file.close();voiddisplay_Cust(char*mobile)Customercustobj;file.open(customer.

178、dat,ios:in);第232页/共237页第二百三十二页,共238页。10.7 程序(chngx)实例file.read(char*)&custobj,sizeof(custobj);while(file.eof()if(strcmp(custobj.mobileNo,mobile)=0)custobj.display();file.close();return;file.read(char*)&custobj,sizeof(custobj);file.close();coutAcustomerwithmobilenumber:mobiledoesnotexist!endl;第233页/共

179、237页第二百三十三页,共238页。10.7 程序(chngx)实例;voidmain()Customercustobj;FileWritewriteobj;FileReadreadobj;intchoice=0;while(choice!=4)coutendlCUSTOMERMENUendl;cout1.Acceptthedetailsofacustomerendl;cout2.Displaythedetailsofallcustomersendl;cout3.Displaydetailsofonecustomerendl;第234页/共237页第二百三十四页,共238页。10.7 程序(c

180、hngx)实例cout4.Quittheapplicationendl;coutchoice;cin.ignore();switch(choice)case1:writeobj.accept(custobj);break;case2:readobj.display_all(custobj);break;case3:coutmobile;readobj.display_Cust(mobile);break;case4:continue;default:coutInvalidoption!Pleaseenter1-4onlyendl;第236页/共237页第二百三十六页,共238页。感谢您的欣赏(xnshng)!第237页/共237页第二百三十七页,共238页。内容(nirng)总结有时候,你可能面临并非所有的事情都是完美的事实,偶而,甚至最好的计划也会失败。印刷的一种方法是为每一页纸或每一米布一遍遍地重复制作样本。I_it=&it。这样编程者就可以只针对这个抽象的逻辑设备流去更加自由地编程了。当文件是可查找的,则filebuf允许查找。get指针指明下一个读操作在文件中将要出现(chxin)的位置。put指针指明下一个写操作在文件中将要出现(chxin)的位置。感谢您的欣赏第二百三十八页,共238页。

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号