How to delegate to implementing class

@πάντα ῥεῖ's answer describe one workaround, but possible this is not what OP is after here. Also, as my comment describe under the answer, the approach in the answer might give unexpected results e.g. when invoking node->notifyObservers(obj):

Note that in this particular example, Node* node = new ObservableNode(); will mean node->notifyObservers(obj) will invoke Node::notifyObservers(IObject*) and not SingleObservable::notifyObservers(IObject*), which might be unexpected, considering we instantiate an ObservableNode object which specifies using SingleObservable::notifyObservers;.

In OP's original code, we are suffering from multiple inheritance ambiguity, as we are not using virtual inheritance when Node and SingleObservable (and MultiObservable) derives from IObservable:

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

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

Meaning our the object's memory layout, w.r.t. inheritance, of ObservableNode to looks like the following

 IObservable  IObservable
           |  |
        Node  SingleObservable
           \  /
       ObservableNode

whereas, in this context, we are likely to want an object's memory layout looking as follows

       IObservable
           /  \
        Node  SingleObservable
           \  /
       ObservableNode

If we were to correct this, Node can stay abstract, and a call to node->notifyObservers(obj) with node as OP's example will result in invocation of SingleObservable::notifyObservers, as might have been expected.

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
}

Note that we not need virtual inheritance for when ObservableNode derives from Node and SingleObservable.

Finally, if we'd want Node be non-abstract (specifically, to provide an override of void notifyObservers(IObject*)), then ObservableNode must provide it's own (final) override of it, as we will otherwise inherit two final overrides of it in ObservableNode (one from Node and one from SingleObservable). In this case, ObservableNode could simply define its own override which explicitly calls the base class of choice, e.g.

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
}

See ISO C++ FAQ - Inheritance — Multiple and Virtual Inheritance for details on the diamond inheritance structure and virtual inheritance.


Your problem seems to be that you inherit Node which is still abstract, and also causes to introduce the good old multimple inheritance vicious diamond problem. When I change your code like this, the error disappears:

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();
}

See it live on coliru.

Tags:

C++