@Sektr

Указатель на функцию члена класса. Как решить?

У меня есть map <std::string, void (*)()> keyEvents
Здесь мне нужно задать новый элемент мапу: метод объекта типа Script. Но компилятор ругается и говорит неверное преобразование типов.
void KeyEvent::Subscribe(Script* script)
{
    keyEvents["KeyPress"] = script->OnKeyPress;
}

Вызываю собственно статический метод и передаю его указатель на сам объект.
Script::Script()
{
    KeyEvent::Subscribe(this);
}

Вот так пытаюсь вызвать через указатель:
keyEvents["KeyPress"]();
Метод OnKeyPress класса Script выглядит вот так:
virtual void OnKeyPress() = 0;
  • Вопрос задан
  • 642 просмотра
Решения вопроса 2
Вам нужен std::bind для каррирования вашего метода. Нестатический метод обязательно принимает неявно первым параметром указатель на объект, у которого он вызывается. Тот самый this. Т.е. метод без параметров на самом деле является функцией с 1 параметром. Вот этот параметр и нужно зафиксировать, превратив метод в настоящую функцию без параметров.

#include <functional>
#include <iostream>
#include <string>
#include <map>

class Foo {
public:
	Foo(std::string msg): m_msg(msg) {}
	void event() {
		std::cout << m_msg << std::endl;
	}
private:
	std::string m_msg;
};

int main() {
	auto foo = new Foo("Foo");
	auto bar = new Foo("Bar");

	std::map<std::string, std::function<void ()>> keyEvents = {
		{"foo", std::bind(&Foo::event, foo)},
		{"bar", std::bind(&Foo::event, bar)}
	};

	for(auto callback: keyEvents) {
		std::cout << callback.first << ":";
		callback.second();
	}

	keyEvents.clear();
	delete foo;
	delete bar;
	return 0;
}
Ответ написан
Комментировать
romy4
@romy4
Exception handler
Можно через функтор (std::function). я не помню уже точно, но видел такую реализацию. копайте в эту сторону.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
petermzg
@petermzg
Самый лучший программист
В С++ методы класса отличаются от обычных функций и статических методов класса тем, что
имеют дополнительный скрытый параметр на инстанс класса.
По этой причине вы не можете передать KeyEvent::Subscribe в тип void (*)()

Чтобы сохранить указатель на ваш метод класса надо обьявлять тип так:
void (Script::*)()
Но в этом случае вы получаете жесткую привязку к данному классу.

Если вам нужны методы разных классов, то такую задачу лучше решить через интерфейсы.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы