捕捉自定义异常


在〈简介异常处理〉示范了如何以字符串作为异常抛出,catch异常时类型指明为char const*,这表示相同类型的异常被抛出时,会执行对应的catch区块,如果有多个类型的话,可以指定多个catch

try {
    foo();
}
catch(int errCode) {
    ...
}
catch(char const* errorMsg) {
    ...
}

只不过直接catch基本类型之类的异常,在程序的意图上不清楚,而且这类异常可以表现的信息有限,int类型的异常被捕捉后,还得比对错误码,字符串的异常被捕捉后,不一定只是想显示字符串,可能还要比对字符串内容等,以做其他相应的处理。

你可以自定义异常类型,并令类型名称具有代表异常意涵的实质意义,例如:

class Exception {
    const string message;

public:
    explicit Exception(const string &message) : message(message) {}

    virtual const char* what() {
        return this->message.c_str();
    }

    virtual ~Exception() = default;
};

class InvalidArgument : public Exception {
    using Exception::Exception;
};

class Insufficient : public Exception {
    int balance;

public:
    explicit Insufficient(const string &message, int balance) 
                : Exception(message), balance(balance) {}

    int getBalance() {
        return balance;
    }
};

这么一来,就可以依不同的异常类型来捕捉异常实例了:

Account acct = {"123-456-789", "Justin Lin", 1000};

try {
    acct.withdraw(10200);
    acct.deposit(-500);
}
catch(InvalidArgument &ex) {
    cout << "实参错误:" << ex.what() << endl;
}
catch(Insufficient &ex) {
    cout << "帐号错误:"  << endl
         << "\t" << ex.what() << endl
         << "\t余额 " << ex.getBalance() << endl;
}

catch时若类型有继承关系,父类型不能写在子类型的catch之前,因为会先被比对到,导致后续的子类型catch写了等于没写,编译时也会提出警讯:

Account acct = {"123-456-789", "Justin Lin", 1000};

try {
    acct.withdraw(10200);
    acct.deposit(-500);
}
catch(Exception &ex) {
    cout << ex.what() << endl;
}
// warning: exception of type 'InvalidArgument' will be caught by earlier handler for 'Exception'
catch(InvalidArgument &ex) {
    cout << "实参错误:" << ex.what() << endl;
}
catch(Insufficient &ex) {
    cout << "帐号错误:"  << endl
         << "\t" << ex.what() << endl
         << "\t余额 " << ex.getBalance() << endl;
}

如果异常的类型具有相同父类,那可以将父类写在最后,作为同类型异常的捕遗:

try {
    acct.withdraw(10200);
    acct.deposit(-500);
}
catch(InvalidArgument &ex) {
    cout << "实参错误:" << ex.what() << endl;
}
catch(AccountException &ex) {
    cout << "帐号操作错误:" << ex.what() << endl;
}
catch(Exception &ex) {
    cout << ex.what() << endl;
}

C++ 有个全捕捉语法catch(...),用来捕捉全部类型的异常,不过并不鼓励使用,这之后再来谈。


展开阅读全文