How to represent generically a parameter using OO?
In C++, I have to implement several algorithms, which represent different ways to compute the same thing.
I thought about using an interface to represent the different algorithm.
class AlgorithmInterface
{
public:
virtual double ComputeSomething(void* parameter) = 0;
}
class AlgorithmImplementation1: public AlgorithmInterface
{
public:
virtual double ComputeSomething(void* parameter) { /* implementation */}
}
class AlgorithmImplementation2:开发者_开发问答 public AlgorithmInterface
{
public:
virtual double ComputeSomething(void* parameter) { /* implementation */}
}
However the parameter (a void* in the previous example) for each of these are different, how can I represent them generically ?
I used a void* for the example, just because I do not know how to represent this. Please tell me how I should do this: should I make the equivalent inheritance for the parameters and cast them ? (this seems ugly to me)
You can pass the parameters in the constructor.
Additionally make the virtual member private and make the object a functor:
class AlgorithmInterface
{
public:
double operator()() {return this->ComputeSomething();}
private:
virtual double ComputeSomething() = 0;
}
class AlgorithmImplementation1: public AlgorithmInterface
{
virtual double ComputeSomething() { /* implementation */}
public:
AlgorithmImplementation1(Parameter 1);
}
class AlgorithmImplementation2: public AlgorithmInterface
{
virtual double ComputeSomething() { /* implementation */}
public:
AlgorithmImplementation2(Item a1,Item a2);
}
int main()
{
AlgorithmImplementation2 job(Item(12), Iterm(13));
double result = job(); // execute;
}
(Based on my understanding of your question) If the computation remains the same and just the parameter types vary, then you can use templates..
One other possibility would be to pass in a "parameter stream" to the algorithms. An algorithm could take a reference to a ParameterStream.
The derived algorithms would then extract the appropriate types (number) of parameters from the stream accordingly. The stream implements type safe extraction (de-serialization) of the parameters, and could also implement (if desired) versioning.
This possibility would IMHO have the advantage that you can keep the interface immutable even if in the future different algorithms will need a different number of parameters.
So basically you would send a parameter that contains a serialized form of the parameters you need and you de-serialize/validate them as you need them in the algorithm implementation.
As mentioned by the previous posters templates could also an option if things are clear cut at compile time.
Either you use classic OO (run-time) polymorphism, in which case the parameter needs to be a base class pointer/reference, to which derived class objects can be passed, or you switch to templates and compile-time polymorphism, as the STL does, and pass the algorithm and the parameter as an instance of a template parameter.
With templates, this is what your code might look like:
class AlgorithmImplementation1
{
public:
virtual double ComputeSomething(Param1* parameter) const
{ /* implementation */}
}
class AlgorithmImplementation1
{
public:
virtual double ComputeSomething(Param2* parameter) const
{ /* implementation */}
}
template< typename Algorithm >
void use_algorithm(const Algorithm& algorithm)
{
// ...
// get_parameter() _must_ return whatever the algorithm takes
double d = algorithm( get_parameter() );
// ...
}
Param1 get_parameter();
void f()
{
use_algorithm( AlgorithmImplementation1() );
}
Do you really need the inheritance? If you do, then templating the function will not be an option (i.e. you cannot have a virtual function template - at least in the current standard) and Martin's solution works. If you don't need inheritance, then the below should suffice
class AlgorithmImplementation1
{
public:
template <typename ParamType>
double ComputeSomething(ParamType const& parameter) { /* implementation */}
}
class AlgorithmImplementation2
{
public:
template <typename ParamType>
double ComputeSomething(ParamType const& parameter) { /* implementation */}
}
This of course depends on how you plan to use parameter
, you may be better off using overloading (for example, treat int
different to string
), if your parameter
has a consistent interface then the function template will suffice.
精彩评论