在多重继承中,使用其中一个基类的构造函数,而其他基类没有默认构造函数。

问题描述 投票:0回答:1

我正试图设计一个自定义的异常层次结构,我想要的是,尽可能地继承标准的异常和错误,在捕捉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 类什么的。

  • 一般来说,在设计异常的时候,用上面的思路好吗?

谢谢。

c++ exception constructor hierarchy multiple-inheritance
1个回答
1
投票

我不知道你是否真的想建立另一个异常层次结构,与此同时,你还想建立一个异常层次结构。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]为了在程序上区分异常事件,使用异常类型。为自己的程序专用异常类添加属性也是有意义的。

© www.soinside.com 2019 - 2024. All rights reserved.