如何委托给实现类

10

我有一个抽象基类Node,它是从一个抽象接口类IObservable继承而来。有几个类实现了抽象的IObservable: SingleObservableMultiObservable

我想创建一个类ObservableNode,它从基类Node派生,并在其声明中指定用于IObservable接口实现的类。

我已经为IObservable中的每个纯虚方法添加了using ...语句,引用了实现类中的方法,但我仍然收到错误消息,说ObservableNode是一个抽象类,缺少notifyObservers(IObject*)的实现。

如果我将参数IObject*添加到using语句中,我会得到一个"expected ';' before '(' token"错误。

如何解决这个问题?

class IObservable {
  public:
    virtual ~IObservable() {};
    virtual void notifyObservers(IObject*) = 0;
};
class SingleObservable: public IObservable {
  public:
    virtual ~SingleObservable() {};
    void notifyObservers(IObject*) override { 
      //some implementaiton
    };
};
class MultiObservable: public IObservable {
  public:
    virtual ~MultiObservable() {};
    void notifyObservers(IObject*) override { 
      //some other implementaiton
    };
};

class Node: public IObservable {
  public:
    virtual ~Node() {};
};

class ObservableNode: public Node, public SingleObservable {
  public:
    virtual ~ObservableNode() {};
    using SingleObservable::notifyObservers;
    // using SingleObservable::notifyObservers(IObject*); // expected ';' before '(' token error

};


Node* node = new ObservableNode() // instantiating abstract class error, missing notifyObservers(IObject*) implementation
3个回答

7

你的问题似乎是继承了仍然是抽象的Node,同时还引起了老旧的多重继承恶性菱形继承问题。当我将你的代码更改如下时,错误消失了:

class Node: public IObservable {
  public:
    virtual ~Node() {};
    // ** Added an implementation here **
    void notifyObservers(IObject*) override { 
          //some other implementaiton
    };
};

class ObservableNode: public virtual Node, public virtual SingleObservable {
                          // ^^^^^^^              ^^^^^^^
  public:
    virtual ~ObservableNode() {};
    using SingleObservable::notifyObservers;
};

int main() {
    Node* node = new ObservableNode();
}

可以在 coliru 上实时查看。


@Scheff 谢谢您采用了这个方案。不从 IObservable 继承 Node 肯定也是另一种解决方法。您仍然可以将其发布为答案。 - πάντα ῥεῖ
确实,那解决了问题,谢谢!而且,我确实想在节点定义中使用IObservable接口。 - Bascy
1
请注意,在这个特定的例子中,Node* node = new ObservableNode(); 意味着 node->notifyObservers(obj) 将调用 Node::notifyObservers(IObject*) 而不是 SingleObservable::notifyObservers(IObject*),这可能会出乎意料,考虑到我们实例化了一个指定了 using SingleObservable::notifyObservers;ObservableNode 对象。OP 可能想要的是,在 ObservableNode 中定义一个 notifyObservers(IObject*) 重载,它明确地转发到 SingleObservable::notifyObservers(IObject*) - dfrib
@Bascy 你应该注意之前的评论。你仍然在与钻石歧义问题斗争,可能会得到意想不到的结果。 - πάντα ῥεῖ
1
如果调用 node->notifyObservers(obj),则会沿着虚函数表向下到达 ObservableNode::notifyObservers(IObject*),然后通过转发显式地向上到达 SingleObservable::notifyObservers(IObject*) - dfrib

3

@πάντα ῥεῖ的回答描述了一种解决方法,但可能并不是OP想要的。此外,正如我的评论在回答下面所述, 回答中的方法可能会产生意外的结果,例如在调用node->notifyObservers(obj)时:

请注意,在这个特定的例子中,Node* node = new ObservableNode();将意味着node->notifyObservers(obj)将调用Node::notifyObservers(IObject*)而不是SingleObservable::notifyObservers(IObject*),这可能是意外的,考虑到我们实例化了一个指定使用SingleObservable::notifyObservers;ObservableNode对象。

在 OP 的原始代码中,我们遭受了多重继承的歧义,因为当 Node 和 SingleObservable(以及 MultiObservable)派生自 IObservable 时,我们没有使用虚拟继承。
class SingleObservable: public IObservable {
  public:
    virtual ~SingleObservable() {};
    void notifyObservers(IObject*) override { 
      //some implementaiton
    };
};

