第10章模板和异常处理_第1页
第10章模板和异常处理_第2页
第10章模板和异常处理_第3页
第10章模板和异常处理_第4页
第10章模板和异常处理_第5页
已阅读5页,还剩75页未读 继续免费阅读

下载本文档

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

文档简介

1、第第10章章 模板和异常处理模板和异常处理目录目录10.1 函数模板函数模板10.1.1 函数模板的定义及说明函数模板的定义及说明10.1.2 函数模板的简单应用函数模板的简单应用10.2 类模板类模板10.2.1类模板的定义及说明类模板的定义及说明10.2.2模板类及简单应用模板类及简单应用10.2.3类模板的派生与继承类模板的派生与继承1、模板类继承非模板类、模板类继承非模板类2、非模板类继承模板类、非模板类继承模板类3、类模板的派生、类模板的派生目录目录10.3 异常处理异常处理10.3.1 异常处理的基本思想异常处理的基本思想10.3.2 异常处理的实现异常处理的实现1、throw语句

2、语句2、trycatch语句语句3、trycatch语句的嵌套语句的嵌套4、相关的几点说明、相关的几点说明 在实际C+程序设计过程中,往往会发现这样的现象:程序中所定义的两个或多个函数的函数体完全一样,所不同的只是它们的参数类型不一样。引言引言求两个数的最小值求两个数的最小值 int MIN(int x, int y) retrun (xy) ? x :y; float MIN(float x, float y) return (xy) ? x :y; double MIN(double x, double y) return (xy) ? x :y; 三个函数函数体相同,唯一不同的是它们的形

3、参不一三个函数函数体相同,唯一不同的是它们的形参不一样,我们可以用样,我们可以用重载重载多态实现,但是很繁琐,也容易多态实现,但是很繁琐,也容易出错。出错。求两个数的最小值求两个数的最小值如有下面调用语句:char a, b;MIN(a, b);?问题:问题:用户因为没有定义char类型的重载函数,程序将会产生错误 !为解决上述问题C+系统引入模板机制 。解决方法解决方法模板:是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性。 模板(Templates)可以生成通用的函数,这些函数能够接受任意数据类型的参数,可返回任意类型的值,而不需要对所

4、有可能的数据类型进行函数重载时的匹配检查。 模板及种类模板及种类根据所处理的数据类型说明作为参数的类和函数,分别称为类模板和函数模板。 10.1 函数模板函数模板 函数模板的定义形式如下: template 返回值类型 函数名(形参表) 函数体 关键字关键字参数表关参数表关键字或者键字或者用用class10.1.1 函数模板的定义及说明函数模板的定义及说明1、template为定义模板的关键字,用于指定在实际调用时可以进行替换的参数类型名,其格式为: 这里的class为关键字,T1、T2、Tn为用户自己命名的以后需要替换的类型名。定义说明定义说明2、 “函数值类型”是模板函数的返回值类型,既可

5、以是已有的类型名,如int、double等,也可以是在中给出的类型名,如T1、T2等。同样,“参数表”和“函数体”中所使用的数据类型名既可以是已有的类型名,也可以是在中给出的类型名。举例举例#include template T GetMax (T a, T b) return (ab? a: b); void main () int i=5,j=6,K; float m=6.5, n=5.8,L; K=GetMax(i, j); L=GetMax(m, n); coutKendl; coutLendl; 函数模板函数模板定义定义函数模板函数模板的应用的应用 1在主函数main( ) 中,模板

