Передача состояний StateMachine в качестве параметра в указатель на функцию C ++ OOP

Я довольно новичок в концепции указателя функции в C ++, поэтому не знаю, как правильно написать свой вопрос. Пожалуйста, потерпите меня.

По сути, я пытаюсь создать объект Button, конструктор которого принимает указатель на функцию в качестве параметра. Этот указатель на функцию указывает на функцию, которая изменит состояние StateMachine.

Вот пример кода (он не работает, и ненужные биты были удалены)

button.h

#include "StateMachine.h"
class Button
{
private:
void (*m_onclickAction)();    //a data member
public:
Button(void (*action)());
};

StateMachine.h (я не писал его, я просто использую его с разрешения. Поэтому с кодом не должно быть проблем, и я не хочу его изменять)

#include <map>

template<class E, class T>
class StateMachine
{
public:
typedef void (T::*CallbackOnInitialise)();
typedef void (T::*CallbackOnExit)();
private:
T* m_pOwner;
E m_currentState;

// Maps to store function pointers to state functions.
std::map<E, CallbackOnInitialise> m_statesOnInitialise;
std::map<E, CallbackOnExit> m_statesOnExit;

public:
StateMachine(T* pOwner, E emptyState)
{
m_currentState = emptyState;
m_pOwner = pOwner;
}

void ChangeState(E statenext)
{
//do something to change the state
}
};

Так что в моем основном классе программы я мог бы сделать что-то вроде этого

#include "Button.h"#include "StateMachine.h"
//Code to instantiate an StateMachine object goes here
Button* aButton = new Button(aStateMachine->ChangeState(NEW_STATE));

Проблема в том, что я не могу придумать, как правильно передать NEW_STATE, который является перечислением, объявленным в классе Program, так как указатель на функцию не ожидает никаких параметров. Я пытался настроить его, но безуспешно.

Любое предложение о том, как мне это сделать?

2

Решение

У вас есть пара проблем здесь. Во-первых, в вашей версии вы вызов ChangeState функция-член, когда вы создаете Button пример. Второе, что m_onclickAction является указателем на функцию, которая не совпадает с указателем на функцию-член.

Для этого я предлагаю вам заглянуть в std::function а также std::bind:

class Button
{
std::function<void(int)> m_onclickAction;

public:
Button(std::function<void(int)> action) { ... }
};

Затем вы можете создать свою кнопку следующим образом:

Button* aButton = new Button(
std::bind(&StateMachine::ChangeState, aStateMachine, NEW_STATE));
0

Другие решения

Для обратных вызовов boost :: bind () и boost :: function () — очень полезный инструмент. Так что ваш класс Button может выглядеть так:

class Button
{
public:
typedef boost::function<void()> Callback;
Button( Callback clickAction );
private:
Callback m_onclickAction;    //a data member
};

Код для передачи метода StateMachine с параметром будет:

Button* aButton = new Button( boost::bind( &StateMachine::ChangeState, aStateMachine, NEW_STATE ) );

Если вы используете C ++ 11, вы можете заменить boost :: bind на std :: bind, а boost :: function на std :: function.

0

В библиотеке есть ошибка дизайна.

Проблема в том, что указатель на функцию — это просто указатель на функцию в C ++ (не замыкание), и поэтому он не имеет никакого контекста.

Если вы хотите создать кнопку, которая рисует синий круг, вам понадобится глобальная функция это нарисует синий круг без параметров.

Если вы хотите, чтобы другая кнопка нарисовала желтый круг, вам понадобится еще одна глобальная функция, которая рисует желтый круг без параметров.

Более конкретно, проблема в том, что библиотека не имеет никакого способа сохранить в кнопке то, что называется «контекстом», чтобы можно было передать вашему коду цвет, используемый для рисования круга.

В C ++ 11 добавлено что-то, что немного напоминает замыкания (это не совсем так из-за проблем на протяжении всей жизни, которые трудно решить на любом языке без сборки мусора), но они не являются пустыми указателями на функции.

То, что вы хотите сделать, просто невозможно без изменения Button класс, если вы не используете какой-то плохой взломать как тот, который вы можете увидеть здесь который пытается подражать std::bind в C с помощью голых указателей на функции.

0
По вопросам рекламы [email protected]