Reputation: 2085
Is there a way to write an abstract base class that looks like it's forcing an implementer to choose among a myriad of pure virtual functions?
The abstract base classes I'm writing define a mathematically tedious function, and request that the deriving code define only building block functions. The building block functions can be generalized to take on more arguments, though. For example, in the code below, it might "make sense" to allow another_derived::first()
to take three arguments. The "mathematically tedious" part of this is the multiplication by 3
. Unsurprisingly, it won't allow won't compile unless I comment out the creation of d2
. I understand why.
One option is to create different base classes. One would request a single parameter function to be defined, and the other would request a two parameter function to be defined. However, there would be an enormous amount of code being copy and pasted between the two base class' definition of final_result()
. This is why I'm asking, so I don't write WET code.
Another option would be to have one pure virtual function, but change the signature so that its implementation can do either of these things. I want to explore this, but I also don't want to start using fancier techniques so that it puts a barrier to entry on the type of people trying to inherit from these base classes. Ideally, if the writers of the base class could get away with barely knowing any c++, that would be great. Also, it would be ideal if the inheritors didn't even have to know about the existence of related classes they could be writing.
#include <iostream>
class base{
public:
virtual int first(int a) = 0;
int final_result(int a) {
return 3*first(a);
}
};
class derived : public base {
public:
int first(int a) {
return 2*a;
}
};
class another_derived : public base {
public:
int first(int a, int b) {
return a + b;
}
};
int main() {
derived d;
std::cout << d.final_result(1) << "\n";
//another_derived d2; // doesn't work
return 0;
}
Upvotes: 1
Views: 140
Reputation: 218090
Not sure it matches exactly what you want, but with CRTP, you might do something like:
template <typename Derived>
struct MulBy3
{
template <typename... Ts>
int final_result(Ts... args) { return 3 * static_cast<Derived&>(*this).first(args...); }
};
class derived : public MulBy3<derived> {
public:
int first(int a) { return 2*a; }
};
class another_derived : public MulBy3<another_derived > {
public:
int first(int a, int b) { return a + b; }
};
With usage similar to
int main() {
derived d;
std::cout << d.final_result(1) << "\n";
another_derived d2;
std::cout << d2.final_result(10, 4) << "\n";
}
Upvotes: 2