程序执行中需要处理异常
- 动态分配空间时可能不会成功
- 打开文件可能会失败
- 除法运算时分母可能为0
- 整数相乘可能溢出
- 指针可能越界
- ……
异常处理方法一
- 使用选择语句(if…else…)
- 判断异常情况,即时处理
- 正常程序流程和异常处理语句混在一起
- 程序员往往无法专注于正常流程编程
异常处理方法二
- 使用C++异常处理机制
- 判断异常情况,发现异常后抛出异常
- 正常程序流程和异常处理模块分开
- 程序员可以专注于正常流程编程,异常处理模块稍候编写
C++异常处理机制
- 程序在产生错误后抛出异常
- 异常处理模块捕获并处理异常
- 异常处理机制一般无法使程序恢复正常执行
- 可以为程序提供有序的整理操作
异常处理基础
- 关键字try:出错时产生异常的代码放在try块中
- 关键字throw:throw语句可以抛出任意类型的异常,包括自定义类型
- 关键字catch:catch块(异常处理器)捕捉和处理异常
- 一个异常处理器一般只捕捉一种类型的异常
- try块抛出异常后,程序控制离开try块
- 抛出异常后,程序在try块后面的catch块中逐个搜索合适的异常处理器
- 如果try块没有异常抛出,则程序跳过所有catch块
- 抛出异常之后,程序控制无法返回到抛出点
- try块可以直接或间接抛出异常
例子1:除数为零的异常处理
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44// ex17_1.cpp: 除数为零的异常例子 #include <iostream> #include <string> using namespace std; //定义异常类MyException class MyException { public: MyException(char *str) { msg = str; } char * show() { return msg; } private: char *msg; }; //定义除法函数division,除数为0时抛出异常。 double division(int dividend, int divisor) { if (divisor == 0) //抛出异常对象 throw MyException("error: divided by zero!"); return (double)dividend/divisor; } int main() { int a, b; double result; cout<<"Enter two integers (EOF to end):"; while (cin>>a>>b){ try { result = division(a,b); cout<<a<<" / "<<b<<" = "<<result<<endl; } catch (MyException e) { cout<<e.show()<<endl; } cout<<endl; cout<<"Enter two integers (EOF to end):"; } return 0; }
程序运行结果
Enter two integers (EOF to end):12 7
12 / 7 = 1.71429
Enter two integers (EOF to end):2 0
error: divided by zero!
Enter two integers (EOF to end):34 5
34 / 5 = 6.8
Enter two integers (EOF to end):
异常的抛出和传播
- 关键字throw可以带任何类型的操作数,包括自定义类型(异常对象)
- 异常抛出后,最近的一个匹配的异常处理器捕获该异常
- 如果没有匹配的异常处理器,则系统调用terminate函数,terminate函数省却地调用abort函数终止程序的执行
- 抛出异常时,throw语句生成异常对象的一个副本,异常处理器执行完毕后删除该临时对象
例子2:编写程序抛出各类异常,并捕捉它们
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42// ex17_2.cpp: 抛出多种类型异常的例子 #include <iostream> using namespace std; main() { int a, myint; float myfloat; double mydouble; cout<<"Enter a integer (EOF to end):"; while (cin>>a){ //抛出不同类型的异常 try { switch(a % 3) { case 0: //输入整数为3的倍数时抛出整型异常 myint = a; throw myint; break; case 1: //抛出float类型异常 myfloat = (float)a; throw myfloat; break; case 2: //抛出double类型异常 mydouble = a; throw mydouble; break; default: break; } } catch (int e) { //捕获整型异常 cout<<"Integer Exception: "<<e<<endl; } catch (float e) { //捕获浮点类型异常 cout<<"Float Exception: "<<e<<endl; } catch (double e) { //捕获双精度类型异常 cout<<"Double Exception: "<<e<<endl; } cout<<endl; cout<<"Enter a integer (EOF to end):"; } return 0; }
程序运行结果
Enter a integer (EOF to end):10
Float Exception: 10
Enter a integer (EOF to end):11
Double Exception: 11
Enter a integer (EOF to end):12
Integer Exception: 12
Enter a integer (EOF to end):13
Float Exception: 13
Enter a integer (EOF to end):
- 异常只能在try块中抛出,并由其后的符合类型的catch块捕捉
- 在try块外面抛出的异常将不会被捕捉到,系统会调用terminate函数终止程序的运行
- 发生异常后跳出抛出异常的程序块,并且无法再返回到抛出点
- 异常可以在try块中显式抛出,也可以在其调用的函数中抛出
try块可以嵌套
内层try块抛出异常的传播顺序
- 先在内层try块后面的catch块中寻找合适的异常处理器
- 找到则进行处理,异常不再往外传播
- 如果找不到,则将该异常向外传播,到外层try块后面的catch块中继续寻找
- 如果异常传播到最外层的try块仍然找不到,则程序调用terminate函数
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41// ex17_3.cpp: 异常传播的例子。 #include <iostream> using namespace std; int add(int a, int b) { //结果过大过小时都抛出异常 int res; try { res = a + b; if (res > 128) //抛出整型异常 throw res; if (res<0) //抛出字符串异常 throw "Negative result!"; } catch (int e) { //捕捉整型异常 cout<<"The result is too large :"<<e<<endl; return -1; } return res; } int main() { int a, b, result; cout<<"Enter two integers (EOF to end):"; while (cin>>a>>b){ try { result = add(a, b); if (result >= 0) cout<<"The result is "<<result<<endl; } catch (...) { //捕捉传播到外层的所有异常 cout<<"Unexpected exception."<<endl; } cout<<endl; cout<<"Enter a integer (EOF to end):"; } return 0; }
程序运行结果
Enter two integers (EOF to end):12 66
The result is 78
Enter a integer (EOF to end):23 456
The result is too large :479
Enter a integer (EOF to end):-123 34
Unexpected exception found.
Enter a integer (EOF to end):
异常的捕获和处理
- 异常处理器以关键字catch开始
- 异常处理器能带一个参数(能捕捉的异常类型),参数名可选
- 有参数名时,可以在异常处理器内使用这个参数,该参数只是抛出的异常对象的一个副本catch (int e){…}
- 没有参数名时,异常对象不从抛出点传递到异常处理器中catch (int){…}
- 程序按顺序寻找匹配的异常处理器,抛出的异常将第一个类型符合的异常处理器捕获
- 如果内层try块后面没有找到合适的异常处理器,该异常向外传播,到外层try块后面寻找
- 没有被捕获的异常将调用terminate函数,terminate函数默认调用abort终止程序的执行
- 可以使用set_terminate函数指定terminate函数将调用的函数
- 参数列表中只有一个省略号的异常处理器能捕捉所有类型的异常catch (...) {...}
- 要注意异常处理器的排列顺序,可能会影响异常处理的结果
满足下面条件之一时,异常被捕捉
- 异常处理器的参数类型和抛出异常的类型完全相同
- .异常处理器的参数类型是抛出的异常对象的基类
- 异常处理器的参数是基类的指针或引用,抛出异常的类型是派生类的指针或引用
- 异常处理器的参数是void*类型的指针,抛出异常的类型是某一种类型的指针
- 异常处理器为catch(…)
例子4:异常捕获的例子
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//file ex17_4.h #include <iostream> using namespace std; //定义基类 class base { public: void show() { cout<<"Base object."<<endl; } }; //定义派生类 class derived :public base { public: void show() { cout<<"Derived object."<<endl; } };
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27// ex17_4.cpp: 抛出基类和派生类异常 #include "ex17_4.h" main() { int no; cout<<"Input a integer please:"; while(cin>>no) { try { if ((no % 2) == 0) //抛出基类对象 throw base(); else //抛出派生类对象 throw derived(); } catch(base b) { cout<<"Exception:"; b.show(); } catch(derived d) { cout<<"Exception:"; d.show(); } cout<<endl<<"Input a integer please:"; } return 0; }
程序运行结果
Input a integer please:1
Exception:Base object.
Input a integer please:2
Exception:Base object.
Input a integer please:3
Exception:Base object.
Input a integer please:4
Exception:Base object.
Input a integer please:
最后
以上就是无聊八宝粥最近收集整理的关于C++学习笔记之异常的全部内容,更多相关C++学习笔记之异常内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复