2016-07-13 2 views
0

Я начал внедрять свою систему GUI для своей игры прошлой ночью, и я решил попробовать использовать указатели функций для обработки событий gui. Я не использовал их раньше, но смог получить базовую реализацию. Однако я хочу расширить удобство и «универсальность» системы GUI. В настоящее время у меня есть указатель на функцию в суперклассе GUI под защищенным модификатором. У меня также есть getter (callback) и setter (subscribeEvent) в классе, чтобы назначить gui событие. В настоящее время она выглядит немного что-то вроде этого:C++: Как передать функцию из любого класса в качестве параметра

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

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

Чтобы установить функцию обратного вызова, вы передаете в функцию ничтожным subscribeEvent, которая прекрасно работает. Однако вы не можете использовать модификатор разрешения области с любой функцией, переданная функция должна быть глобальной функцией.

(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() 
{ 
…… 
} 

Кто-нибудь знает, как изменить параметр, чтобы разрешить любой функции в рамках любого класса, который будет принят. Это будет полезно, потому что я мог бы событие кнопку исходить от игрока, противника, пункт, и т. д., а не каждая функция обработчика должна быть глобальной. Я видел, что системы gui высокого уровня проходят в таких событиях, как «event (handlerFunction, classtype)», поэтому вы можете передать функцию обработчика, а затем объект, в котором находится функция обработчика. Это подход, который я хотел бы принять.

+2

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

ответ

1

Ваш код будет работать, если вы сделали функцию MainGame::nonGlobal статическую:

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

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

Причина вы не можете передать нестатический функции члена потому, что функции-члены имеют неявный первый параметр (this), в ваш случай типа MainGame*. Таким образом, функция, которую вы в настоящее время пытаетесь передать, имеет подпись void(MainGame*) вместо void().

В качестве альтернативы, вы можете связать параметр this с помощью лямбда вместо передачи функции непосредственно:

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

Изменить это:

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

в

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

С этим изменение у вас есть другая проблема управления жизненным циклом this.

+0

Большое спасибо! Я включил функцию std :: bind в функцию subscribeEvent, чтобы я мог вызвать & MainGame :: nonGlobal без std :: bind в коде MainGame. Я также сделал его общим, чтобы я мог включать функции с аргументами: std :: function callback() const {return eventCallback; } \t шаблон <Ьурепате Т, Р Ьурепате, Ьурепате ... Args> \t недействительными subscribeEvent (экземпляр T, F, функ арг ... арг) \t { \t \t вызова темп = {станд :: Bind (FUNC , instance, args ...)}; \t \t eventCallback = temp; \t} – Connor

Смежные вопросы