我正试图设计一个自定义的异常层次结构,我想要的是,尽可能地继承标准的异常和错误,在捕捉STL异常的情况下,允许捕捉自定义的异常。我想要的是,尽可能继承标准异常和错误,在捕获STL异常的情况下,允许捕获自定义异常。
例如,在下面的层次结构中,如果你捕获了一个异常 std::logic_error
那么,一个 LogicException
也会被捕获。
-> Exception --> LogicException
/ ^
std::exception --> std::logic_error --^
所以,这就是实现这个目标的代码(不包括头保护,包含和命名空间作用域,以及定义)。
class Exception: public std::exception
{
public:
Exception() = delete;
Exception(const char *) noexcept(true);
Exception(const std::string &) noexcept(true);
virtual Message what() const noexcept(true);
private:
std::string message;
};
class LogicException: public Exception, public std::logic_error
{
public:
LogicException() = delete;
using Exception::Exception;
using Exception::what;
};
然而,考虑到下面的基本主函数(同样,排除非意义部分):
int main()
{
throw LogicException("Oops!");
}
我会得到以下错误(用GCC 10.0.1编译)。
test.cpp: In function ‘int main()’:
test.cpp:5:29: error: use of deleted function ‘LogicException::LogicException(const char*) [inherited from Exception]’
5 | throw LogicException("e");
| ^
In file included from test.cpp:1:
./include/exception.hpp:27:34: note: ‘LogicException::LogicException(const char*) [inherited from Exception]’ is implicitly deleted because the default definition would be ill-formed:
27 | using Exception::Exception;
| ^~~~~~~~~
./include/exception.hpp:27:34: error: no matching function for call to ‘std::logic_error::logic_error()’
In file included from ./include/exception.hpp:4,
from test.cpp:1:
/usr/include/c++/10/stdexcept:131:5: note: candidate: ‘std::logic_error::logic_error(const std::logic_error&)’
131 | logic_error(const logic_error&) _GLIBCXX_NOTHROW;
| ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:131:5: note: candidate expects 1 argument, 0 provided
/usr/include/c++/10/stdexcept:126:5: note: candidate: ‘std::logic_error::logic_error(std::logic_error&&)’
126 | logic_error(logic_error&&) noexcept;
| ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:126:5: note: candidate expects 1 argument, 0 provided
/usr/include/c++/10/stdexcept:124:5: note: candidate: ‘std::logic_error::logic_error(const char*)’
124 | logic_error(const char*) _GLIBCXX_TXN_SAFE;
| ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:124:5: note: candidate expects 1 argument, 0 provided
/usr/include/c++/10/stdexcept:120:5: note: candidate: ‘std::logic_error::logic_error(const string&)’
120 | logic_error(const string& __arg) _GLIBCXX_TXN_SAFE;
| ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:120:5: note: candidate expects 1 argument, 0 provided
所以,问题是:
经过一段时间后,我认为这就是为什么会出现错误的原因。当使用 Exception
构造函数,编译器会尝试隐式地调用 std::logic_error
不存在的。是否真的如此?
有没有什么方法可以避免这个错误(例如,以某种方式调用 std::logic_error
的构造函数),而不必显式地声明 LogicException
构造函数或改变类的层次结构?
请注意。 我之所以不想明确声明 LogicException::LogicException
是,我有一些异常类是这样定义的,因此,我不想增加额外的文件来定义 LogicException
类什么的。
一般来说,在设计异常的时候,用上面的思路好吗?
谢谢。
我不知道你是否真的想建立另一个异常层次结构,与此同时,你还想建立一个异常层次结构。std::exception
也许我只是不明白你的意思)。至于建立一个异常层次结构到 std::exception
(及其子女),你不需要另一个基地。
由于你无论如何都不应该抛出不特定的异常,因为你将无法在调用者端以特定的方式处理它,所以只需在你的平台支持的现有异常层次结构中添加特定的叶子。如果你是用标准的C++编程,那么这就是 std::exception
层次结构。
你应该非常小心地抓住 std::exception
. 我建议这样做 只是 在 main
(或同等的顶层函数),以便在退出前记录一个错误。允许你捕捉的异常是那些你能理解的条件,并且你能完全控制的异常;例如,一个文件不存在,而程序有其他的选择,或者根本不需要它(因为ist只是可选的)。
what
到消息我的理解是 what()
属性是来自 "事故 "发生地的原始信息,它给出了你的程序不应该绑定的附加信息。[1] 它是用于 "取证 "的,主要是用于生成输出(用于显示在用户界面上或添加到日志文件中)。请看下面我理解的小演示。
#include <iostream>
#include <stdexcept>
class my_ex: public std::logic_error {
public:
my_ex(const char* const what): std::logic_error(what) {}
};
void just_throw_the_message(const char* const msg) {
throw my_ex(msg);
}
int main() {
try {
just_throw_the_message("I feel somewhat exceptional.");
} catch (const std::exception& e) {
std::cout << "exception caught: " << e.what() << std::endl;
}
return 0;
}
(见上面的代码运行在 ideone.com)
你最初的说法是(强调是我的)。
我想要的是,从标准的异常和错误中继承下来 尽可能,以允许在捕获STL异常的情况下捕获自定义异常。
对于这个要求,我看到的唯一合理的答案是直接从 std::exception
或其子孙之一! 不要对异常使用多重继承! 尤其是。尽可能,并不比你构建到的层次结构已经定义的错误分类多多少。所以在标准C++中,我强烈建议继承(最终)于 std::exception
.
如果你已经有一个符合你需求的特定应用程序异常层次结构,只需将它的基类变成一个类似于 std::exception
.
[1]为了在程序上区分异常事件,使用异常类型。为自己的程序专用异常类添加属性也是有意义的。