I have an abstract base class Node
, which is derived from an abstract Interface class IObservable
.
There is a several classes implementing the abstract IObservable
: SingleObservable
and MultiObservable
I want to create a class ObservableNode
, derived from the base Node
class and specify on its declaration which class to use for the implementation of the IObservable
interface.
I've added using ...
statements for every pure virtual method in IObservable
, referring to the methods in the implementation classes but I still get errors saying that ObservableNode
is an abstract class, missing the implementation of notifyObservers(IObject*)
.
If I add the parameter IObject*
to the using
statement I get an "expected ';' before '(' token" error
How can I solve this?
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
The implements keyword is used to implement an interface . The interface keyword is used to declare a special type of class that only contains abstract methods. To access the interface methods, the interface must be "implemented" (kinda like inherited) by another class with the implements keyword (instead of extends ).
A delegate is a reference type variable that holds the reference to a method. The reference can be changed at runtime. Delegates are especially used for implementing events and the call-back methods. All delegates are implicitly derived from the System. Delegate class.
A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.
Delegation refers to the transfer of responsibility for specific tasks from one person to another. From a management perspective, delegation occurs when a manager assigns specific tasks to their employees.
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.
@πάντα ῥεῖ'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 meannode->notifyObservers(obj)
will invokeNode::notifyObservers(IObject*)
and notSingleObservable::notifyObservers(IObject*)
, which might be unexpected, considering we instantiate anObservableNode
object which specifies usingSingleObservable::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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With