c++的异常处理
来源:互联网 发布:六年级上册优化答案 编辑:程序博客网 时间:2024/05/22 15:28
1. c++的异常处理介绍
c++的异常处理语法:
int main(void){ try { double a = div(6, 0); } catch(...) { printf("div 0 is error!!\n"); } return 0;}
如上try…catch两个语句块,将正常功能代码和异常处理代码在一个函数中分隔开,提高代码的可读性:try语句用于处理正常代码逻辑,catch语句用于处理异常情况,try语句中的异常由对应的catch语句处理。
在div()函数中,若发现除以0操作,可以通过throw语句抛出异常,并终止本函数运行:
double div(double a, double b){ double tmp = 0.00000001; if ((-tmp < b) && (b < tmp)) { throw 0; } else return a / b;}
编译运行:
在div()函数中抛出的异常必须被catch处理,当前函数能够处理异常,程序则继续往下执行,当前函数无法处理异常,则函数停止执行并返回。未被处理的异常会顺着函数调用栈向上抛出,直至被处理为止,
若直到main()函数都没有处理,那么程序将停止执行:
int main(void){ //try //{ double a = div(6, 0); //} //catch(...) //{ // printf("div 0 is error!!\n"); //} return 0;}
编译运行:
一个函数执行过程中可能会抛出多重类型的异常,那么也就意味着,一个try语句可以跟上多个catch。catch语句可以定义具体处理的异常类型,不同的类型的异常由不同的catch语句负责处理。代码中的catch(…)可用于处理所有类型的的异常,需要注意,任何异常都只能被捕获一次。
void exception_test1(){ try{ throw 'a'; } catch(char c) { printf("catch(char c)\n"); } catch(int i) { printf("catch(int i)\n"); } catch(double d) { printf("catch(double d)\n"); } catch(...) { printf("catch(...)\n"); }}int main(void){ exception_test1(); return 0;}
编译运行:
异常抛出后,编译器将自上而下严格匹配每一个catch语句处理的类型,异常处理会进行严格类型匹配,不会进行任何类型转换:
void exception_test2(){ throw std::string("hello");}int main(void){ try { exception_test2(); } catch(char* s) { printf("catch(char* s)\n"); } catch(const char* cs) { printf("catch(char* s)\n"); } catch(std::string ss) { printf("catch(std::string ss)\n"); } return 0;}
编译运行:
2. catch语句块抛出异常
前面讲到try语句块中可能会抛出异常,抛出的异常被当前函数或者函数调用栈的上一和函数的catch语句块处理。在catch语句块中,处理异常操作还可以是把异常再次抛出,catch抛出的异常需要外层的try…catch语句捕获。
在catch没有抛出异常的情景中:
void test_func(int i){ switch (i) { case 1: throw -1; break; case 2: throw -2; break; case 3: throw -3; break; default: break; } printf("void test_func(int i)\n");}int main(void){ try { test_func(2); } catch(int i) { printf("catch(int i), i = %d\n", i); } return 0;}
编译运行:
抛出异常为-2,此时对于程序调试者可能还尚未知道-2究竟是什么错误码。然而它并不知道test_func(int i)的源代码,只能通过另外的查询手段去获取-2是什么异常,所以说比较麻烦。在实际工程中,catch语句块捕获到的异常可以被重新解释后抛出,假设:
-1代表输入错误
-2代表通讯异常
-3代表其它错误
上面函数不动,增加run_test_func()函数:
void run_test_func(int i){ try{ test_func(i); } catch (int i) { if (i == -1) { throw "input error!"; } else if (i == -2) throw "communication erroe!"; else if ( i == -3) throw "error!"; }}
在main()函数中,try语句块调用run_test_func()函数,catch语句块捕获run_test_func()可能抛出的异常:
int main(void){ try { run_test_func(2); } catch(const char* s) { printf("%s\n", s); } return 0;}
编译运行:
这样就能对程序所抛出的异常类型一目了然。
3. 抛出类类型异常
异常的类型还可以是自定义的类类型,对于类类型的异常匹配规则依旧是从上而下严格匹配,但是注意,子父类的赋值兼容性原则在异常匹配中仍然适用,所以说匹配子类异常的 catch应该放在上面,匹配父类异常的chtch放在下面。
//异常的基类class exceptionBase{public:};class exceptionSub : public exceptionBase{private: int m_id; std::string desc_str;public: exceptionSub(int id, std::string str) : m_id(id), desc_str(str) {} int id() { return m_id; } std::string description() { return desc_str; }};void test_func(int i){ switch (i) { case 1: throw -1; break; case 2: throw -2; break; case 3: throw -3; break; default: break; } printf("void test_func(int i)\n");}void run_test_func(int i){ try{ test_func(i); } catch (int i) { if (i == -1) { //throw "input error!"; throw exceptionSub(-1, "input error!"); } else if (i == -2) //throw "communication erroe!"; throw exceptionSub(-2, "communication erroe!"); else if ( i == -3) //throw "error!"; throw exceptionSub(-3, "error!"); }}int main(void){ try { run_test_func(2); } catch(exceptionSub& ee) { printf("ID: %d\n", ee.id()); printf("description: %s\n", ee.description().c_str()); } catch(exceptionBase& ee) //因为支持赋值兼容性原则,所以父类类型应放在子类类型后面 { printf(" catch(exceptionBase& ee)\n"); } return 0;}
编译运行:
4. try…catch的两种特殊写法
(1) c++的函数声明和定义时可以直接指定可能抛出的异常类型,异常声明成为函数声明的一部分。这可以提高代码的可阅读性,如:
void func1(int i) trow(int) //表示该函数可能抛出int类型的异常{ //...}void func2(int i, char c) //表示该函数可能抛出int类型、char类型的异常{ //...}
需要注意的是,函数的异常声明是一种和编译器的协议,也就是说函数声明异常后就只能抛出所声明的类型的异常。
void func(int i) throw(int){ if (i > 5) throw -i;}int main(void){ try{ func(9); } catch(int i) { printf("exception: %d\n", i); } catch(...) { printf("catch(...)\n"); } return 0;}
编译运行正常:
尝试在声明抛出异常类型为int的func()函数中抛出char类型的异常:
void func(int i) throw(int){ if (i > 5) throw 'e';}
编译运行:
即使是在main()函数中有catch(…)代码用于捕捉所有异常,但是不起作用,func()函数违背了与编译器的协议了。
(2) try…catch的意义在于用于分隔正常功能代码与异常功能代码,这个分隔实现还可以写成这样:
void test_fun(int i) try{ func(i); printf("test_fun...\n");}catch(int i){ printf("test_fun, catch(int) = %d\n", i);}catch(...){ printf("test_fun, catch(...)\n");}int main(void){ test_fun(12); test_fun(4); return 0;
编译运行:
这样的写法会让初学者感觉try…catch处于两个函数一样,其实不然,它们跟前面写的在一个函数内实现的效果是一致的。
c++的异常先笔记到这里,下来看看c++标准库的异常类。
- C语言的异常处理
- C语言的异常处理
- C语言的异常处理
- c的异常处理学习
- C++&Qt的异常处理
- 异常处理(二、C语言的异常处理)
- C/C++异常处理的对比
- object-c的异常处理机制
- 神奇的C语言五:异常处理
- c/c++的异常统一处理
- object-c的异常处理机制
- object-c的异常处理机制
- 【C++】异常处理的简单应用。
- object-c的异常处理机制
- linux C 异常处理的方式
- 程序的异常处理(C#)
- object-c的异常处理机制
- Exception-异常处理(c++)的总结
- CPU使用率
- jsp/html页面图片上传并展示上传的图片
- NVIDIA Jetson TX1 系列开发教程之十一:TCP/IP文件传输
- caffe安装以及LeNet实现手写数字体识别
- 操作DOM
- c++的异常处理
- [排序] 希尔排序(Python)
- 穷举法
- 数学建模常规方法
- 二分图匹配水题列表
- John’s Inversions 2011-2012 ACM-ICPC, NEERC, Northern Subregional Contest
- 浅谈FloatingActionButton(悬浮按钮)
- 暂存杂记
- 设计模式学习(一)之设计模式简介