I'm a layperson in terms of software design. I'm facing an "issue" that perhaps is solved by some well known technique/idiom/pattern which I would like to be told about.
I have an abstract base class basically defining one pure virtual member function and little else. Then I have several classes deriving from this one and overriding the said virtual function. I have now half a dozen such classes and the number is growing. The classes have just a few data members (very few, like a couple of doubles or that plus a function pointer) and they differ mainly by the way they perform a very short computation. I wonder if this indicates a bad design and is better dealt in some other way.
If appropriate, could someone point me at a relevant design pattern or idiom I should know of. Thanks.
EDIT
To clarify things, the abstract base class doesn't have any data members. Not all derived classes have data members. What I'm doing is to have coordinate transformations for integrals as classes. A given transformation only need a couple of parameters and sometimes the user-supplied function.
If your abstract base class does not have any data members (and it seems like it shouldn't if it has one pure virtual method), then there is a better pattern for this indeed. Suppose we have this code:
struct AbstractBase {
virtual double calc(double) = 0;
virtual ~AbstractBase() = default
}
Now, you have to inherit from this in order to use things dynamically elsewhere:
struct Derived : public AbstractBase { ... }
void BaseUser(AbstractBase& ab) { ... };
A less coupled solution would just be to write your class as a function object and use std::function
.
struct Derived {
double operator()(double x) { ... };
}
void User(std::function<double(double)> f);
User(Derived{}); // Calls user with Derived routine.
This has other advantages as well, for instance if some of your derived classes don't actually need state, then you can just write them as plain functions and still pass them around in std::functions
. Yet another benefit is that you can write short functions inline as well now, because a lambda is a function object:
User([] (double x) { return 2*x; });
If you need more precision control than an abstract base class with a single virtual function call is ok, but when there's just one function in an interface I'd at least consider looking at function objects.
I wouldn't be concerned about the number of derived objects you have necessarily.