Disclaimer: I haven't been able to clearly describe exactly what I am trying to do, so I hope the example will be clearer than my explanation! Please suggest any re-phrasing to make it clearer. :)
Is it possible to override functions with more specific versions than those required by an interface in order to handle subclasses of the parameters of methods in that interface separately to the generic case? (Example and better explanation below...) If it can't be done directly, is there some pattern which can be used to achieve a similar effect?
#include <iostream>
class BaseNode {};
class DerivedNode : public BaseNode {};
class NodeProcessingInterface
{
public:
virtual void processNode(BaseNode* node) = 0;
};
class MyNodeProcessor : public NodeProcessingInterface
{
public:
virtual void processNode(BaseNode* node)
{
std::cout << "Processing a node." << std::endl;
}
virtual void processNode(DerivedNode* node)
{
std::cout << "Special processing for a DerivedNode." << std::endl;
}
};
int main()
{
BaseNode* bn = new BaseNode();
DerivedNode* dn = new DerivedNode();
NodeProcessingInterface* processor = new MyNodeProcessor();
// Calls MyNodeProcessor::processNode(BaseNode) as expected.
processor->processNode(bn);
// Calls MyNodeProcessor::processNode(BaseNode).
// I would like this to call MyNodeProcessor::processNode(DerivedNode).
processor->processNode(dn);
delete bn;
delete dn;
delete processor;
return 0;
}
I want to be able to implement several different concrete NodeProcessor
s some of which will treat all nodes the same (i.e. implement only what is shown in the interface) and some of which will distinguish between different types of node (as in MyNodeProcessor
). So I would like the second call to processNode(dn)
to use the implementation in MyNodeProcessor::processNode(DerivedNode)
by overloading (some parts/subclasses of) the interface methods. Is that possible?
Obviously if I change processor
to be of type MyNodeProcessor*
then this works as expected, but I need to be able to use different node processors interchangeably.
I can also get around this by having a single method processNode(BaseNode)
which checks the precise type of its argument at run-time and branches based on that. It seems inelegant to me to include this check in my code (especially as the number of node types grows and I have a giant switch statement). I feel like the language should be able to help.
I am using C++ but I'm interested in general answers as well if you prefer (or if this is easier/different in other languages).
Yes, you can have overloaded methods (methods with the same name different parameters) in an interface. You can implement this interface and achieve method overloading through its methods.
Overloading Methods Method overloading can be achieved by the following: By changing the number of parameters in a method. By changing the order of parameters in a method. By using different data types for parameters.
Overloading. If two methods of an interface (whether both declared in the same interface, or both inherited by an interface, or one declared and one inherited) have the same name but different signatures that are not override-equivalent (§8.4. 2), then the method name is said to be overloaded.
In Java, two or more methods may have the same name if they differ in parameters (different number of parameters, different types of parameters, or both). These methods are called overloaded methods and this feature is called method overloading. For example: void func() { ... } void func(int a) { ... }
No, that's not possible this way. The virtual method dispatch happens at compiletime, i.e. is using the static type of the Processor pointer, namely NodeProcessingInterface
. If that base type has only one virtual function, only that one virtual function (or its overriding implementations) will be called. The compiler has no way to determine that there migth be a derived NodeProcessor class implementing more distinguished functions.
So, instead of diversifying the methods in derived classes, you'd have to do it the other way round: Declare all different virtual functions that you need in the base class override them as needed:
class NodeProcessingInterface
{
public:
virtual void processNode(BaseNode* node) = 0;
//simplify the method definition for complex node hierarchies:
#define PROCESS(_derived_, _base_) \
virtual void processNode(_derived_* node) { \
processNode(static_cast<_base_*>(node)); \
}
PROCESS(DerivedNode, BaseNode)
PROCESS(FurtherDerivedNode, DerivedNode)
PROCESS(AnotherDerivedNode, BaseNode)
#undef PROCESS
};
class BoringNodeProcessor : public NodeProcessingInterface
{
public:
virtual void processNode(BaseNode* node) override
{
std::cout << "It's all the same.\n";
}
};
class InterestingNodeProcessor : public NodeProcessingInterface
{
public:
virtual void processNode(BaseNode* node) override
{
std::cout << "A Base.\n";
}
virtual void processNode(DerivedNode* node) override
{
std::cout << "A Derived.\n";
}
};
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