1.C++中的异常
C++异常处理语法元素try-catch语句
- try语句处理正常代码逻辑 (但有可能产生异常,产生异常时抛出异常并转到catch语句块里面的代码)
- catch语句处理异常情况
- try语句中的异常由对应的catch语句处理
- C++通过throw语句抛出异常信息(一般在try语句中)
throw和return区别
throw异常的返回一个值,这个值就代表了异常, 抛到catch语句块
return正常的返回一个值
C++异常处理分析
(1)throw抛出的异常必须被catch处理
- 当前函数能够处理异常(含有catch语句块),程序继续往下执行
- 当前函数无法处理异常,则函数停止执行,并返回,由上层函数进行处理了。
(2)未被处理的异常会顺着函数调用栈向上传播,直到被处理为止,否则程序将停止执行。如果一直未处理则会到main函数,该函数中若果仍没有try..catch语句直接退出
(3)同一个try语句可以跟上多个catch语句
①catch语句可以定义具体处理的异常类型
②不同类型的异常由不同的catch语句负责处理。
③try语句中可以抛出任何类型的异常
④catch(…)用于处理所有类型的异常
⑤任何异常都只能被捕获(catch)一次。
(4)异常处理的匹配规则
1 #include <iostream> 2 3 using namespace std; 4 5 double divide(double a, double b) 6 { 7 const double delta = 0.000000000000001; 8 double ret = 0; 9 10 if( !((-delta < b) && ( b < delta))){ 11 ret = a / b; 12 }else{ 13 throw 0; //产生除0异常 14 } 15 16 return ret; 17 } 18 19 //匹配规则(自上而下,严格匹配、不进行类型转换) 20 void Demo1() 21 { 22 try{ 23 throw 'c'; //抛出字符型的异常 24 }catch(int i){ 25 cout << "catch(int i)" << endl; 26 }catch(double d){ 27 cout << "catch(double d)" << endl; 28 }catch(char c){ //只能被这里的catch捕获 29 cout << "catch(char c)" << endl; 30 } 31 } 32 33 void Demo2() 34 { 35 throw "Demo2"; //const char* 36 } 37 int main() 38 { 39 cout << "main() begin" << endl; 40 41 try{ 42 double c = divide(1, 0);//产生异常 43 cout <<"c = " << c << endl; //无法被执行到! 44 }catch(...){ 45 cout << "Divide by zero..." << endl; 46 } 47 48 Demo1(); 49 50 try{ 51 Demo2(); 52 } 53 catch(char* c) 54 { 55 cout << "catch(char* c)" << endl; 56 } 57 catch(const char* c) 58 { 59 cout << "catch(const char* c)" << endl; 60 }catch(...) 61 { 62 //写位置最后 63 cout << "catch(...)" << endl; 64 } 65 66 cout << "main() end" << endl; 67 return 0; 68 }
2.异常类的构建
- 异常的类型可以是自定义的类类型
- 对于类类型异常的匹配依旧是至上而下严格匹配(不能强制类型的转换)
- 赋值兼容性原则(子类的对象可以直接复制给父类的对象,父类的指针可以直接指向子类的对象)在异常匹配中依然使用 (出现父类对象是可以用一个子类对象代替)
- 一般而言:
------匹配子类异常的catch放在上部
------匹配父类异常的catch放在下部
3、异常类族
现代C++库必然包含充要的异常类族
异常类族是数据结构类所以来的“基础设施”
顶层父类Exception是一个抽象类,不能定义对象,用于被继承的。
这一节就是实现这个抽象基类的。
目的:当程序抛出异常时(有可能会是一个字符串、文件名、行号),能够捕捉到这个异常,并打印处异常的信息等。
要实现的几个函数:
构造函数:对收到的异常进行初始化工作
1 Exception(const char* message); 2 Exception(const char* file,int line); 3 Exception(const char* message,const char* file,int line);
由于初始化工作差不多,为了代码整洁我们将相同的操作封装成了一个函数即:
void init(const char*,const char*,int);//由于三个构造函数中的逻辑很相似,所以可以将相似的部分统一放到一个函数init()
此外还需要保存一些初始化变量的成员变量
1 char* m_message;//m_message指向一个字符串,用于说明当前的异常信息 2 char* m_location;//m_location指向一个字符串,用于说明当前的异常位置
由于涉及到堆空间即需进行深拷贝,就不能使用默认的拷贝构造函数和赋值操作符,需要自己定义实现即
1 //涉及到堆空间即需进行深拷贝,拷贝构造函数和"=" 2 Exception(const Exception& e); 3 Exception& operator =(const Exception& e);
完整代码如下
Exception.h
1 #ifndef _EXCEPTION_H_ 2 #define _EXCEPTION_H_ 3 namespace DataStructureLib 4 { 5 6 class Exception 7 { 8 protected: 9 char* m_message; 10 char* m_location; 11 protected: 12 void init(const char*,const char*,int);//由于三个构造函数中的逻辑很相似,所以可以将相似的部分统一放到一个函数init() 13 public: 14 Exception(const char* message); 15 Exception(const char* file,int line); 16 Exception(const char* message,const char* file,int line); 17 18 //涉及到堆空间即需进行深拷贝,拷贝构造函数和"=" 19 Exception(const Exception& e); 20 Exception& operator =(const Exception& e); 21 22 virtual const char* message() const; 23 virtual const char* location() const; 24 25 virtual ~Exception(void); 26 }; 27 #endif 28 }
Exception.cpp
1 #include "Exception.h" 2 #include <cstring> 3 #include <cstdlib> 4 5 namespace DataStructureLib 6 { 7 void Exception::init(const char* message,const char* file,int line) 8 { 9 m_message=strdup(message);//这里不能直接使用m_message=message, 10 //因为message指针指向的数据有可能会在栈、堆、全局区,如果是在栈上,局部变量可能会消失,如果直接使用m_message=message就会不安全 11 if(file!=NULL) 12 { 13 char sl[16]={0}; 14 itoa(line,sl,10);//将line转为char类型 10代表十进制 15 16 m_location=static_cast<char* >(malloc(strlen(file)+strlen(sl)+2));//加2表示后面的":"和结束符即“/0” 17 m_location=strcpy(m_location,file); 18 m_location=strcat(m_location,":"); 19 m_location=strcat(m_location,sl); 20 } 21 } 22 23 Exception:: Exception(const char* message) 24 { 25 init(message,NULL,0); 26 } 27 28 Exception::Exception(const char* file,int line) 29 { 30 init(NULL,file,line); 31 } 32 33 Exception::Exception(const char* message,const char* file,int line) 34 { 35 init(message,file,line); 36 } 37 38 Exception::~Exception(void) 39 { 40 41 free(m_message); 42 free(m_location); 43 } 44 45 const char* Exception::message() const 46 { 47 return m_message; 48 } 49 50 const char* Exception::location() const 51 { 52 return m_location; 53 } 54 55 Exception::Exception(const Exception& e) 56 { 57 m_message=strdup(e.m_message); 58 m_location=strdup(e.m_location); 59 } 60 61 Exception& Exception::operator =(const Exception& e) 62 { 63 if (this!=&e) 64 { 65 free(m_message); 66 free(m_location); 67 68 m_message=strdup(e.m_message); 69 m_location=strdup(e.m_location); 70 } 71 return *this; 72 } 73 74 }
测试:
#include<iostream> #include "SmartPointer.h" #include "Exception.h" using namespace std; using namespace DataStructureLib; int main(int argc,char* argv[]) { try { throw(Exception("test",__FILE__,__LINE__)); } catch (const Exception& e) { cout<<e.message()<<endl; cout<<e.location()<<endl; } return 0; }
结果: