Strategy pattern or function pointer

In C ++, when I have an algorithm that can take different actions at runtime, I rather use a function pointer.

For example, a chart drawing program has one algorithm for drawing a line, which can take any function to specialize the shape of that line.

There are no function pointers in Java and I am required to use either the strategy pattern or reflection (or some other pattern).

How do I enable custom behavior to be selected at runtime in my program? Strategy template or function pointer?

+1


source to share


3 answers


Java function pointers are implemented using functors. Create an interface with one function and pass instances to it instead of pointers to objects. Let your C ++ code look like this:

void func(void (*f)(int par));

      

In Java it would look like this:



public interface F {
  public void f(int par);
}

void func(F f);

      

Take a look at the Guava Function class . This is also not a bad approach for C ++. This is more readable and allows the user to pass stateful objects as opposed to static functions.

+2


source


There are several ways to implement the strategy pattern in C ++.

  • Use the OOP method like in other programming languages.
  • Use a function object.
  • Use a policy class.

All three can complete the task, which is chosen very much depends on your problem.

You mentioned that you want to use a strategy for drawing a chart. This is a tricky use case in my opinion and you will go with option one because your strategy object might ask for settings like preferred colors and so on, and you might want to save strategies somewhere so the user can select them in combo -boxing.

Functional object is really good if you want to give clients (your colleagues) more flexibility. In my current project, we are using functional objects to test the stop criterion in the algorithm. This works very well with lambdas in C ++ 11, as long as the functionality doesn't get too complicated.



The main policy path may be the fastest, but it must know the type at compile time. DLLs are not supported when using this module. At least until you encapsulate your implementation in a class hierarchy:

template <class LockPolicy>
class MyClass
{
  void do_something()
  {
    LockPolicy::lock();
    //...
    LockPolicy::unlock();
  }
};

      

I believe the good tips are:

  • Use 1. if the strategy is complex and may interfere with other systems.
  • Use 1.if you want new implementations of the strategy using the plugin
  • Use 2.if the strategy can be expressed in short lines of code
  • Use 2.if strategy implementations match free functions and you don't want to introduce a class hierarchy
  • Use 3.if you really know what you are doing and you need productivity.
+2


source


It totally depends on what you are doing with your functor. If you want to use it as a one-off to perform an operation, you want to use a template. See any of the standard algorithms for an example - for example std::sort

:

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
                                          ^^^^^^^^^^^^
                                          any functor that does comparing

      

If you want to save your functors for later use, you want std::function

a type-erasable functor:

class SaveFunctionForLater {
public:
    template <typename F>
    SaveFunctionForLater(F&& f)
        : func(std::forward<F>(f))
        { }

    int callMe(int i) { return func(i); }
                               ^^^^
                               use the saved one

private:
    std::function<int(int)> func; // function taking an int, returning an int
};

      

What would you like to use:

int f(int i) { return 2*i; }

template <int I>
struct Constant {
    int operator()(int ) { return I; }
};

SaveFunctionForLater add1([](int i){return i+1;});    // works with lambda
SaveFunctionForLater double(f);                       // works with func ptr
SaveFunctionForLater zero(Constant<0>{});             // works with object

cout << add1.callMe(2);                  // prints 3
cout << double.callMe(double.callMe(4)); // prints 16
cout << zero.callMe(42);                 // prints 0

      

You definitely don't want to use explicit function pointers - this will severely limit the usability of your class / function. You want people to pass objects too. It's C ++, after all, not C!

+1


source







All Articles