从虚拟基础派生类,没有默认构造函数 [英] Deriving class from virtual base with no default constructor

查看:73
本文介绍了从虚拟基础派生类,没有默认构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我正在开发的C ++应用程序编写一小段异常类层次结构,并且在从 std :: runtime_error 间接派生时遇到了麻烦.这是类似于我到目前为止编写的代码:

  class RuntimeException:公共虚拟boost :: exception,公共虚拟std :: runtime_error {上市:虚拟〜RuntimeException(){}RuntimeException():runtime_error(发生RuntimeException."){}RuntimeException(const std :: string& what):runtime_error(what){}};class IllegalArgumentException:公共虚拟RuntimeException {上市:IllegalArgumentException():RuntimeException(发生IllegalArgumentException."){}IllegalArgumentException(const std :: string& what):RuntimeException(what){}}; 

RuntimeException 类可以毫无问题地进行编译,但是 IllegalArgumentException 拒绝在VS2015上进行编译,从而产生错误:类"std ::"不存在默认构造函数: IllegalArgumentException 的两个构造函数的"runtime_error" .挑战了我对C ++继承层次结构的理解,因为我希望这段代码可以很好地编译.

我的理解是 IllegalArgumentException 应该进行编译,因为尽管 std :: runtime_error 确实没有默认构造函数,但是构造函数正在为 RuntimeException 调用构造函数.但是显然这一定是错误的,因为编译器正在拒绝它.似乎要我直接从 IllegalArgumentException 构造函数调用 std :: runtime_error 构造函数(当我这样做时,编译器错误会消失),但这似乎是错误的,因为这样我会两次调用 std :: runtime_error 的构造函数:一次在 RuntimeException 的构造函数中,再一次在 IllegalArgumentException 的构造函数中./p>

这样做安全和/或有效吗?如果没有,为什么编译器似乎鼓励它呢?我可以只是从 std :: exception 派生并自己实现 std :: string 作为成员变量,但我认为这样会更容易从已经实现此功能的标准类派生.这是错误的方法吗?另外,事实上我实际上是从 boost:exception std :: runtime_error 派生出来的吗?

解决方案

使用 virtual 继承时, virtual 基的构造函数调用是的责任大多数派生类,而不是任何中间类的责任.原因很明显:使用 virtual 继承表示期望使用基类实际上存在多个派生类.这些派生类中的哪一个负责构建 virtual 基?

因此,任何派生类的构造函数都需要为 virtual 基提供一个参数,例如:

  IllegalArgumentException :: IllegalArgumentException(std :: string const& what):std :: runtime_error(什么),RuntimeException(what){} 

为避免有中间基类,调用用于 virtual 继承的 virtual 基类的构造函数通常会提供默认的构造函数.当然,这开辟了以下可能性:大多数派生类不正确地依赖于由其基数之一调用的适当构造函数.

I'm writing a small hierarchy of exception classes for a C++ application I'm developing, and I'm having trouble deriving indirectly from std::runtime_error. Here is code analogous to what I've written so far:

class RuntimeException : public virtual boost::exception, public virtual std::runtime_error {
public:
    virtual ~RuntimeException() {}
    RuntimeException() : runtime_error("A RuntimeException occurred.") {}
    RuntimeException(const std::string& what) : runtime_error(what) {}
};

class IllegalArgumentException : public virtual RuntimeException {
public:
    IllegalArgumentException() : RuntimeException("An IllegalArgumentException occurred.") {}
    IllegalArgumentException(const std::string& what) : RuntimeException(what) {}
};

The RuntimeException class compiles without issue, but IllegalArgumentException refuses to compile on VS2015, generating the error: no default constructor exists for class "std::runtime_error" for both constructors of IllegalArgumentException. This challenges my understanding of C++ inheritance hierarchies, as I expected this code to compile fine.

My understanding is that IllegalArgumentException should compile because, although it is true that std::runtime_error does not have a default constructor, its constructor is being called by the constructor for RuntimeException. But obviously this must be false, as the compiler is rejecting it. It seems to want me to call the std::runtime_error constructor directly from the IllegalArgumentException constructor (the compiler error goes away when I do so), but this seems wrong because then I would be calling the constructor for std::runtime_error twice: once in the constructor for RuntimeException, and again in the constructor for IllegalArgumentException.

Is this safe and/or efficient to do? If not, why does the compiler seem to encourage it? I could just derive from std::exception and implement the std::string myself as a member variable, but I thought it would be easier to derive from a standard class that has already implemented this. Is this the wrong approach to take? Additionally, is the fact that I'm deriving virtually from both boost:exception and std::runtime_error contributing to this issue?

解决方案

When using virtual inheritance the constructor call of the virtual base is the responsibility of the most derived class rather than the responsibility of any intermediate class. The reason is obvious: the use of virtual inheritance indicates that there is an expectation that there are actually multiple derived classes using the base class. Which one of these derived classes would be responsible for constructing the virtual base?

So, the constructor of any of the derived classes needs to provide an argument to the virtual base, e.g.:

IllegalArgumentException::IllegalArgumentException(std::string const& what)
    : std::runtime_error(what)
    , RuntimeException(what) {
}

To avoid having intermediate bases call the constructor of the virtual base classes intended for virtual inheritance often provide a default constructor. Of course, that opens up the possibility that the most derived class incorrectly relies on the proper constructor being called by one of its bases.

这篇关于从虚拟基础派生类,没有默认构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