У вас есть несколько основных опций:
1) Укажите, какой класс будет использовать обратный вызов, чтобы указатель объекта и типы указателей на функции-члены были известны и могли использоваться в вызывающей программе. Класс может иметь несколько функций-членов с одной и той же сигнатурой, которую вы можете выбрать, но ваши параметры весьма ограничены.
Одна вещь, которую вы сделали неправильно в своем коде, заключается в том, что указатели на функции-члены и указатели свободных функций в C ++ не совпадают и не являются совместимыми типами. Ваша функция регистрации обратного вызова принимает указатель на функцию, но вы пытаетесь передать ей указатель на функцию-член. Не положено. Кроме того, тип объекта «this» является частью типа указателя на функцию-член, поэтому в C ++ нет такой вещи, как «указатель на любую функцию-член, которая принимает целое число и возвращает void». Это должен быть «указатель на любую функцию-член объекта Target , которая принимает целое число и возвращает void». Отсюда и ограниченные возможности.
2) Определить чисто виртуальную функцию в классе интерфейса. Поэтому любой класс, который хочет получить обратный вызов, может наследовать от класса интерфейса. Благодаря множественному наследованию это не мешает остальной иерархии классов. Это почти то же самое, что и определение интерфейса в Java.
3) Использовать функцию, не являющуюся членом для обратного вызова. Для каждого класса, который хочет его использовать, вы пишете небольшую функцию-заглушку, которая берет указатель на объект и вызывает для него правильную функцию-член. Так что в вашем случае у вас будет:
dosomething_stub(void *obj, int a) {
((Target *)obj)->doSomething(a);
}
4) Использовать шаблоны:
template<typename CB> class MyClassWithCallback {
CB *callback;
public:
void setCallback(CB &cb) { callback = &cb; }
void callCallback(int a) {
callback(a);
}
};
class Target {
void operator()(int a) { /* do something; */ }
};
int main() {
Target t;
MyClassWithCallback<T> caller;
caller.setCallback(t);
}
Возможность использования шаблонов зависит от того, является ли ваш ClassWithCallback частью какой-то большой старой инфраструктуры - если это так, то это может оказаться невозможным (если быть точным: может потребоваться еще несколько хитростей, таких как класс шаблона, который наследуется от не (шаблонный класс, имеющий виртуальную функцию-член), потому что вы не можете создать экземпляр всей платформы один раз для каждого получателя обратного вызова.