【问题标题】:Cannot derive from class with virtual inheritance (C++ virtual inheritance)无法从具有虚拟继承的类派生(C++ 虚拟继承)
【发布时间】:2016-03-04 19:11:12
【问题描述】:
class Base
{
public:
    Base(std::string arg1, std::string arg2) : arg1(arg1), arg2(arg2) {}
    string arg1,arg2;
    virtual void f() = 0;
    inline virtual ~Base() {}
};

class Mixin1 : virtual public Base
{
};

//Virtual class uses virtual base and a mixin
class VirtualDerived : virtual public Base, public Mixin1
{
public:
    VirtualDerived(string arg2) : Base("some literal", arg2) {}
};

//Here I am concretely subclassing VirtualDerived, whose constructor constructs all virtual superclasses.
class ConcreteDerived : public VirtualDerived
{
public:
    ConcreteDerived(string arg2) : VirtualDerived(arg2) {}
    inline void f() {}
};

int main(int argc, const char * argv[]) {

    ConcreteDerived cd("hello");

    return 0;
}

我是从 VirtualDerived 派生的,它的构造函数将初始化 Base。我是否明确声明 VirtualDerived 对 Mixin1 virtual 的继承没有区别。

我得到的错误是 ConcreteDerived 必须显式调用 Base 的构造函数。

使 ConcreteDerived 的继承虚拟化同样没有区别。

问题不在于 VirutalDerived 的构造函数转发。如果我实现 f 使其成为一个具体的类,我可以毫无问题地创建它:

class VirtualDerived : virtual public Base, public Mixin1
{
public:
    VirtualDerived(string arg2) : Base("some literal", arg2) {}
    inline void f(){}
};

int main(int argc, const char * argv[]) {

    VirtualDerived cd("hello");

    return 0;
}

编译器似乎明白,VirtualDerived 的构造函数在直接创建 VirtualDerived 时调用 Base 的 non-trivial 构造函数。但如果某些东西派生 VirtualDerived 并调用它,则不会。为什么会这样?

【问题讨论】:

  • "virtual public Base, public Mixin1"这里为什么继承Base

标签: c++ inheritance constructor initialization virtual-inheritance


【解决方案1】:

关于虚拟继承要理解的是,当你从一个类虚拟继承时,它会走到继承“队列”的“前面”;也就是说,您必须在所有其他基类之前初始化虚拟基。

在这种情况下,ConcreteDerived 通过VirtualDerivedBase 作为间接虚拟基础。由于Base没有默认构造函数,所以必须在ConcreteDerived的初始化列表中指定。

原因是这样的:假设您有另一个中间类,例如

class VirtualDerived2 : virtual public Base
{
public:
    VirtualDerived2() : Base("arg1", "arg2") {}    
};

这里的VirtualDerived2 也实际上继承自Base,并使用自己的一组参数对其进行初始化。现在我们添加另一个具体类:

class ConcreteDerived2 : public VirtualDerived, public VirtualDerived2
{
    // ...
};

现在ConcreteDerived2 有两个基类,它们实际上都继承自Base。但是你在层次结构中只有一个Base 的副本——这就是虚拟继承的全部意义所在。那么现在您将使用哪些参数来初始化Base 的(单个)副本?来自VirtualDerived 的人,还是来自VirtualDerived2 的人?对此没有好的答案,因此 C++ 让您在派生最多的类中进行选择。

【讨论】:

  • "没有很好的答案" 有一个很好的答案:C++ 对虚函数也有同样的答案。在那种特殊情况下是模棱两可的。这并不能证明最派生类应该初始化虚拟基类的规则。
猜你喜欢
  • 2015-07-13
  • 2020-10-26
  • 2015-09-09
  • 1970-01-01
  • 2013-02-26
  • 2016-03-26
  • 2011-01-08
相关资源
最近更新 更多