学而时习之:C++中的异常处理2

C++ 利用"类"实现异常处理

程序运行时常会遇到"除以 0、文件不存在、数据无效"等突发状况,统称为异常 。若放任不管,进程会异常终止。

C++ 提供 try-catch 机制:在 try 块里用 throw 抛出一个对象 ,该对象通常是某个异常类 的实例;catch 块根据对象类型捕获并处理。

标准库已预置的异常类, 所有内置异常都以 std::exception 为公共基类,其接口如下:

cpp 复制代码
class exception {
public:
    exception() noexcept;
    exception(const exception&) noexcept;
    exception& operator=(const exception&) noexcept;
    virtual ~exception();
    virtual const char* what() const noexcept;  // 返回描述字符串
};

what() 为虚函数,派生类可重写以给出更精确的诊断信息。 最常用的一众内置异常类见下表(均位于 <stdexcept>):

这些异常通常由 C++ 标准库组件抛出,程序员必须主动去捕获它们。

示例 1:捕获标准库抛出的异常

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    try {
        // 尝试分配一个极大的数组
        int* bigArray = new int[100000000000000];
    }
    catch (const bad_alloc& e) {          // 内存分配失败时库抛 bad_alloc
        cout << "捕获 bad_alloc: " << e.what();
    }
    // 程序继续往下执行
    return 0;
}
c 复制代码
捕获 bad_alloc: std::bad_alloc

示例 2:在自己的代码里主动使用标准异常

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    int num = 10, den = 0, res;

    try {
        if (!den)                       // 检测除 0
            throw runtime_error("Division by Zero");  // 主动抛异常
        res = num / den;
    }
    catch (const runtime_error& e) {    // 按引用捕获
        cout << "捕获: " << e.what();
    }
    return 0;
}
csharp 复制代码
捕获: Division by Zero

注意:除 std::exception 基类外,其余标准异常类都支持在构造函数里传入自定义描述字符串,方便我们给出具体错误信息。

创建自定义异常类

如果标准异常不满足需求,我们可以自己写异常类。常见有三种做法,第一种最简单:

1. 继承 std::exception

直接继承标准基类,即可与现有 catch (const exception&) 体系无缝衔接;通过重写虚函数定制行为。

示例:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

// 自定义异常类
class CustomExcept : public exception {
public:
    // 重写 what() 返回描述信息
    const char* what() const noexcept override {
        return "This is a custom exception!";
    }
};

int main() {
    try {
        throw CustomExcept();   // 抛出自定义异常对象
    }
    catch (const CustomExcept& e) {          // 按引用捕获
        cout << "Caught an exception: " << e.what();
    }
    return 0;
}
vbnet 复制代码
Caught an an exception: This is a custom exception!

解释:我们定义了 CustomExcept 并改写 what()。当 throw CustomExcept() 时,匹配到的 catch 会调用其 what() 打印自定义错误信息。

2. 继承其他标准异常

除了直接从 std::exception 派生,我们还可以继承 std::runtime_errorstd::logic_error具体异常类

这样既能沿用它们已有的自定义消息机制 (构造函数接收 string),又能让异常类型更精细,与标准库风格保持一致。

示例:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

class CustomExcept : public runtime_error {
public:
    // 把自定义描述传给父类构造函数
    CustomExcept(const string& message)
        : runtime_error(message) {}
};

int main() {
    try {
        throw CustomExcept("This is a custom runtime_exception!");
    }
    catch (const CustomExcept& e) {
        cout << e.what();   // 输出父类保存的描述
    }
    return 0;
}
vbnet 复制代码
This is a custom runtime_exception!

解释: CustomExcept 继承自 runtime_error,因此自带 what() 功能;

我们只需在构造函数里把自定义信息转发给基类即可使用。

3. 创建非标准异常

我们也可以完全不继承任何标准异常类,自己写一个"独立"的异常类。 这样做最灵活,但代价是:

  • 不再能与 catch (const std::exception&) 之类的外层处理器兼容;
  • 必须自己实现所有接口(例如 what())。

示例:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

class CustomExcept {
public:
    explicit CustomExcept(const string& msg) : message(msg) {}
    
    // 自定义 what(),返回 C-style 字符串
    const char* what() const {
        return message.c_str();
    }

private:
    string message;
};

int main() {
    try {
        throw CustomExcept("This is a custom exception!");
    }
    catch (const CustomExcept& e) {   // 必须精确匹配类型
        cout << e.what();
    }
    return 0;
}
vbnet 复制代码
This is a custom exception!

要点

  • 完全自定义,想怎么写都行;
  • 无法catch (const exception&) 接住,使用时务必保证 catch 类型与抛出类型严格一致
相关推荐
小小晓.2 小时前
Pinely Round 4 (Div. 1 + Div. 2)
c++·算法
SHOJYS2 小时前
学习离线处理 [CSP-J 2022 山东] 部署
数据结构·c++·学习·算法
steins_甲乙3 小时前
C++并发编程(3)——资源竞争下的安全栈
开发语言·c++·安全
仰泳的熊猫3 小时前
1084 Broken Keyboard
数据结构·c++·算法·pat考试
我不会插花弄玉3 小时前
C++的内存管理【由浅入深-C++】
c++
CSDN_RTKLIB4 小时前
代码指令与属性配置
开发语言·c++
上不如老下不如小4 小时前
2025年第七届全国高校计算机能力挑战赛 决赛 C++组 编程题汇总
开发语言·c++
雍凉明月夜4 小时前
c++ 精学笔记记录Ⅱ
开发语言·c++·笔记·vscode
GHL2842710904 小时前
文件重命名(C++源码)
前端·c++·windows