6、函数GetMax()调用了两次,两次调用的参数类型是不一致的,而对于GetMax()函数的定义,并没有在括号中指明具体数据类型的,但把它定义成函数模板。因此,编译器将会自动决定每一个调用需要什么数据类型。 举例说明举例说明2模板函数只包括一种数据类型 (class T)时,它的两个参数都要求是同一种数据类型,当使用两个不同类型的参数来调用它,系统将产生错误。如:int i;long j; k = GetMax (i, j);上面的调用就是错误的,因为函数等待的是接收两个相同类型的参数。 3系统允许模板函数接受两种或两种以上不同类型的数据,例如: template T GetMin (T a,

7、U b) return (ab? a: b); 本例中,模板函数 GetMin() 接受两个不同类型的参数,两个不同的类型参数的区分是通过T和U来进行的,结果将返回一个与第一个参数同类型的数据。在这种定义方式下,还可以通过以下方式来调用该函数:int i, j; long k; i = GetMin (j, k); 或者,简单的用下面形式来实现调用: i = GetMin (j, k);举例说明举例说明4在定义时要注意:在template语句与函数模板定义语句之间不允许有别的语句。如下面的声明是错误的:templateint i;T min(T x,T y) 函数体举例说明举例说明5模板函数类

8、似于重载函数,但两者有很大区别:函数重载时,每个函数体内可以执行不同的动作,即函数体功能可以定义不同。但同一个函数模板实例化后的模板函数都必须执行相同的动作,即只能执行的该模板函数的函数体。 举例说明举例说明6、函数模板中的模板形参可实例化为各种类型,当实例化模板形参的各模板实参之间不完全一致时,就可能发生错误,在C+中,函数模板与同名的非模板函数重载时,应遵循下列调用原则:举例说明举例说明7、模板参数也可以设置默认(缺省)值,类似于为函数参数设置默认值一样,如:template / 一个typename 参数template / 两个class 参数。template / 一个class 和

9、一个整数。template / 有一个默认值。template / 参数为一个函数。举例说明举例说明(1)首先寻找一个与参数完全匹配的函数,若找到就调用它。若参数完全匹配的函数多于一个,则这个调用也将是一个错误的调用。(2)其次寻找一个函数模板,若找到就将其实例化生成一个匹配的模板函数并调用它。(3)若上面两条都失败,则使用函数重载的方法,通过类型转换产生参数匹配,若找到就调用它。(4)若上面三条都失败,即没有找都匹配的函数,则这个调用是一个错误的调用,系统将产生报错。在定义函数模板之后,用户可以直接用实参代替函数模板定义中的参数,来实现对该函数的调用。具体形式如下所示:函数名;10.1.2

10、函数模板的简单应用函数模板的简单应用系统处理:编译器将根据用户给出的实参类型,来生成相应的重载函数,该生成的重载函数称为模板函数,是一个实实在在的函数,可以执行。 【例例10-1】试编程实现利用函数模板方式设计一个函数sort,实现对整数序列和字符序列从小到大的排序。举例举例分析:要实现在一个函数中对整数序列和字符序列进行排序,则要用到函数模板,进行对不同数据的处理。在定义时要注意函数模板的定义格式。考虑到数据序列的存储,则函数sort应有两个参数,一个是数据序列的首地址,一个应是数据序列的长度。要进行排序,则要用到排序算法进行实现。 #include#includetemplate/对函数模