class Node: public IObservable {
  public:
    virtual ~Node() {};
};
意味着我们关于继承的可观察节点(ObservableNode)的对象内存布局应该如下所示。
 IObservable  IObservable
           |  |
        Node  SingleObservable
           \  /
       ObservableNode

在这种情况下,我们可能希望一个对象的内存布局如下所示。
       IObservable
           /  \
        Node  SingleObservable
           \  /
       ObservableNode

如果我们进行更正,Node 可以保持抽象,并且对 node->notifyObservers(obj) 的调用,就像 OP 的示例一样,将导致调用 SingleObservable::notifyObservers,就像可能已经预期的那样。

class Node: public virtual IObservable {
                // ↑↑↑↑↑↑↑
  public:
    virtual ~Node() {};
};

class SingleObservable: public virtual IObservable {
                            // ↑↑↑↑↑↑↑
  public:
    virtual ~SingleObservable() {};
    void notifyObservers(IObject*) override { 
        std::cout << "SingleObservable::notifyObservers";
    };
};

struct DummyObj : public IObject {};

int main() {
    Node* node = new ObservableNode();
    DummyObj obj;
    node->notifyObservers(obj);  // SingleObservable::notifyObservers
}

请注意,当ObservableNodeNodeSingleObservable派生时,我们不需要虚拟继承。
最后,如果我们想让Node是非抽象的(特别是为了提供对void notifyObservers(IObject*)的重写),那么ObservableNode必须提供自己的(final)重写,否则我们将会继承ObservableNode中两个最终的重写(一个来自Node,一个来自SingleObservable)。在这种情况下,ObservableNode可以简单地定义自己的重写,并显式调用所选择的基类,例如。
class Node: public virtual IObservable {
  public:
    virtual ~Node() {};
    void notifyObservers(IObject*) override { 
        std::cout << "Node::notifyObservers";
    };
};

class SingleObservable: public virtual IObservable {
  public:
    virtual ~SingleObservable() {};
    void notifyObservers(IObject*) override { 
        std::cout << "SingleObservable::notifyObservers";
    };
};

class ObservableNode: public Node, public SingleObservable {
  public:
    virtual ~ObservableNode() {};
    // Non-ambiguous final override in ObservableNode.
    // We could use `override` specifier here, but we might as well
    // use `final`, if we are not expecting something to derive from ObservableNode.
    void notifyObservers(IObject* obj) final { 
        SingleObservable::notifyObservers(obj);
    };
};

struct DummyObj : public IObject {};

int main() {
    Node* node = new ObservableNode();
    DummyObj obj;
    node->notifyObservers(obj);  // SingleObservable::notifyObservers
}

请参考ISO C++ FAQ - Inheritance — Multiple and Virtual Inheritance,了解关于菱形继承结构和虚拟继承的详细信息。

0

感谢所有的建议!实施这些建议会导致其他使用Observable实现的类出现很多问题,因此我选择了另一种方式来解决它,即包含一个实现实例并将所有方法委托给该实例。

class IObject {
    public:
    virtual ~IObject() {};
};

class IObservable {
  public:
    virtual ~IObservable() {};
    virtual void notifyObservers(IObject*) = 0;
};

class SingleObservable: public IObservable {
  public:
    virtual ~SingleObservable() {};
    void notifyObservers(IObject*) override { 
        std::cout << "Single\n";
      //some implementaiton
    };
};

class MultiObservable: public IObservable {
  public:
    virtual ~MultiObservable() {};
    void notifyObservers(IObject*) override { 
        std::cout << "Multi\n";
      //some other implementaiton
    };
};

class Node: public IObservable {
  public:
    virtual ~Node() {};
    // void notifyObservers(IObject*) override { };
};

class SingleObservableNode: public Node {
  public:
    SingleObservableNode() {};
    virtual ~SingleObservableNode() {
        delete obs;
    };
    void notifyObservers(IObject* obj) override { 
        obs->notifyObservers(obj);
    }
    private:
     IObservable* obs = new SingleObservable();
};


class MultiObservableNode: public Node {
  public:
    MultiObservableNode() {};
    virtual ~MultiObservableNode() {
        delete obs;
    };
    void notifyObservers(IObject* obj) override { 
        obs->notifyObservers(obj);
    }
    private:
     IObservable* obs = new MultiObservable();
};

Node* node1 = new SingleObservableNode(); 
Node* node2 = new MultiObservableNode(); 

int main()
{
    node1->notifyObservers(nullptr);   // "Single"
    node2->notifyObservers(nullptr);   // "Multi"
   return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接