博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++
座右铭:“不要等到什么都没有了,才下定决心去做”
大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点
目录
C++异常处理的实现
try的嵌套异常处理语句
异常与函数
异常类
C++处理异常的机制由三个部分组成:检查(try)、抛出(throw)和捕捉(catch)。把需要检查的语句放在try块中,throw用来当出现异常时抛出一个异常信息,而catch则用来捕捉异常信息,如果捕捉到异常信息,就处理它。try-throw-catch构成了C++异常处理的基本结构
例如:
try { ... if(表达式1) throw x1; ... if(表达式2) throw x1; ... if(表达式n) throw xn; ... } catch(异常类型声明1) { 异常类型语句序列1 } catch(异常类型声明2) { 异常类型语句序列2 } ... catch(异常类型声明n) { 异常类型语句序列n }
这里,try语句块内为需要受保护的待检测异常的语句序列,如果怀疑某段程序代码在执行时有可能发生异常,就将它放入try语句块中。当这段代码执行出现异常时,即某个if语句的表达式为真时,会用其中的throw语句来抛出这个异常
例如:
throw语句的语法格式 throw 表达式;
throw语句是在程序执行发生了异常时用来抛出这个异常的,其中表达式的值可以是int,float,字符串,类类型等,把异常抛给相应的处理者,即类型匹配的catch语句块。如果程序中多处需要抛出异常,应该用不同类型的操作数来互相区别。throw抛出的异常,通常是被catch语句捕获
catch语句块是紧跟在try语句后面的,即try块和catch块作为一个整体出现,在一个try-catch结构中,可以只有try而无catch块。即在本函数中只检查异常而不处理异常,把catch块放在其他函数中。一个try-catch结构try只能有一个,但可以有多个catch块,以便于与不同类型的异常信息匹配。在执行try块中的语句时如果出现异常执行了throw语句,系统会根据throw抛出的异常信息类型按catch块出现的次序,一次检查每一个catch参数表中的异常声明类型与抛出的异常信息类型是否匹配,若匹配,该catch块就会捕获这个异常,执行catch块中的异常处理语句来处理异常
在catch参数表中,一般只写异常信息的类型名,如,catch(double)
系统检查所抛出的异常信息类型是否与catch参数表中的异常声明类型相匹配,而不检查它们的值。假如变量a,b,c都是int类型,即使它们的值不同,在throw语句中写throw a、throw b、throw c的作用均是相同的。因此,如果需要检测多个不同的异常信息,应当由throw抛出不同类型的异常信息。
异常信息类型可以是C++系统预定义的标准类型,也可以是自己定义的类型(如结构体或类)。如果有throw抛出的异常信息属于该类型或其子类型,则catch与throw二者匹配,catch捕获异常信息。
注意:系统在检查异常信息数据类型的匹配时,不会进行数据类型的默认转换,只有与所抛的异常信息类型精度匹配的catch块才会捕获这个异常
在catch参数表中,除了指定异常信息的类型名以外,还可以是变量名,如:catch(double d)。此时,若throw抛出的异常信息是double型变量 a,则catch在捕获异常信息a的同时,还使d获得a的值。如果希望在捕获异常信息时,还能利用throw抛出的异常信息的值,这时就需要在catch参数表中写出变量名。
例如:
catch(double d) { cout<<"throw "<
求解一元二次方程ax^2+bx+c=0。其一般解为x1=(-b+(b^2-4ac))/2a,x2=x1=(-b-(b^2-4ac))/2a,但若a=0或b^2-4ac<0时,用此公式计算就会出错。从键盘输入a,b,c的值,求x1,x2。如果a=0或b^2-4ac<0,输出错误信息
#include
#include using namespace std; int main() { double a,b,c; double disc; cout<<"Please Enter a,b,c:"; cin>>a>>b>>c; try { if(a==0) { throw 0;// } else { disc=b*b-4*a*c; if(disc<0) { throw "b*b-4*a*c<0"; } cout<<"x1="<<(-b+sqrt(disc))/2*a< (1)首先在try后面的大括号中放置上可能出现异常的语句块或程序段
(2)程序运行时将按正常的顺序执行到try块,执行try块中大括号的语句。如果在执行try块内的语句过程中没有发生异常,则忽略所有的catch块,流程转到catch块后面的语句继续执行。例如,上述代码中结果(1)的情况
(3)如果在执行try块内的语句过程中发生异常,则由throw语句抛出一个异常信息。throw抛出什么样的异常取决于自己怎么设计,可以是任何类型的异常。例如,上述代码中抛出的就是字符类型和整形的异常
(4)这个异常信息提供给try-catch结构,系统会查找与之匹配的catch块。若某个catch参数表中的异常声明类型与抛出的异常类型匹配,该catch块就捕获这个异常,执行catch块中的异常处理语句。只要有一个catch捕获捕获了异常,其余的catch块将被忽略。例如,上述代码运行结果的(2)的情况,由try块内的throw语句抛出一个整形异常,被第一个catch捕获,上述代码运行结果的(3)的情况,由try块内的throw语句抛出一个字符串类型异常,被第二个catch捕获
当然,异常类型可以声明为省略号(...),表示可以处理任何类型的异常,注意的是,catch(...)应该放在最后面,如果放在前面,就可以捕获任何异常,那么后面的catch语句块就不会检查和执行了。
(5)在进行异常处理后,程序不会自动终止,继续执行catch块后面的语句
(6)如果throw抛出异常信息找不到与之匹配的catch块,则系统会调用一个系统函数terminate,在屏幕上显示"abnormal praogram termination"。并终止程序的运行
(7)抛出异常信息的throw语句可以与try-catch结构出现在一个函数中,也可以不出现在同一个函数中。这种情况下,当throw抛出异常信息后,首先在本函数中查找与之配对的catch块,如果在本函数中try-catch结构或者没有与之配对的catch块,就转到离开出现异常最近的try-catch结构去处理
例如:
#include
#include using namespace std; double sort_1(double a,double b,double c) { double disc=b*b-4*a*c; if(a==0) { throw a; } else { if(disc<0) { throw "b*b-4*a*c<0"; } return disc; } } int main() { double a,b,c; double disc; cout<<"Please Enter a,b,c:"; cin>>a>>b>>c; try { disc=sort_1(a, b, c); cout<<"x1="<<(-b+sqrt(disc))/2*a< (8)异常处理还可以应用函数嵌套。
例如:
#include
using namespace std; void func2() { double a=0; try { throw a; } catch(float) { cout<<"OK2!"< 第四种情况与第三种情况不同的是:第四种情况cout<<"OK1!"<
例如:
throw ;
此时它将当前正在处理的异常信息再次抛出。再次抛出的异常不会被同一层的catch块捕获,它将被传递给上一层的catch块处理。
修改后的func1函数中的catch块捕获throw抛出的异常信息a,输出"OK1!",但它立即用"throw;"将a再次抛出。被main函数中的catch块捕获,输出"OK0!",执行完毕后继续执行main函数中的catch块后面的语句,输出"end0",程序结束。
注意:只能从catch块再次抛出异常,这中方式有利于构成对同一异常的多层处理机制,使异常能够在恰当的地方被处理,增强异常处理的能力
try的嵌套异常处理语句
在一个try块中可以嵌套另一个try块。每个块都有自己的一组catch块,来处理在try中抛出的异常。try块的catch块只能处理在该try块中抛出的异常。
例如:
try { ...//外层的try语句 try { ...//内层的try语句 } catch(elemtype a)//用来捕获内层try中抛出的异常 { ... } ... } catch(elemtype b)//用来捕获外层try中抛出的异常和在内层未捕获到的异常 { ... } ...
上面的语句中,每个try都有一个处理程序,当然,也可以有多个。在内层try块中的代码抛出一个异常时,其处理程序会首先处理它。内层try块的每个处理程序都会检查匹配的异常类型,如果这些处理程序都不匹配,外层try块的处理程序会捕获该异常。
异常与函数
异常处理可以化为一个函数,当每次进行该函数的调用时,异常将被重置。这样编写程序更加简便。
例如:
check是一个检测成绩异常的函数,当成绩达到100分以上或低于60分产生异常,60-100之间为正常成绩
#include
using namespace std; void check(int score) { try { if(score<60) { throw score; } else if(score>100) { throw score; } cout<<"分数正常"< 100) { cout<<"分数过高"< 异常类
用来传递错异常信息的类就是异常类。异常类可以非常简单,甚至没有任何成员;也可以同普通类一样。
#include
using namespace std; #define MAX 3 class Full { ; }; class Eempty { ; }; class Stack { public: Stack() { top=0; } void push(int a); int pop(); private: int s[MAX]; int top; }; void Stack:: push(int a) { if(top>=MAX) { throw Full(); } s[top]=a; top++; } int Stack:: pop() { if(top<=0) { Eempty e1; throw e1; // throw Eempty(); } return s[--top]; } int main() { Stack s1; try { s1.push(1); s1.push(2); s1.push(3); s1.push(4); cout<
如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家!