11、板的定义void sort(T a,int n) /注意函数模板中参数的定义形式int i,j;cout原系列为:; for(i=0;in;i+) coutait;coutendl;for(i=0;in;i+)for(j=i+1;jaj) T k=ai; ai=aj; aj=k;cout排序后系列为:;for(i=0;in;i+)coutait;coutendl;void main() int b5=7,5,2,8,1; char c=xkdwzeopb; sort(b,5);/函数模板的调用,注意数据类型为int sort(c,strlen(c); /函数模板的调用,注意数据类型为char运

12、行结果如下:运行结果如下:原序列为:75281排序后的序列为:1 25 78原序列为:x k d w z e o p b 排序后的序列为:b d e k o p w x z 类也可以定义为类模板(class templates),这样就可使得一个类有基于通用类型的成员,而不需要在类生成的时候定义具体的数据类型,例如:template class AA T x, y;public: AA (T a, T b) x=a; y=b; ;10.2 类类模板模板类模板定义关键字,也类模板定义关键字,也可用关键字可用关键字typename类模板的一般定义形式: Template class 类名 /类定义

13、 ;10.2.1 类模板的定义及说明类模板的定义及说明模板参数可以是一个,模板参数可以是一个,也可以是多个。也可以是多个。定义说明定义说明1、定义中的template是声明各模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个。2、参数类型说明关键字typename也可以用class代替3、类模板定义中,凡要采用标准数据类型的数据成员、成员函数的参数或返回类型的前面都要加上类型标识符。定义说明定义说明4、如果类中的成员函数要在类的声明之外定义,则它必须是模板函数。其定义形式为:template函数返回类型 类名:函数名(数据类型参数标识符 形参1,数据类型参数标识符 形参n) 函数

14、体5、类模板使类中的一些数据成员和成员函数的参数或返回值可以取任意的数据类型。类模板不是一个具体的类,它代表着一族类,是这一族类的统一模式。使用类模板就是要将它实例化为具体的类。【例例10-2】定义一个包含两个私有数据、一个构造函数和一个输出函数的类模板。举例举例template /A行class AA private: T1 i; /B行 T2 j; public:AA(T1 a,T2 b);void print( );template /C行AA:AA(T1 a, T2 b):I(a), J(b) /D行template void AA:print( )couti=i, j=jendl;

15、实现类定义如下:实现类定义如下:定义模板的格式定义模板的格式定义了私有数据定义了私有数据:i1、程序中的A行为定义模板的格式,注意语句后面不能加上分号,因为它要和下面的类定义构成一个整体。2、程序中的B行语句是定义了一个类的私有数据i;3、程序中的C行和D行合在一起构成了在类的外部定义AA类的构造函数AA,注意定义形式;4、关键字typename,也可以使用用关键字class代替。说明说明模板类是一个实实在在的类,即有确定类型的类。可以利用类模板产生很多的不同模板类,如,利用10-2例中的类模板AA,可以生成以下的模板类:AA; /第一个参数是int,第二个参数也是int。AA; /第一个参数

16、是int, 第二个参数是char。AAAA, char /第一个参数具有AA类的类型,第二个参数是char。AA /第一个参数指向int的指针类型,第二个参数是int。 10.2.2 模板类及简单应用模板类及简单应用将类模板的模板参数实例化后生成的具体的类,就是模板类。将类模板的模板参数实例化后生成的具体的类,就是模板类。 定义形式:类名类名 对象名对象名1,对象名,对象名2,对象名,对象名n;其中:1、类名为实例化的模板类,对象名1,对象名2等为定义类的对象名称。2、系统将会把格式中的:类名中的“类型实参表”全部替换成对应的实际类型,从而创建一个具体的模板类,并生成该模板类(具体类)的对象。

17、 10.2.2 模板类及简单应用模板类及简单应用有了确定类型的模板类后,就能利用它来创建类的实有了确定类型的模板类后,就能利用它来创建类的实例例-即产生类的对象。即产生类的对象。【例例10-3】定义10-2例中的模板类及生成对象,并在主函数中完成对相关成员函数的调用测试。 举例举例分析:在主函数中通过定义模板类并生成对象,然后利用对象来调用成员函数来完成对定义类的测试 。void main()AAa1(3,5); /实例化模板类并成了a1对象。a1.print(); /a1对象调用了成员函数print。AAa2(4,a);a2.print();AAa3(2.9,10);a3.print();实

18、现类定义如下:实现类定义如下:运行结果:运行结果:i3,j5i4,jai2.9,j10【例例10-4】试设计一个复数类模板Complex,其私有数据成员real和image的类型未知且不一定相同,具体相关函数要求如下:(1)构造函数;要求:设置缺省值0。(2)输出函数show;要求按复数的标准形式输出。(3)成员函数add;功能:求两个复数的和。(4)友元函数重载运算符-;功能实现求两个复数的差。(5)要求在主函数中定义模板类对象,分别以int和double实例化类型参数来测试复数类模板。举例举例1、从该复数类模板Complex的两个私有数据成员real和image的类型未知且不一定相同可知,

19、模板有两个不相同的参数,应设置如下模板参数:template;在定义构造函数时要求要有缺省参数,所以构造函数申明应为:Complex(T1 x=0,T2 y=0);2、对输出函数show的定义应考虑到复数的输出形式:real+image i;的形式,在输出时,应考虑到如果image的值为正数时,输出为:real+image i;负数时输出为:real-image i;当为0时输出为:real。因此,要先对image的值进行判断,再决定输出形式;分析分析3、对add函数,应考虑到其参数类型也应该是一个对象,因此,在定义该对象时,要注意对定义的类模板进行实例化,形式为:Complex add(Co

20、mplex a);注意函数的返回值也应为类的对象。4、对于友元函数重载运算符-,要注意参数表也应为两个参数,并且这两个参数也进行实例化,如:friend Complex operator-(Complex b, Complex c);5、在类的外部定义成员函数时,要注意类模板的成员函数定义与普通类成员函数定义的区别,特别是注意在函数体内定义对象时,也要注意对类模板进行实例化,否则系统将出错,如:Complex t1; 分析分析#includetemplateclass Complex T1 real; T2 image;public: Complex(T1 x=0,T2 y=0); Compl

21、ex add(Complex a); friend Complex operator-(Complex b, Complex c); void show();程序如下:程序如下:templateComplex:Complex(T1 x,T2 y)real=x;image=y;templateComplex Complex:add(Complex a)Complex t1;t1.real=real+a.real;t1.image=image+a.image;return t1;templateComplex operator-(Complex b, Complex c)Complex t2;t2

22、.real=b.real-c.real;t2.image=b.image-c.image;return t2;templatevoid Complex:show()cout0)cout+imageiendl;else if(image0) cout-imageiendl;类模板作为一种特殊的类,也可以有自己的派生类,与普通类的派生一样,类模板的派生也有公有派生、私有派生和保护派生方式,相关类成员的访问方法与原则和普通类的继承与派生是一致,如:派生类不能访问基类的私有成员等,并且派生的语法格式普通类也是相似的。但要注意以下两点:(1)在声明模板继承之前,必须重新声明该模板,否则系统将产生错误。(

23、2)类模板的成员函数不能声明为虚函数。10.2.2 类模板的派生与继承类模板的派生与继承void main()Complexi(2,3),k;Complexj(4,5.2),m(1,2.6),n;k=i.add(i);k.show();n=j-m;n.show();问题:问题:如何利用成员函数的方式重载如何利用成员函数的方式重载“+”,实现,实现add函数的功能?函数的功能?在派生与继承的过程中,基类和派生类都有可能是模板类或者是经过实例化的模板类。常见有以下三种:1、模板类继承非模板类:、模板类继承非模板类:基类为非模板类,派生类为模板类。其作用可以实现用一个非模板类,为一组模板提供一种共同

