如何从重复继承的基类中消除重写虚拟的歧义?

时间:2012-08-23 07:30:24

标签: c++ multiple-inheritance

考虑以下无效的C ++代码。

#include <assert.h>

class NodeInterface {
public:
    virtual ~NodeInterface () {}

    virtual int f (const int& n) const = 0;
};

class ChildNodeInterface : public NodeInterface {
public:
    virtual ~ChildNodeInterface () {}
};

class ParentNodeInterface : public NodeInterface {
public:
    virtual ~ParentNodeInterface () {}
};

class ChildNode : public ChildNodeInterface {
public:
    virtual ~ChildNode () {}

    virtual int f (const int& n) const {
        return 2*n;
    }
};

class ParentNode : public ParentNodeInterface, private ChildNodeInterface {
public:
    explicit ParentNode () :
        mChild (new ChildNode ())
    {
    }

    virtual ~ParentNode () {}

    ChildNodeInterface* GetChildHandle () {
        return this;
    }

    virtual int f (const int& n) const {
        return 3*n;
    }

private:
    ChildNode* const mChild;

    // How do I specify that I would like to override ChildNodeInterface::f?
    virtual int f (const int& n) const { // On MSVC2010: C2535 member function already defined or declared
        return 1 + mChild->f (n);
    }
};

int main()
{
    ParentNode parent;
    assert (parent.f (2) == 6);
    ChildNode node;
    assert (node.f (2) == 4);
    ChildNodeInterface* child (parent.GetChildHandle ());
    assert (child->f (2) == 5);
    return 0;
}

我的目标是让ParentNode私下看起来像ChildNode,以便它可以在ChildNode ChildNodeInterface的实施之上添加一些额外的功能。因此,ParentNode可以有效地被伪装成ChildNode - 句柄,由GetChildHandle的简单性表示。 显然,如果ParentNode不会重复继承NodeInterface,那么就没有问题。因此,可以轻松消除覆盖的歧义。这由以下正确的示例说明:

#include <assert.h>

class ChildNodeInterface {
public:
    virtual ~ChildNodeInterface () {}

    virtual int ChildMethod (const int& n) const = 0;
};

class ParentNodeInterface {
public:
    virtual ~ParentNodeInterface () {}

    virtual int ParentMethod (const int& n) const = 0;
};

class ChildNode : public ChildNodeInterface {
public:
    virtual ~ChildNode () {}

    virtual int ChildMethod (const int& n) const {
        return 2*n;
    }
};

class ParentNode : public ParentNodeInterface, private ChildNodeInterface {
public:
    explicit ParentNode () :
        mChild (new ChildNode ()),
        mValue (1)
    {
    }

    ChildNodeInterface* GetChildHandle () {
        return this;
    }

    virtual int ParentMethod (const int& n) const {
        return 3*n;
    }

private:
    ChildNode* const mChild;
    const int mValue;

    virtual int ChildMethod (const int& n) const {
        return mValue + mChild->ChildMethod (n);
    }
};

int main()
{
    ParentNode parent;
    assert (parent.ParentMethod (2) == 6);
    ChildNode node;
    assert (node.ChildMethod (2) == 4);
    ChildNodeInterface* child (parent.GetChildHandle ());
    assert (child->ChildMethod (2) == 5);
    return 0;
}

但是,在ParentNodeInterfaceChildNodeInterface都从NodeInterface继承的特殊情况下,会产生歧义。 从main中的断言中可以清楚地看出,我的目标不是NodeInterface的虚拟继承。我打算在NodeInterface::f中实现ParentNode的真正独特实现。 我想知道如何(如果可能的话)我可以在ParentNodeInterface::f中区分ChildNodeInterface::fParentNode的实施。

2 个答案:

答案 0 :(得分:1)

我认为你的设计是错误的。你是继承的ChildNodeInterface,你的ParentNode类中有一个ChildNode成员吗?

继承的ChildNodeInterface不允许使用f函数实现,因为ChildNode类不在继承树中。

C ++不允许将具有相同签名的函数重新加倍两次。因此,无法完成相同虚函数的2个实现。

所以你有两个选择:

  1. [最佳]尝试以正确的方式使用继承重新定义您的类设计。钻石继承通常是由于糟糕的设计。
  2. [Fastest]从ChildNodeInterface中删除继承,并且更喜欢在ParentNode :: f()函数中调用mChild-&gt; f()来将Child行为添加到父级:

    virtual int f(const int&amp; n)const {     return 3 * n + mChild-&gt; f(n); } 但我不知道这是否是你想要的行为。

答案 1 :(得分:1)

请注意,ChildNodeInterface实际上与ChildNode::f()无关。

但要解决您的问题(我认为),请使用从ChildNodeInterface继承并在该类型中覆盖ChildNode的帮助程序类型,而不是从ChildNode::f()私有继承。 ParentNode可以维护指向其中一个对象的指针(或只是拥有该类型的普通旧成员),并在调用ParentNode::GetChildHandle()时发出指向该东西的指针:

// the helper class
class ParentNode;
class ParentsChildNodeInterface : public ChildNode {
public:
    virtual int f (const int& n) const;
};

class ParentNode : public ParentNodeInterface {

public:
    explicit ParentNode () :
        mChild (new ParentsChildNodeInterface ())
    {
    }

    virtual ~ParentNode () {}

    ChildNodeInterface* GetChildHandle () {
        return mChild;
    }

    virtual int f (const int& n) const {
        return 3*n;
    }

private:
    ParentsChildNodeInterface* const mChild;
};

// the new, special f() for children of parents...
int ParentsChildNodeInterface::f (const int& n) const {
    return 1 + ChildNode::f (n);
}

发布后,帮助程序类不需要访问ParentNode对象中的任何状态。但如果它确实需要,你可以让助手类成为friend的{​​{1}}。