Reputation: 877
I've declared a pure virtual method in the base class, but I want to make set of arguments in different derived classes to be different.
My current code is overloading functions in base class, which goes like:
class Base {
protected:
virtual void function(arg_set_first) = 0;
virtual void function(arg_set_second) = 0;
}
class Derived_First: public Base {
private:
void function(arg_set_first);
void function(arg_set_second) { } // do nothing
}
class Derived_Second: public Base {
private:
void function(arg_set_first) { } // do nothing
void function(arg_set_second);
}
It works but I think it's ugly, as there are redundant implementations in each derived class. I want to remove them.
How can I change the pure virtual function in the base class to have variable set of arguments which would be specified when is implemented? Is there a way to do so?
Upvotes: 2
Views: 1404
Reputation: 73091
Strictly speaking, you can't do it in C++ -- the parameter-list of a method (and the types of those parameters) are considered part of the method's type-signature, and therefore a child class's virtual method can only override/implement the parent class's virtual method if they both share the same name and the same exact parameters.
That said, you can sort of fake it by passing your arguments using a data-structure instead of directly. For example:
class Base {
protected:
virtual void function(const std::map<std::string, std::variant> & args) = 0;
}
With the above, you have a method that can take any set of named arguments, in the form of a set of key-value pairs. It would then be up to the child classes (and their callers) to agree on which argument-names and argument-values to use. The downside of this approach is that it's less efficient and harder to use (the caller has to create and populate a std::map
every time he wants to call the method, and the method has to examine the contents of the std:map
and figure out what to do with them); however if flexibility is your primary concern and performance isn't (e.g. because the method won't be called very often), this approach can work well.
Another approach would be to use multiple-inheritance, and specify separate interfaces for each of the two methods, and (just for convenience) also an interface class for subclasses that want to implement both:
class BaseFirst {
protected:
virtual void function(arg_set_first) = 0;
}
class BaseSecond {
protected:
virtual void function(arg_set_second) = 0;
}
class BaseBoth : public BaseFirst, public BaseSecond {
};
class Derived_First: public BaseFirst {
private:
virtual void function(arg_set_first) {...}
};
class Derived_Second: public BaseSecond {
private:
virtual void function(arg_set_second) {...}
};
class Derived_Both: public BaseBoth {
private:
virtual void function(arg_set_first) {...}
virtual void function(arg_set_second) {...}
};
Since any particular piece of calling code knows which of the function
methods it will want to call (and which it won't), it can simply specify the appropriate pointer/reference types in its API (e.g. BaseFirst *
, BaseSecond *
, or BaseBoth *
) to reflect its requirements, and the compiler will guarantee for you that only objects that actually meet those requirements can be passed to it.
Upvotes: 2