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_error、std::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类型与抛出类型严格一致。