C++中的异常处理机制详解

2020-01-06 17:21:42丽君


//基类
class Base{
 public:
 Base(string msg):m_msg(msg)
 {
 }
 virtual void what(){
 cout << m_msg << endl;
 }
 void test()
 {
 cout << "I am a CBase" << endl;
 }
 protected:
 string m_msg;
};
//派生类,重新实现了虚函数
class CBase : public Base
{
 public:
 CBase(string msg):Base(msg)
 {
 }
 void what()
 {
 cout << "CBase:" << m_msg << endl;
 }
 };
int main()
 {
 try {
 //do some thing
 //抛出派生类对象
 throw CBase("I am a CBase exception");
 }catch(Base& e) { //使用基类可以接收
 e.what();
 }
 }

上面的这段代码可以正常的工作,实际上我们日常编写自己的异常处理函数的时候也是通过继承标准异常来实现字节的自定义异常的,但是如果将Base&换成Base的话,将会导致对象被切割,例如下面这段代码将会编译出错,因为CBase被切割了,导致CBase中的test函数无法被调用。


try {
    //do some thing
    throw CBase("I am a CBase exception");
}catch(Base e) {

e.test();

}

到此为此,异常的匹配算是说清楚了,总结一下,异常匹配的时候基本上遵循下面几条规则:

异常匹配除了必须要是严格的类型匹配外,还支持下面几个类型转换.

允许非常量到常量的类型转换,也就是说可以抛出一个非常量类型,然后使用catch捕捉对应的常量类型版本

允许从派生类到基类的类型转换

允许数组被转换为数组指针,允许函数被转换为函数指针

假想一种情况,当我要实现一代代码的时候,希望无论抛出什么类型的异常我都可以捕捉到,目前来说我们只能写上一大堆的catch语句捕获所有可能在代码中出现的异常来解决这个问题,很显然这样处理起来太过繁琐,幸好C++提供了一种可以捕捉任何异常的机制,可以使用下列代码中的语法。

catch(...) {
    //异常处理器,这里可以捕捉任何异常,带来的问题就是无法或者异常信息
   }
如果你要实现一个函数库,你捕捉了你的函数库中的一些异常,但是你只是记录日志,并不去处理这些异常,处理异常的事情会交给上层调用的代码来处理.对于这样的一个场景C++也提供了支持.


try{
    throw Exception("I am a exception");  
  }catch(...) {
    //log the exception
    throw;
  }

通过在catch语句块中加入一个throw,就可以把当前捕获到的异常重新抛出.在异常抛出的那一节中,我在代码中抛出了一个异常,但是我没有使用任何catch语句来捕获我抛出的这个异常,执行上面的程序会出现下面的结果.

terminate called after throwing an instance of 'MyError'
Aborted (core dumped)