Diamond继承两次派生 - 构造函数params不同 - base无法指定虚拟继承

时间:2014-07-03 01:25:41

标签: c++ interface multiple-inheritance diamond-problem

我努力在标题中简洁地描述问题,所以如果你理解了这个问题并且有更好的标题,请建议。

我已经制作了我的问题的精简版本,它尽可能小,因此所有函数都是内联定义的,所以请原谅,实际代码不是这样的。

这是我的结构:

class iobject
{
public:
    virtual bool isValid (void) = 0;
};

class object : virtual public iobject
{
public:
    object (void) { }
    virtual ~object () {}
    virtual bool isValid (void) { return true; }
};

如上所述,一个接口+实现只是跟踪一个对象是否有效......想象一下,引擎/系统中的所有对象都将来自这个单个对象。

class ibase : public virtual iobject
{
public:
    virtual void show (void) = 0;
};

class base : public virtual object,
             public virtual ibase
{
public:
    base (int value) : object() { m_value = value; }
    virtual ~base () {}
    virtual void show (void) { std::cout << m_value << std::endl; }

private:
    int m_value;
};

现在我有一个假设的课程,除了存储一个数字并打印它之外什么也没做。它源于对象。所以&#39;钻石&#39;已经完成了。

class derived1 : public virtual base
{
public: 
    derived1 (int value) : base (value) {}
    virtual ~derived1 () {}
};

现在我从基类派生。关于这个派生类的注意事项是我有与基类(int值)相同的构造函数参数。

class derived2 : public virtual derived1
{
public:
    derived2 (void) : derived1 (15) {}
    virtual ~derived2 () {}
};

最后,我从这个派生类派生出来。但请注意,此类没有任何构造函数参数。相反,这个类在内部应该知道在这个例子中该值应该是15。

我的期望是,当我实例化derived2时,它将使用值15构造derived1并将其传递给对象。我希望做到以下几点:

derived1 works(1234);
derived2 doesNotWork;

works.show();
doesNotWork.show();

但是当我尝试这个时,我得到了:

error C2512: 'base::base' : no appropriate default constructor available

如果我添加一个空的base :: base构造函数,那么我最终会得到m_value未定义的预期(但无论如何都要尝试)

我似乎错过了一些明显的东西......,有人能突出它吗?

2 个答案:

答案 0 :(得分:1)

将derived2更改为:

derived2(void) : derived1(15), base(15) {}

这里出现了同样的问题: Why is Default constructor called in virtual inheritance?

本常见问题解答中描述了答案: http://www.parashift.com/c++-faq-lite/virtual-inheritance-ctors.html

简而言之:C ++不会分层调用虚拟构造函数。派生类最多的类负责调用所有虚拟基类构造函数。因此,您必须显式调用derived1()和base(),因为它们接受参数。链接的FAQ意味着这里的最佳实践是使虚拟基类只有no-arg构造函数。

答案 1 :(得分:0)

你没有钻石继承,这里没有共享基类(derived2 - &gt; derived1 - &gt; base - &gt;(object - &gt; iobject),ibase),无处可去链是否有任何重复。因此,您不需要虚拟继承,因此只需将public virtual全部删除即可。我意识到这是一个人为的例子而且与你的实际用法并不匹配,但根据我的经验,你真的需要多次继承虚拟调用,这是你通常应该远离的事情。在所有可能的情况下(对象大小,调用开销以及指针表现的一般肮脏)。