24、实现的方法。2、非模板类继承模板类:非模板类继承模板类:基类为模板类,派生类为非模板类。3、类模板的派生:类模板的派生:基类为类模板,派生类也为类模板。与非模板类继承模板类不同的是派生类(类模板)将继承基类(模板类)的所有实例,而不是一个实例 10.2.2 类模板的派生与继承类模板的派生与继承基类为非模板类,派生类为模板类。其作用可以实现用一个非模板类,为一组模板提供一种共同实现的方法。1、模板类继承非模板类模板类继承非模板类 【例例10-5】试设计一个非模板类Point类,然后设计一个继承Point类的类模板Line,利用成员函数求Line类实例化为int, double类型时的长度,并进行

25、相应的输出和测试。 1、首先定义一个非模板类point,其定义形式为普通类的定义,但需要注意的是:两个数据成员如果访问权限为private时,要考虑到在派生类中的访问,所以在point类中要定义两个公有函数getx(),gety(),来实现对基类私有数据在派生类中的访问。2、类模板Line的定义,要注意定义形式,templateclass Line:public Point,在成员函数Length()中。3、因为要求出两个点的长度,所以要利用求平方根数学函数,要注意头文件的包含#include; 4、在主函数中定义Line类的对象时要注意:首先要对进行模板类的实例化形式如:Linem(1,2,

