0

I am writing a program that performs a basic set of operations, but allows the user to fill in the specific functions that are called (and they choose those functions before compiling). For example, my program may call a function filter(input,&output) but the user can write their own filter.

The ways I've read about that may solve this problem are function pointers and virtual functions. It looks like I can either do something along the lines of

int (*pt2Filter)(float,&float) = NULL;
int IIRFilter(float input, float &output);
pt2Filter=&IIRFilter;

for a function pointer. But that doesn't let me keep track of internal states in the filter.

Or I could make a class myClass with a virtual filter function, and then the user would make an IIR class that inherits from myClass and overwrites the filter function.

class myClass
{
    virtual void Filter(float input, float &output);
    ...
};

class IIR : public myClass
{
    float stateVariable;
    virtual void Filter(float input, float &output);
}

void IIR::Filter(float input, float &output)
{ //IIR filter done here }

I guess my question is how do I call the filter function from my program without knowing that an IIR class even exists?

Or if I'm going about this completely wrong, how do I go about calling my Filter function when my goals are to 1: let the user define whatever filter they want. 2: Don't allow the user to change my source code

Update This may have not been as difficult as I first thought. I created a header file where the users will say which function they want the Filter class to call using the line

//User types this into "FunctionImplementations.h"
#include "IIR.h"
typedef IIR FilterImplementation;
//then I just type
#include "FunctionImplementations.h"
FilterImplementation.filter(); //Implements IIR classes filter function
4

2 に答える 2

3

There are several ways you can achieve this kind of polymorphism.

The main question is whether you need compile-time polymorphic behavior or run-time polymorphic behavior. In the first case, the solution is usually to define a function (or class) template to perform your generic work, and have it parameterized with the type of the callable object to be invoked by your generic code for doing the customized part of the job:

// This is how you would define your generic procedure
template<typename F> void do_something(F f, ...) 
{ 
    ...
    f(...); 
    ... 
}

// This is how you would use it...
void my_func(...) { ... };
do_something(&my_func, ...); // with a function pointer

do_something([] (...) { ... }, ...); // with a lambda

struct my_functor { operator void () (...) { ... } };
do_something(my_functor(), ...); // with a functor

If the type of the object which defines the customized behavior is determined only at run-time, then you have two possibilities: either you use std::function<> for encapsulating your callback, or you go with the virtual function approach. I personally would prefer the former, because it does not force you to create a hierarchy of inheritance just for the purposes of achieving dynamic polymorphism.

This is how you use a std::function<> object:

void my_func1(int, int) { ... }
void my_func2(int, int) { ... }

std::function<void(int, int)> fxn = &my_func1;
fxn(2, 3);
...
fxn = &my_func2;
fxn(3, 4);
...
fxn = [] (int x, int y) { ... };
fxn(4, 5)

This is how you could take advantage of it for defining your generic procedure:

void do_something(std::function<void(int, int)> f, ...)
{
    ...
    f(3, 4);
    ...
}

At this point, you can invoke do_something() with anything that can be assigned to an std::function (i.e. any callable object with a compatible signature).

于 2013-01-22T17:30:22.673 に答える
1

If you need this to be done at compile-time, you may consider using templates over inheritance. An example:

template<typename Derived> // Derived is having DoActualWork
class WorkerBase
{
public:
   DoWork()
   {
       ((Derived*)this)->DoActualWork();
   }

};

class MyWorker : public WorkerBase<MyWorker>
{
public:
   void DoActualWork() {...}
};

Here MyWorker is inheriting from class template WorkerBase passing itself as type-argument to template. The conversion from this to Derive is needed, and will work, since this object is actually derived class.

Note that this is one of the technique for compile-time polymorphism, using classes. Through templates, you may have such feature in other ways. std::map can be used with std::greater!

于 2013-01-22T17:28:07.517 に答える