views:

312

answers:

5
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?

+1  A: 

You could overload the addition operator, I suppose.

mmr
+1  A: 

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?

Uri
Functors are usually *more* efficient than function pointers. But that is when they are implemented without virtual functions. In any case, "creating classes" is nonsense, and there is zero overhead to that. It smells like premature optimization to me.
jalf
What exactly are you doing that you care enough about efficiency over good OO principles? Dynamic binding is just as efficient as manually managing your own function pointers.
Uri
I guess that is a matter of style and of the actual project. Function pointers in C++ are dangerous. If your concern is saving typing, use a better IDE or a CASE tool.
Uri
In one of my jobs, we represented an entire computer system down to small registers and instruction formats with a class hierarchy, and we were very happy using Rose to do all the grunt work for us.
Uri
Also, IMHO, if this is production code that others may maintain, you don't want to use language features that require an above average programming to understand and maintain. If this is personal code, different story.
Uri
+2  A: 

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.

Johannes Schaub - litb
TomWij
nope, no way :/ wait i mean if you assign the pointer without the case - then that is forbidden. sounds like you mistook that, i didn't want to say your code was forbidden by C++. sorry if it sounds a bit unclear :)
Johannes Schaub - litb
+2  A: 

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...
Scott Wisniewski
Creating a separate class is not an overkill in terms of design, just in terms of typing (after all, Java and C# create classes when you use anonymous). I feel that a CASE tool or good IDE can save that work while still maintaining good design.
Uri
While I like your code a lot, I doubt that the average (non SO addict) C++ programmer would be able to understand and maintain it correctly, and thus would be wary of using it in production.
Uri
I'm not sure the code is that difficult...It took me about 5 mins to write. Most of time was just getting the member function pointer syntax right.I think there are implementations in boost (like someone mentioned below) that can just be downloaded, and will probably be in the standard soon.
Scott Wisniewski
Uri,About the CASE tool... I wrote my opionion about this on my blog. You can read it athttp://www.specbug.com/blog/2009/1/21/scotts-law-of-software-2.html
Scott Wisniewski
+1  A: 

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.

I gave a more complicated example. If you look at the Boost.Signals docs you'll see that it is a really slick, minimal interface. For type-safe generic callbacks I haven't seen a better library.