Connor
Connor

Reputation: 19

C++: How to pass a function from any class as a parameter

I began implementing my GUI system for my game last night and I decided to try using function pointers to handle gui events. I haven’t used them before, but was able to get a basic implementation in. However, I want to extend the usability and ‘genericness’ of the GUI system. Currently I have a function pointer in the GUI superclass under the protected modifier. I also have a getter (callback) and a setter (subscribeEvent) in the class to assign the gui an event. It currently looks a little something like this:

class GUI
{
public:
    …….
    ……
    std::function<void()> callback() const { return eventCallback; }
    void subscribeEvent(const std::function<void()>& callback)
    { 
        eventCallback = callback; 
    }

protected:
    std::function<void()> eventCallback;
};

To set a function callback, you pass in a void function to subscribeEvent which works fine. However you cannot use a scope resolution modifier with any function, the function passed in has to be a global function like so.

(MainGame.h):

void global();

class MainGame
{
public:
    void Init();
    void nonGlobal();

private:
    std::vector<GUI*> _guis;
};

(MainGame.cpp):

void MainGame::Init()
{
    Button* button  = new Button(……); //< Button is a subclass of GUI
    button->subscribeEvent(global); //< This works fine
    button->subscribeEvent(MainGame::nonGlobal); //< This does not work saying something like “void(MainGame) is not of type void()”
    _guis.pushBack(button);
}

void MainGame::nonGlobal()
{
……
}

void global()
{
……
}

Does anyone know how to modify the parameter to allow any function in the scope of any class to be passed in. This would be helpful because I could have a button event come from a player, enemy, item, etc class and not have every handler function be global. I’ve seen high level gui systems pass in events such as ‘event(handlerFunction, classtype)’ so you can pass in the handler function and then an object that the handler function resides in. This is an approach I would like to take.

Upvotes: 0

Views: 264

Answers (2)

Arunmu
Arunmu

Reputation: 6901

Change this:

button->subscribeEvent(MainGame::nonGlobal); //< This does not work saying something like “void(MainGame) is not of type void()”

to

button->subscribeEvent(std::bind(&MainGame::nonGlobal, this)); 

With this change you have another problem of lifetime management of this though.

Upvotes: 0

Smeeheey
Smeeheey

Reputation: 10336

Your code would work if you made the function MainGame::nonGlobal static:

class MainGame
{
public:
    void Init();
    static void nonGlobal();

private:
    std::vector<GUI*> _guis;
};

The reason you can't pass a non-static member function is because member functions have an implicit first parameter (this), in your case of type MainGame*. So in effect the function you're currently trying to pass has the signature void(MainGame*) instead of void().

Alternatively, you can bind the this parameter by using a lambda instead of passing the function directly:

button->subscribeEvent([this](){nonGlobal();});

Upvotes: 1

Related Questions