C++ try catch异常处理语句的用法(附带实例)
异常信号抛出后,一旦被异常处理器接收到就会被销毁。C++ 程序中,异常处理器通常紧跟在 try 语句后,处理方法由关键字 catch 引导。
下面通过 try…catch 语句捕获一个异常,程序代码如下:
通过 throw 关键字抛出异常时需指定这两个参数。注意,throw 语句可以直接写在 try 语句块的内部,也可以写在函数或类方法的内部,再将函数或方法写在 try 语句块内部。
捕获异常时,异常处理器还可以成组出现,根据捕获到的不同信息进行不同的处理。例如:
有时无法在列出的异常处理中包含所有可能发生的异常类型,C++ 提供了可以处理未知类型异常的方法,就是在 catch 后面的括号内添加“…”。程序代码如下:
有时需要重新抛出刚接收到的异常,尤其在程序无法得到相关异常信息而用省略号表示时。重新抛出异常可通过不带参数的 throw 语句完成。例如:
异常匹配并不要求异常与异常处理器进行完美匹配,一个对象或一个派生类对象的引用将与基类处理器进行匹配。若抛出的是类对象的指针,则会匹配相应的对象类型,但不会自动转换成其他对象的类型。例如:
下面看下基类处理器如何捕获派生类的异常:
下面通过 try…catch 语句捕获一个异常,程序代码如下:
#include<iostream> #include <string> using namespace std; class CCustomError // 定义异常类 CCustomError { private: int m_ErrorID; // m_ErrorID 表示异常 ID char m_Error[255]; // m_Error 表示异常信息 public: CCustomError() // 构造函数 { m_ErrorID = 1; strcpy(m_Error,"出现异常!"); } int GetErrorID() // GetErrorID() 方法,用于获取异常 ID { return m_ErrorID; } char *GetError() // 重载 GetErrorID() 方法,用于获取异常信息 { return m_Error; } }; int main(int argc, char *argv) { try // 检测异常 { throw (new CCustomError()); // 抛出异常 } catch(CCustomError *error) // 捕获异常 { // 输出异常信息 cout << "异常 ID: " << error->GetErrorID() << endl; cout << "异常信息:" << error->GetError() << endl; } return 0; }程序中定义了一个异常类,该类包含两个内容:
- 一个是异常 ID,即异常信息的编号;
- 另一个是异常信息,即异常的说明文本。
通过 throw 关键字抛出异常时需指定这两个参数。注意,throw 语句可以直接写在 try 语句块的内部,也可以写在函数或类方法的内部,再将函数或方法写在 try 语句块内部。
捕获异常时,异常处理器还可以成组出现,根据捕获到的不同信息进行不同的处理。例如:
int main(int argc, char *argv) { try { throw "字符串异常!"; // throw (new CCustomError()); // 抛出异常 } catch(CCustomError *error) // 捕获异常1 { cout << "异常 ID:" << error->GetErrorID() << endl; cout << "异常信息:" << error->GetError() << endl; } catch(char *error) // 捕获异常2 { cout << "异常信息:" << error << endl; } return 0; }
有时无法在列出的异常处理中包含所有可能发生的异常类型,C++ 提供了可以处理未知类型异常的方法,就是在 catch 后面的括号内添加“…”。程序代码如下:
int main(int argc, char *argv) { try { throw "字符串异常!"; // 抛出字符串异常 // throw (new CCustomError()); // 抛出 CCustomError 类异常 } catch(CCustomError *error) // 捕获异常1 { cout << "异常ID:" << error->GetErrorID() << endl; cout << "异常信息:" << error->GetError() << endl; } catch(char *error) // 捕获异常2 { cout << "异常信息:" << error << endl; } catch(...) // 捕获未知异常 { cout << "未知异常信息!" << endl; } return 0; }
有时需要重新抛出刚接收到的异常,尤其在程序无法得到相关异常信息而用省略号表示时。重新抛出异常可通过不带参数的 throw 语句完成。例如:
catch (...) { cout << "未知异常!" << endl; throw; }如果 catch 语句忽略了某个异常,该异常将进入更高层级的异常处理器。每个异常抛出的对象都会被保留,因此更高层的异常处理器可抛出来自这个对象的所有信息。
异常匹配
当程序中有异常抛出时,异常处理系统根据异常处理器的顺序找到最近的异常处理块,并不会搜索更多的异常处理块。异常匹配并不要求异常与异常处理器进行完美匹配,一个对象或一个派生类对象的引用将与基类处理器进行匹配。若抛出的是类对象的指针,则会匹配相应的对象类型,但不会自动转换成其他对象的类型。例如:
class CExcept1 {}; class CExcept2 { public: CExcept2(CExcept1& e) {} }; int main(int argc, char *argv) { try { throw CExcept1(); // 抛出异常 } catch (CExcept2) // 捕获异常1 { printf("进入 CExcept2 异常处理器!\n"); } catch(CExcept1) // 捕获异常2 { printf("进入 CExcept1 异常处理器!\n"); } return 0; }程序中,第一个异常处理器使用构造函数进行转换,将 CExcept1 转换为 CExcept2 对象,但实际上系统在异常处理期间并不执行这样的转换,而是在 CExcept1 处终止。
下面看下基类处理器如何捕获派生类的异常:
#include<iostream> using namespace std; class CExcept { public: virtual char *GetError() { return "基类处理器"; } }; class CDerive : public CExcept { public: char *GetError() { return "派生类处理器"; } }; int main(int argc, char *argv) { try { // 抛出异常 throw CDerive(); } catch(CExcept) // 捕获异常 { cout << "进入基类处理器\n"; } catch(CDerive) // 捕获异常 { cout << "进入派生类处理器\n"; } return 0; }程序中,虽然抛出的异常是 CDerive 类,但异常处理器的第一个是 CExcept 类,该类是 CDerive 类的基类,因此将进入此异常处理器内部。为了正确进入指定的异常处理器,在对异常处理器进行排列时应将派生类排在前面,而将基类排在后面。