Question

typedef void (FunctionSet::* Function)();

class MyFunctionSet : public FunctionSet
{
protected:
    void addFunctions()
    {
        addFunction(Function(&MyFunctionSet::function1));
    }

    void function1()
    {
        // Do something.
    }
};

The addFunction method adds the function to a list in the base class,
which can then be enumerated to call all functions.

Is there any way to simplify (less typing work) the adding of functions?

Was it helpful?

Solution

Looks like you assign a member function pointer to a function of the derived class to a member function pointer to a function of the base class. Well, that's forbidden, because it opens up a hole in the type-system. It comes at a surprise (at least for me, the first time i heard that). Read this answer for why.

To answer your actual question - i would make addFunction a template:

void addFunctions() {
    addFunction(&MyFunctionSet::function1);
}

Change addFunction in the base-class to this:

template<typename Derived>
void addFunction(void(Derived::*f)()) {
    myFunctions.push_back(static_cast<Function>(f));
}

Better use static_cast, because it will tell you if Derived isn't actually derived from FunctionSet.

OTHER TIPS

Can you explain what you're trying to achieve by doing this?

This seems like a fairly bad design, can't you have an abstract class ("c++ interface") such as "Computable" that has a pure virtual function1, subclass Computable for each implementation, and then have MyFunctionSet maintain a set of Computable?

Is there a specific reason you're using function pointers?

So, I tend to disagree with Uri, somewhat.

If you are implementing the Observer pattern, what you want is to be able to say:

"When object X does Y, I want to execute code Z".

Going with an approach based purely on an abstract class is not the best way to do that. Requiring a separate class (especially in C++) for every event handler is overkill. If you come from Java, that's how they do everything. However Java has 2 features that makes this only slightly annoying: anonymous class, and "instance" member classes. This allows you to define multiple handlers for multiple events in the same class. You have to prefix the methods with "class {", but you can do it.

C++ does not have either anonymous classes or "instance" member classes. This makes using an abstract class for events much more cumbersome if you have multiple handlers that need to share state. You have to do the equivalent of closure generation by hand, which can get pretty irritating pretty quickly.

.NET uses delegates for event handling, which are basically type safe function pointers. They make the code for handling events very straight forward. Unlike function pointers in C++, however, a delegate unifies member function pointers and static function pointers. Basically it can curry the "this" parameter of any member function, leaving a function pointers that looks just like a static function pointer. This means that the type of the object handling the event is not part of the event "interface". That makes it very flexible.

You can't do that directly using C++ member function pointers because the "this" type ends up being a part of the function pointer type, thus limiting your handlers to only appearing within the current class.

The best solution for C++ is a hybrid between the two. What you want is a generic interface like this:

class EventHandler
{
public:
    virtual void Handle() = 0;
};

And then an implementation for member functions like this

template <class T>
class MemberFuncEventHandler : public EventHandler
{
public:


    MemberFuncEventHandler(T * pThis, void (T::*pFunc)()) : m_pThis(pThis), m_pFunc(pFunc)
    {
    }

    void Handle()
    {
        (m_pThis->*m_pFunc)();
    } 
private:
    T* m_pThis;
    void (T::*m_pFunc)();
};

template <class T>
EventHandler * Handler(T * pThis, void (T::*pFunc)())
{
    return new MemberFuncEventHandler<T>(pThis, pFunc);
}

You can also similarly define a handler class for static methods. Then you can just do things like this:

Handlers += Handler(obj, &(c1::foo));
Handlers += Handler(obj, &(c2::bar));
Handlers += Handler(blaa); // for static methods...

You could overload the addition operator, I suppose.

If you're trying to make a callback system or something I would recommend the Boost.Signals library. Basically it aggregates functions and calls the function group on command (like any other signal library) but it is also designed to work with Boost.Bind and Boost.Function which are awesome.

Example:

using boost::function
using boost::bind
using boost::signal

void some_other_func();    

Foo a;
Bar b;

signal<void()> sig;

sig.connect(bind(&Foo::foo,&a));
sig.connect(bind(&Bar::bar,&b));
sig.connect(some_other_func);

sig(); // calls -> a.foo(), b.bar(), some_other_func()

Also supports blocking, sophisticated connection management and other neat stuff.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top