首页 > 编程笔记 > C++笔记 阅读:101

C++ try catch异常处理语句的用法(附带实例)

异常信号抛出后,一旦被异常处理器接收到就会被销毁。C++ 程序中,异常处理器通常紧跟在 try 语句后,处理方法由关键字 catch 引导。

下面通过 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;
}
程序中定义了一个异常类,该类包含两个内容:
通过 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 类的基类,因此将进入此异常处理器内部。为了正确进入指定的异常处理器,在对异常处理器进行排列时应将派生类排在前面,而将基类排在后面。

相关文章