答案:C++异常处理需按具体到一般的顺序排列catch块,支持向上转型但避免对象切片,推荐使用const引用捕获,catch(...)放最后兜底处理。

在C++中,异常处理机制通过 try、catch 和 throw 实现。当一个异常被抛出时,程序会沿着调用栈查找匹配的 catch 块。异常的捕获顺序和类型匹配规则直接影响程序能否正确处理异常。理解这些规则对编写健壮的 C++ 程序至关重要。
异常捕获顺序:按声明顺序匹配
catch 块的排列顺序非常重要。程序会从上到下依次检查每个 catch 块,一旦找到匹配的类型,就执行该块并跳过其余 catch 块。
因此,更具体的异常类型应放在前面,更通用的(如基类)应放在后面。如果将基类 catch 块放在派生类之前,派生类的异常将永远不会被捕获。
错误示例:
try {
throw std::runtime_error("error");
}
catch (std::exception &e) {
// 先匹配了基类,下面的 catch 永远不会执行
}
catch (std::runtime_error &e) {
// 这个块无法到达
}
正确写法:
try {
throw std::runtime_error("error");
}
catch (std::runtime_error &e) {
// 先处理派生类
}
catch (std::exception &e) {
// 再处理基类
}
类型匹配规则:精确匹配优先,支持向上转型
catch 块的类型匹配不是多态调用,而是基于类型是否“兼容”。匹配规则如下:
立即学习“C++免费学习笔记(深入)”;
- 异常对象的类型与 catch 参数类型完全相同(忽略 const 和引用修饰)
- catch 参数是异常对象类型的基类(支持 public 继承下的向上转型)
- catch 参数是指针时,只匹配指针类型,不会进行隐式转换(除非是 void* 等特殊情况)
注意:如果 catch 参数是值类型(如
catch (std::exception e)),会触发对象切片(slicing),建议始终使用引用或 const 引用。
引用与值捕获的区别
使用引用捕获可以避免对象复制和切片问题,保留异常的完整类型信息。
例如:
class MyException : public std::exception {
public:
const char* what() const noexcept override {
return "My custom exception";
}
};
try {
throw MyException();
}
catch (std::exception e) { // 值捕获,发生切片
// e 的类型是 std::exception,丢失派生信息
}
catch (std::exception &e) { // 引用捕获,保留完整类型
// 可以安全调用虚函数,行为正确
}
推荐始终使用 const 引用 捕获标准异常,如
const std::exception &。
捕获所有异常:使用 ...
C++ 允许使用
catch (...)捕获任何类型的异常,通常用于兜底处理或资源清理。
注意:
- ... 必须放在所有其他 catch 块之后,否则后续 catch 块无法到达
- 无法获取异常的具体信息,只能重新抛出或记录日志
- 常用于封装接口,防止异常泄漏
示例:
try {
riskyOperation();
}
catch (const std::invalid_argument &e) {
// 处理参数错误
}
catch (...) {
// 兜底处理
std::cerr << "Unknown exception caught\n";
throw; // 重新抛出
}
基本上就这些。只要记住:catch 顺序从具体到一般,类型匹配支持向上转型但避免切片,优先使用 const 引用,... 放最后。不复杂但容易忽略细节。










