38、不一样的C++系列--C++的异常处理
来源:互联网 发布:宜人贷淘宝验证不了 编辑:程序博客网 时间:2024/06/07 10:04
C++的异常处理
异常处理介绍
C++内置了异常处理的语法元素 try … catch …
- try语句处理正常代码逻辑
- catch语句处理异常情况
- try语句中的异常由对应的catch语句处理
- 语法:
try{ double r = divide(1, 0);}catch(...){ cout << "Divided by zero..." << endl;}
- C++通过throw语句抛出异常信息
double divide(double a, double b){ const double delta = 0.0000000000001; double ret = 0; if(!((-delta < b) && (b < delta))) { ret = a / b; } else { //产生除0异常 throw 0; } return ret;}
异常处理分析
- 这里对C++异常处理分析一下:
- throw抛出的异常必须被catch处理
- 当前函数能够处理异常,程序继续往下执行
- 当前函数无法处理异常,则函数停止执行,并返回
- throw抛出的异常必须被catch处理
未被处理的异常会顺着函数调用栈向上传播,知道被处理为止,否则程序将停止执行。
function1 ==> function2 ==> function3 <== <== throw1;
这里举一个例子:
#include <iostream>#include <string>using namespace std;double divide(double a, double b){ const double delta = 0.000000000000001; double ret = 0; if( !((-delta < b) && (b < delta)) ) { ret = a / b; } else { //用throw抛出异常信息 throw 0; } return ret;}int main(int argc, char *argv[]){ try { double r = divide(1, 0); cout << "r = " << r << endl; } catch(...) { //try语句中抛出的异常在这里接受并处理 cout << "Divided by zero..." << endl; } return 0;}
继续学习 try… catch …的知识点:
同一个try 语句可以跟上多个catch语句
- catch语句可以定义具体处理的异常类型
- 不同类型的异常由不同的catch语句负责处理
- try语句中可以抛出任何类型的异常
- catch( … ) 用于处理所有类型的异常
- 任何异常都只能被捕获(catch)一次
异常处理的匹配规则:
//异常处理匹配时,不进行任何的类型转换| try| {| throw 1;| } | catch(Type1 t1)| {| }| catch(Type2 t2)| {| }| catch(TypeN tn)| {| }v异常抛出后,自上而下严格匹配每一个catch语句处理的类型
这里用一个例子来试验一下匹配规则:
#include <iostream>#include <string>using namespace std;void Demo1(){ try { //这里抛出一个字符 throw 'c'; } catch(char c) { cout << "catch(char c)" << endl; } catch(short c) { cout << "catch(short c)" << endl; } catch(double c) { cout << "catch(double c)" << endl; } catch(...) { cout << "catch(...)" << endl; }}void Demo2(){ //这里抛出string类字符串 throw string("D.T.Software");}int main(int argc, char *argv[]){ Demo1(); try { Demo2(); } catch(char* s) { cout << "catch(char *s)" << endl; } catch(const char* cs) { cout << "catch(const char *cs)" << endl; } catch(string ss) { cout << "catch(string ss)" << endl; } return 0;}
执行结果如下:
catch(char c)catch(string ss)
catch再抛出异常
在try … catch … 语句中,catch语句块中可以抛出异常
try{ func();}catch(int i){ //将捕获的异常重新抛出 throw i;}catch(...){ //将捕获的异常重新抛出 throw;}//catch中抛出的异常需要外层的try ... catch ...捕获
可是为什么要重新抛出异常呢?因为:
catch中捕获的异常可以被重新解释后抛出,这样就可以在工程开发中使用这样的方式统一异常类型。
//工程开发通过调用 MyFunc 获得 func函数的功能和统一的异常信息 | | 调用 V//私有库void MyFunc(int i);/*异常类型为Exception*/ | | 封装 V//第三方库void func(int i);/*异常类型为int*/
这里举一个例子:
#include <iostream>#include <string>using namespace std;void Demo(){ try { try { //这里抛出的异常由内层try ... catch ...来捕获处理 throw 'c'; } catch(int i) { cout << "Inner: catch(int i)" << endl; //这里再次抛出的异常由外层来捕获并处理 throw i; } catch(...) { cout << "Inner: catch(...)" << endl; //这里再次抛出的异常由外层来捕获并处理 throw; } } catch(...) { cout << "Outer: catch(...)" << endl; }}/* 假设: 当前的函数式第三方库中的函数,因此,我们无法修改源代码 函数名: void func(int i) 抛出异常的类型: int -1 ==》 参数异常 -2 ==》 运行异常 -3 ==》 超时异常*/void func(int i){ if( i < 0 ) { throw -1; } if( i > 100 ) { throw -2; } if( i == 11 ) { throw -3; } cout << "Run func..." << endl;}void MyFunc(int i){ try { func(i); } catch(int i) { switch(i) { case -1: throw "Invalid Parameter"; break; case -2: throw "Runtime Exception"; break; case -3: throw "Timeout Exception"; break; } }}int main(int argc, char *argv[]){ Demo(); try { MyFunc(11); } catch(const char* cs) { cout << "Exception Info: " << cs << endl; } return 0;}
运行结果为:
Inner: catch(...)Outer: catch(...)Exception Info: Timeout Exception
自定义异常类型
自定义类类型及匹配:
- 异常的类型可以是自定义类类型
- 对于类类型异常的匹配依旧是自上而下严格匹配
- 赋值兼容性原则在异常匹配中依然适用
- 一般而言
- 匹配子类异常的catch放在上部
- 匹配父类异常的catch放在下部
工程中的异常类:
- 在工程中会定义一系列的异常类
- 每个类代表工程中可能出现的一种异常类型
- 代码复用时可能需要重解释不同的异常类
- 在定义 catch语句块时推荐使用引用作为参数
这里举一个例子:
#include <iostream>#include <string>using namespace std;class Base{};class Exception : public Base{ int m_id; string m_desc;public: Exception(int id, string desc) { m_id = id; m_desc = desc; } int id() const { return m_id; } string description() const { return m_desc; }};/* 假设: 当前的函数式第三方库中的函数,因此,我们无法修改源代码 函数名: void func(int i) 抛出异常的类型: int -1 ==》 参数异常 -2 ==》 运行异常 -3 ==》 超时异常*/void func(int i){ if( i < 0 ) { throw -1; } if( i > 100 ) { throw -2; } if( i == 11 ) { throw -3; } cout << "Run func..." << endl;}void MyFunc(int i){ try { func(i); } catch(int i) { switch(i) { case -1: //这里直接抛出一个类 throw Exception(-1, "Invalid Parameter"); break; case -2: //这里直接抛出一个类 throw Exception(-2, "Runtime Exception"); break; case -3: //这里直接抛出一个类 throw Exception(-3, "Timeout Exception"); break; } }}int main(int argc, char *argv[]){ try { MyFunc(11); } //接受到的时候 判断为引用类型 catch(const Exception& e) { cout << "Exception Info: " << endl; cout << " ID: " << e.id() << endl; cout << " Description: " << e.description() << endl; } //接受到的时候 判断为引用类型 catch(const Base& e) { cout << "catch(const Base& e)" << endl; } return 0;}
运行结果为:
Exception Info: ID: -3 Description: Timeout Exception
C++标准库的异常类族
在C++标准库中提供了实用异常类族
- 标准库中的异常都是从 exception 类派生的
- exception 类有两个主要的分支
- logic_error
- 常用于程序中的可避免逻辑错误
- runtime_error
- 常用于程序中无法避免的恶性错误
- logic_error
这里演示一下如何使用:
#include <iostream>#include <string>#include "Array.h"#include "HeapArray.h"using namespace std;void TestArray(){ Array<int, 5> a; /* 这里如果越界会抛出异常: throw out_of_range("T& Array<T, N>::operator[] (int index)"); throw out_of_range("T Array<T, N>::operator[] (int index) const"); */ for(int i=0; i<a.length(); i++) { a[i] = i; } for(int i=0; i<a.length(); i++) { cout << a[i] << endl; }}void TestHeapArray(){ HeapArray<double>* pa = HeapArray<double>::NewInstance(5); if( pa != NULL ) { HeapArray<double>& array = pa->self(); /* 这里如果越界会抛出异常: throw out_of_range("T& HeapArray<T>::operator [] (int index)"); throw out_of_range("T HeapArray<T>::operator [] (int index) const"); */ for(int i=0; i<array.length(); i++) { array[i] = i; } for(int i=0; i<array.length(); i++) { cout << array[i] << endl; } } delete pa;}int main(int argc, char *argv[]){ try { TestArray(); cout << endl; TestHeapArray(); } catch(...) { cout << "Exception" << endl; } return 0;}
小结
- C++中直接支持异常处理的概念
- try … catch …是C++中异常处理的专用语句
- try 语句处理正常代码逻辑,catch 语句处理异常情况
- 同一个 try 语句可以跟上多个 catch 语句
- 异常处理必须严格匹配,不进行任何的类型转换
- catch语句块中可以抛出异常
- 异常的类型可以是自定义类类型
- 赋值兼容性原则在异常匹配中依然适用
- 标准库中的异常都是从exception类派生的
阅读全文
0 0
- 37、不一样的C++系列--C语言异常处理
- 38、不一样的C++系列--C++的异常处理
- 1、不一样的C++系列--C到C++的升级
- C语言的异常处理
- C语言的异常处理
- C语言的异常处理
- c的异常处理学习
- C++&Qt的异常处理
- Objective C 不一样的语法
- 1 不一样的 C 基础
- 不一样的C语言-变量
- 不一样的随机数生成方法(C/C++)
- c系列之异常的抛出
- 异常处理(二、C语言的异常处理)
- C/C++异常处理的对比
- object-c的异常处理机制
- 神奇的C语言五:异常处理
- c/c++的异常统一处理
- 【二十一】Docker-创建自己的Docker镜像
- HttpClientUtil实现post、get请求
- JavaScript进阶设计模式系列——基础篇——this-call-apply
- 洛谷1125 笨小猴
- JAVA WEB 后台开发自己用的UI admin 框架
- 38、不一样的C++系列--C++的异常处理
- Codeforces Gym 101190 (NEERC 2016) E. Expect to Wait (扫描线)
- 文章标题
- Java-解析XML
- CreateEvent 自动复位和手动复位的区别
- 【Swift】 Collections初识
- jQuery对象和javascript的对象的转化
- spring原理
- 开启动画用start