在c++++中自定义异常类时,应继承std::exception或其子类,并正确实现what()方法。1. 优先从std::runtime_error或std::logic_error等标准异常类派生;2. 若继承std::exception则必须重写const char what() const noexcept方法,并将错误信息保存在成员变量中;3. 在多层多重继承场景下使用虚继承以避免菱形继承问题;4. 构造函数应支持多种消息输入方式,如std::string和const char,确保灵活性与兼容性。

在 C++ 中自定义异常类时,通常的做法是继承标准库中的异常类(如
std::exception或其派生类),这样可以与现有的异常处理机制兼容。但很多人对如何正确地做这件事并不清楚,尤其是关于虚继承、重写
what()方法以及构造函数的设计等方面。

下面是一些关键点和建议,帮助你写出清晰、安全且符合规范的自定义异常类。
1. 继承 std::exception 或其子类
C++ 标准库中定义了一些常用的异常类,比如:
立即学习“C++免费学习笔记(深入)”;

std::exception
:所有标准异常类的基类std::runtime_error
std::logic_error
- 等等
如果你要定义一个运行时错误类型的异常,推荐从
std::runtime_error派生;如果是逻辑错误,则从
std::logic_error派生。当然,也可以直接继承
std::exception,但那样你需要自己实现更多的细节。
#include#include class MyException : public std::runtime_error { public: explicit MyException(const std::string& message) : std::runtime_error(message) {} };
这样做的好处是你可以利用已有的结构和行为,同时保持一致性。

2. 正确重写 what() 方法(如果需要)
如果你继承的是
std::exception,就必须重写
virtual const char* what() const noexcept方法。这个方法用于返回异常的描述信息。
#include#include #include class MyCustomException : public std::exception { std::string msg_; public: explicit MyCustomException(const std::string& msg) : msg_(msg) {} const char* what() const noexcept override { return msg_.c_str(); } };
注意几点:
- 返回值要是常量字符串指针,所以不能返回临时对象或局部变量
- 推荐将信息保存在成员变量中
- 使用
noexcept
和override
来明确语义和避免错误
3. 考虑使用虚继承(当多层继承时)
如果你的异常类体系比较复杂,比如有多级继承或者多个基类都继承自
std::exception,那么为了避免菱形继承问题,应该使用虚继承。
例如:
class BaseException : public virtual std::exception {};
class DerivedA : public virtual BaseException {};
class DerivedB : public virtual BaseException {};
class FinalException : public DerivedA, public DerivedB {};在这种情况下,使用虚继承可以确保最终派生类只有一个
std::exception子对象,从而避免歧义和资源浪费。
4. 构造函数设计要灵活
一个好的异常类应支持多种方式传入错误信息,比如:
const char*
std::string
- 支持格式化字符串(可选)
例如:
class MyException : public std::runtime_error {
public:
explicit MyException(const std::string& msg) : std::runtime_error(msg) {}
explicit MyException(const char* msg) : std::runtime_error(msg) {}
};或者更进一步,提供一个类似
printf的构造方式(虽然不推荐在异常中频繁使用)。
基本上就这些。自定义异常类看起来不复杂,但要注意继承方式、虚析构、what 方法的实现以及构造函数的灵活性。只要遵循标准库的设计思路,就能写出既安全又实用的异常类。









