Ну, причиной использовать указатель было бы точно то же, которое причина использовать указатели в C выделила с malloc: если Вы хотите свой объект жить дольше, чем Ваша переменная!
Это даже настоятельно рекомендовано для НЕ использования нового оператора, если можно избежать его. Особенно, если Вы используете исключения. В целом намного более безопасно позволить компилятору освободить Ваши объекты.
Ваш подход требует, чтобы функции обратного вызова были либо свободными, либо статическими членами класса. Это не позволяет клиентам использовать функции-члены в качестве обратных вызовов. Одно из решений - использовать boost :: function в качестве типа обратного вызова:
typedef boost::function<void (MenuItem*)> callback_type;
AddItem(const std::string& s, const callback_type& callback = callback_type());
Клиенты могут затем использовать boost :: bind или boost :: lambda для передачи обратного вызова:
menu->AddItem("Open", boost::bind(&MyClass::Open, this));
Другой вариант - использовать boost :: signal , который позволяет нескольким обратным вызовам регистрироваться для одного и того же события.
Мне нравится ваш подход. Одной из альтернатив может быть объявление интерфейса, который в некотором смысле является «объектно-ориентированным эквивалентом» обратного вызова:
class IMenuEntry {
public:
virtual void OnMenuEntrySelected(MenuItem* item) = 0;
};
Регистрационная подпись станет
AddItem(string s, IMenuEntry * entry);
И реализация метода
class MyApp : public IMenuEntry {
public:
virtual void OnMenuEntrySelected(MenuItem* item){
activeMode = item->text;
}
}
Интерфейсный подход позволит вам избежать «void * обходной путь» для отсутствующего указателя this
.
Вы можете взглянуть на использование boost :: bind .
menu->AddItem(TRANSLATE,
"translate",
boost::bind( &MyApp::OnModeSelected, this, _1, _2 ));
Я настоятельно рекомендую посмотреть ] boost :: function и boost: bind для этого. Его изучение упростит привязку ваших функций в сто раз.
Я не вижу ничего плохого, кроме того, что сигнатуру указателя функции трудно прочитать. Но я бы, вероятно, наблюдатель паттерн, чтобы добиться этого.
Прочтите этот технический документ. Он строит различные методы для механизма обратного вызова, достаточно подробно анализируя производительность, удобство использования и другие компромиссы. Я нашел это трудным для чтения: - (
Вы можете использовать функтор для инкапсуляции вашего обратного вызова. Это позволит вам использовать функцию в стиле C или объектный интерфейс для обеспечения обратного вызова.