I want to design a general C++ class that defines an operator() function that returns the value of a mathematical function at a point. However, I want that class to be able to be instantiated with either an object that already has the operator() defined or with a table of values that the class will interpolate to give the value. I thought about the following approach:
class MathFunction
{
MathFunction(Functor& function);
MathFunction(Mat<double> interpolationValues);
double operator()(double radius, double angle);
};
where the constructors could set a member variable and double operator() could use a switch statement to determine how to output the double I want. This seems awfully inelegant, though.
A templated version of this class could be of use, but since the two methods don’t share any code, would it be wise to do it? And how exactly would the templated version be designed?
Not sure if I’m clear. Please comment if any clarifications are needed.
EDIT: Although I chose Useless’s answer for its completeness, I want to underline the speed and clarity of dasblikenlight’s contribution. Thanks.
If
MathFunctiondoesn’t have any common implementation, what is it for?If its purpose is to provide a common interface to two implementations, consider where you’ll use it:
MathFunction, or in code which will always statically know which type it’s usingIn case 1, using something like the strategy pattern is reasonable. Either
MathFunctioncan be a statically-typed wrapper dispatching to a virtual Strategy, or you can write an abstract MathFunction base class, and instantiate one of two concrete subclasses.dasblinkenlight already demonstrated the Strategy version, so here is the ABC equivalent (notice how it can use a factory function to hide the implementation details)
In case 2, templating
MathFunctionis a good choice: you can either (partially-) specialize it, or use the compile-time equivalent of the Strategy pattern, which is to parameterize MathFunction on a Policy class, to which it delegates the evaluation. If performance is a concern, saving the virtual function call (and enabling in-lining) may be useful.The benefit of using a Policy over just writing two distinct concrete classes (
FunctionMathFunctionandTableMathFunction) comes in showing their relationship, in sharing any code that doesn’t depend on the policy, and in the ability to split unrelated concerns into separate policies.