Function pointers and inheritance

Mar 20, 2010 at 9:35pm
Hi All,

This is more of an aesthetic problem I have.

My project (in bold the class names): Creating a simple game engine using OpenGL (Qt style)
There is a big Game class, which handles most of the OpenGL stuff. The plan is: the user inherits the Game class to extend it (Let's call the new Class MyGame). Game inherits from EventManager (a singleton). And here is where my problem comes in: I want the user to be able to create a method; let's call it

void keyPressEvent(Key key)

This method must not be static (else it would be pretty useless to the user). So the function pointer will be in the format

void (MyGame::*keyPressEvent)(Key key)

Now I have in the class Game a function that will pass the user-defined function to the singleton (EventManager) which handles the callbacks. (In order to do that the functions to pass on to OpenGL have to be static!)

And from that it should also be clear why EventManager is a singleton. Now while passing the function pointer on to the method

void setKeyboardFunc(void (MyGame::*func)(Key key))

in Game I ran in to a problem: what is MyGame?
I found some solutions which are only semi-elegant, but I'm sure there is a more "beautiful" one out there.

My solutions:
- reinterpret_casting it to Game (which feels kinda awkward to do imho)
- template (i.e. Game<MyGame>) which will be able to tell me the type
- creating an abstract function pointer (with the use of variadic templates; see below)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template <typename ret, typename... args>
class AbstractFptr {
    public:
        virtual ret operator()(args... a) = 0;
};

template <class C, typename ret, typename... args>
class Fptr : public AbstractFptr<ret, args...> {
    private:
        C& obj;
        ret (C::*fun)(args...);
 
    public:
        Fptr(C& o, ret (C::*f)(args...))
            : obj(o), fun(f) {}
 
        ret operator()(args... a) {
            (obj.*fun)(a...);
        } 
}; 


Is there some other way to elegantly do this (without variadic templates ;-) )??

Thanks in advance!
Mar 20, 2010 at 10:21pm
You seem to have gotten yourself into quite a bit of a mess.
Your solutions won't work:
- Casting between function pointer types is not allowed. It's specially dangerous when casting between member function pointer types.
- Templates carry compile time information, and you're using run time information.
- Unless you're already writing in C++0x, there's no such thing as "variadic templates".

What I suggest you do is you change the callback type to void (*)(void *,Key). Now the user can pass whatever type they want and the function won't see the difference. It's the user who'll have to compensate for the type.
For example,
1
2
3
4
5
6
7
class Derived:Game{
    //...
    void callback(Key key);
    static void static_callback(void *_this,Key key){
        ((Derived *)_this)->callback(key);
    }
};
Mar 20, 2010 at 11:14pm
Thank You, but you must have misunderstood (or maybe I did).

I need to get the function pointer up to the singleton!
There I have a function (static) declared for the (e.g keyboard) callback.
The OpenGL function:
void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y));
Thus the function I pass to this function has to be static.
Mar 20, 2010 at 11:45pm
Sorry, I don't get what you're saying. Could you post your class declarations, plus the function that calls glutKeyboardFunc()?
Mar 20, 2010 at 11:53pm
Not 100% sure what your asking for but you want to checkout functors. These are are available in boost and loki. They allow for both methods and functions pointers to be used in a simplified way.
Mar 21, 2010 at 12:49am
That should summarize it a little bit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class EventHandler { };
class EventManager {
    private:
        static void (EventHandler::*keyPress)(Key key); // Function pointer that will be inside keyPressEvent
        static void keyPressEvent(unsigned char key, int x, int y); // Function to pass into glutKeyboardFunc
    protected:
        EventManager();
    public:
        static EventManager& instance(); // Returns instance of class
        void setKeyListener(void (EventHandler::*func)(Key key));
};

void EventManager::keyPressEvent(unsigned char key, int x, int y) {
    EventManager &em = instance();
    em.*keyPress(reinterpret_cast<Key>(key));
}

class Game : public EventManager {
    private:
         /* stuff */
    protected:
        void setKeyboardFunc(AbstractFptr<void,Key> fptr); // Here is the problem
    /*Rest of class*/
};

class Derived : public Game {
    /* stuff */
    protected:
        void kbdfunc(Key key);
    public:
        void init();
};

void Derived::init() {
    setKeyboardFunc(kbdfunc);
}


Thanks for taking your time :-)... really appreciate it
Mar 21, 2010 at 2:13am
Yeah really looks like you want to go with a loki functor or if you've got the latest version of C++ its now part of stl (I haven't upgraded no I'm not 100% on its format). Here's loki's:

#include <Functor.h> //Assumes you've added loki to your c++

typedef Loki::Functor<void, LOKI_TYPELIST_1(Key)> EventKeyPress; //Always good to use typedefs for maintainability


class Game : public EventManager {
private:
/* stuff */
protected:
void setKeyboardFunc(EventKeyPress fptr); // Here is the problem
/*Rest of class*/
};

Something like that... you can store it as an object and call it like:

EventKeyPressObj(key);

A lot of the little gotchas like threading issues have been solved in loki (and the stl C++, boost etc...) so you might as well take advantage of it... along with other solutions to common patterns it provides.
Mar 21, 2010 at 10:22am
Thank you :-)
Mar 21, 2010 at 12:08pm
As hohums said, Loki's functor, boost::function or std::function provide nice wrappers for member function calling.

An other way to use the current means of standard library would be to use std::bind1st and std::mem_fun to convert the member function into a "global" function. I think it should look along those lines, but probably a bit different in syntax: "setKeyboardFunc( std::bind1st( std::mem_fun(kbdfunc), this );"

I never got the hang of bind1st and mem_fun, and since my compiler ships with std::bind (similar to boost::bind), it will look plain boring simple like this:

1
2
3
4
5
6
7
    typedef void(*EventKeyPress)(const Key&);
    ...
    void setKeyboardFunc(EventKeyPress fn);
...
void Derived::init() {
    setKeyboardFunc( std::bind(kbdfunc,this) );
}


Can't think of any simplier solution :-D

Ciao, Imi.
Topic archived. No new replies allowed.