26、3,4);在定义好对象后,其成员函数的访问同普通类是一样的。 分析分析#include#includeclass Pointint x1;int y1;public:Point(int i=0,int j=0)x1=I;y1=j;void show( )cout”起点为:(“x1”,”y1”)”t”; int getx( )return x1;int gety( )return y1; templateclass Line:public PointT x2,y2;public:Line(T c1,T c2,int c3,int c4 ):Point(c3,c4) x2=c1; y2=c2;T

27、Length() T k=sqrt(x2-getx()*(x2-getx()+(y2-gety()*(y2-gety(); return k;void show()Point:show( );cout”终点为:(“x2”,”y2”)”endl;void main()Linem(1,2,3,4);m.show( );cout”两点的距离为:”m.Length()endl;Linen(2.4,5.2,1,8);n.show( );cout”两点的距离为:”n.Length()endl;运行结果运行结果:起点为:(3,4) 终点为:(1,2)两点的距离为:2起点为:(1,8) 终点为:(2.4,5.

28、2)两点的距离为:3.1305 基类为模板类,派生类为非模板类。因为类模板能产生不同实例,所以非模板类只能继承一个确定的模板类,既继承一个实例。2、非模板类继承模板类非模板类继承模板类 【例例10-6】试设计一个模板类Point类,然后设计一个继承Point类的Line类,用来输出两个点的值。并在主函数中进行测试。 。 1、先定义模板类Point,注意定义时和普通类定义的区别。2、定义派生类Line时,要注意定义时与普通派生定义的区别,模板类首先要实例化才能进行派生,形式如: class Line: public Point;在派生类的构造函数定义时和说明基类的构造调用时,也要注意基类的实例化

29、,形式如下所示:Line(int a,int b,int c,int d):Point(c,d)在进行基类成员函数调用时,也要注意对基类(模板类)的实例化,形式如下所示:Point:show( );模板类实例化后,可以直接生成派生类 。分析分析#includetemplateclass PointT x1,y1;public:Point(T m,T n)x1=m;y1=n;void show() coutx1=x1,y1=y1endl; ;class Line:public Pointint x2,y2;public:Line(int a,int b,int c,int d):Point(c,

30、d)x2=a;y2=b;void show()Point:show();coutx2=x2,y2=y2endl;void main()Pointp1(1.1,2.2);p1.show();Line ab(1,2,3,4);ab.show();运行结果:运行结果:x1=1.1,y1=2.2x1=3,y1=4x2=1,y2=2 基类为类模板,派生类也为类模板。与非模板类继承模板类不同的是派生类(类模板)将继承基类(模板类)的所有实例,而不是一个实例。 3、类模板的派生类模板的派生【例例10-7】试设计一个模板类Point类,然后设计一个继承Point类的Line类模板,作用是用来输出两个点的值,并

31、在主函数中进行测试。1、先定义模板类Point,注意定义时和普通类定义的区别。2、在定义派生类模板Line时,一定要对模板类要先进行实例化才能够进行派生,形式如: templateclass Line: public Point 在类模板(派生类)的构造函数定义时,要注意定义时对基类的实例化。形式如下所示:Line(T a,T b,T c,T d):Point(c, d); 在进行基类成员函数调用时,应首先对基类(模板类)的实例化,形式如下所示:Point:show( ); 3、实例化后,在主函数中定义派生类对象时,也要注意对对象的实例化,形式如下所示:Lineb(1,2,3,4); 分析分析

32、#includetemplateclass PointT x1,y1;public:Point(T m,T n)x1=m;y1=n;void show() coutx1=x1,y1=y1endl; ;templateclass Line:public PointT x2,y2;public:Line(T a,T b,T c,T d):Point(c,d)x2=a;y2=b;void show()Point:show();coutx2=x2,y2=y2endl; void main()Pointa(1.1,2.2);a.show();Lineb(1,2,3,4);b.show();Linec(1

33、.1,2.2,3.3,4.4);c.show();运行结果:运行结果:x1=1.1,y1=2.2x1=3,y1=4x2=1,y2=2x1=3.3,y1=4.4x2=1.1,y2=2.2程序中的错误通常包括三类:语法错误、逻辑错误和运行异常。1、语法错误:是指程序中源代码的书写不符合语言的语法规范。2、逻辑错误(或语义错误):是指因程序设计不当而造成程序不能完成预期的功能。 3、运行异常:是指由程序运行环境问题造成的程序异常中止。 如,程序提出内存分配申请,但内存空间不足;或者是程序运行时要打开文件,但在硬盘中的该文件被删除或移走等等,这些情况都会造成运行异常。 10.3 异常处理异常处理 C+

34、中使用异常处理基本思想包括:抛出异常、捕获异常和处理异常。1、抛出异常:是指把程序中出现的异常抛出,等待用户处理。2、捕获异常:对出现的异常进行捕获。3、处理异常:编写程序对捕获的异常进行处理,处理的方法由程序决定。 C+中使用throw语句来抛出异常,使用trycatch语句来捕获和处理异常。10.3.1 10.3.1 异常处理的基本思想异常处理的基本思想1、throw语句 抛出异常的语法格式如下: throw ; 10.3.2 10.3.2 异常处理的实现异常处理的实现 说明:如果某段程序中发现了自己不能处理的异常情况 ,就可以使用该方式抛出这个异常,将它抛给调用该段程序的函数。其中:表达

35、式值的类型称为异常类型,它可以是任意的C+的类型(void除外),包括C+的类。具体如下: throw 1; /抛出一个异常,该异常为int类型,值为1throw 1; /抛出一个异常,该异常为char类型,值为字符型数据1。throw “number error”; /抛出一个异常,该异常为char*类型,值为字符串的首地址。 执行顺序规定: 当在执行完throw语句后,系统将不执行throw后面的语句,而是直接跳到异常处理语句部分进行异常的处理。 10.3.2 10.3.2 异常处理的实现异常处理的实现语法格式:try . /可能抛出异常的语句序列 catch( ) . /异常处理代码 c

36、atch( ) . /异常处理代码 catch(异常类型名n ) . /异常处理代码 2、trycatch语句1、若try内的代码中用throw语句抛出一个异常,则在内部“throw表达式;”代码执行后,立即跳转到try后的catch块列表中,按照catch块出现的先后顺序,查找和抛出的异常对象的类型相同的catch块。若找到,将抛出的异常对象的值赋值给对应catch块的,并进入该catch块执行(类似一个函数调用过程)。2、执行完该catch块代码后,系统跳过和其并列的其它的catch块到trycatch后面的语句进行执行。3、所有同级别的catch语句只能有一条被执行,不存在两条被同时执行

37、的情况;4、如果在catch语句块代码中,其部分的形式表示为三个点(三个点()。即写成:catch (),系统将把三个点处理成“通配符”,表示捕获所有类型的异常,并且,此形式只能位于同级别的catch语句中的最后位置。 定义说明定义说明举例举例 【例例10-8】试分析下面程序的输出结果 。#includevoid main() try coutThis is a Test!endl; throw 1; /A行coutIt can not show!endl; /B行 catch(char) cout“*”endl; /C行 /D行 catch(int a) cout“+”endl; /E行 c

38、out”a=”aendl; /F行 catch() cout”catch all type!”; /G行 cout”Test is end!”endl; / /H行运行结果及分析运行结果及分析运行结果:运行结果:This is a Test!+a=1Test is end! 程序分析:程序分析:1、本程序主要是展示trycatch语句的使用;程序的结构是由try和两个catch语句构成,其中:两个catch语句是并列的。2、程序的执行是从按从上往下的顺序依次进行的,当执行到程序中的A行时,throw语句抛出了一个异常,这个异常的数据类型是int,值为1。程序转而去执行catch语句,而程序中的

39、B行将不会执行。 运行结果及分析运行结果及分析3、两个catch语句哪个能执行呢?系统处理方法为:按照从上往下的顺序去看哪catch语句中的数据类型和throw抛出的数据类型相同,即首先判断程序中的C行中的catch语句中的数据类型是不是int,结果不是。程序将找到第二个catch语句,即程序中的E行,结果类型相同,并且有一个变量a。系统将对a进行赋值,即a=1;程序将继续执行F行,并输出a的值。结束了整个trycatch语句的执行。4、程序中的G行,为catch语句中的“异常类型名”表示为三个点的形式,即表示捕获所有的异常,注意是从上往下查找catch语句时,找不到匹配的数据类型,系统将执行

40、此catch中的语句块,如果找到,则不会执行此条语句。5、在执行完trycatch语句后,系统将按照顺序执行后面的语句,即执行程序中的H行,执行完后整个程序执行结束。 trycatch语句是可以嵌套的,当某语句的执行中抛出异常时,首先在包含它的最内层的try语句块对应的catch块列表中查找与之匹配的处理块,如果内层的catch块列表类型都不能匹配,即不能捕获到相应异常,则逐步向外层进行查找。具体如下图所示: 3、trycatch语句的嵌套 举例举例 【例例10-9】试分析下面程序的输出结果 。#includevoid main()try /A行try /B行throw a; /C行coutf

41、irst!endl; /D行catch(char) /E行throw; /F行coutsecond!endl; /G行catch (.) /H行cout抛出异常!endl; /I行运行结果及分析运行结果及分析运行结果:运行结果:抛出异常! 程序分析:程序分析:1、程序中是trycatch语句的嵌套使用,从A行处开始有一个trycatch语句,第二个trycatch语句从B行处开始,位于第一个trycatch语句的内部。2、程序执行是按顺序,从上往下依次执行,当执行到C行时,系统抛出异常,异常类型为字符型,首先由同一级的catch语句进行捕获,即由程序中的E行经检查数据类型后,匹配成功程序转而执

42、行该catch语句块。因此,D行程序不会执行。3、当执行到F行时,系统又抛出一个异常,而在同级别中没有相应的catch语句进行捕获,因此,系统转而到外层的catch语句中去查找,因此,找到了H行。4、H行的catch语句用的是三个点,系统把它处理成“通配符”,表示捕获所有类型的异常,因此,系统执行I行。执行完成后,系统即结束。 举例举例 【例例10-10】试编写程序,处理一个求两个数据相除的函数,在进行调用时除数为0时的异常 。分析:分析:当函数调用进行求两个数据的除数时,如果分母为0,则应用throw抛出此异常,在主函数就应该用trycatch语句来捕获,并在catch语句中进行相应的处理。

43、 #include double fun(double x, double y) /函数的定义 if (y=0) throw y; /当除数为0时,抛出异常 return x/y; /否则,返回两个数的商 void main() double res; try /定义异常开始 res=fun(2,3); /函数调用 coutThe result of x/y is : resendl; res=fun(4,0); /此次调用会产生异常,函数内部将抛出异常 catch(double) /捕获并处理异常 cerrerror of dividing zero.n; exit(1); /异常退出程序 举例举例 【例例10-11】试定义两个异常类来处理给定数据范围条件下的除法运算。要求:异常类的基类用于处理零除数;异常类的派生类则用于处理数据过大或者数据过小时的异常。先通过检查数据进行处理:当数据超过最大值或者低于最

温馨提示

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

评论

0/150

提交评论