c++ - parametro - Pasar una función miembro no estática calificada como un puntero de función
punteros en c (3)
Ampliando el consejo de Michael Burr, tendrá que averiguar cómo una función no miembro puede obtener acceso a la instancia del objeto que está modificando. Una forma común es aprovechar el alcance de los globales estáticos en C:
// Top of your .c module:
static Window *gMyWindow;
// The declaration
extern "C" {
void* my_callback(int, int);
}
// Later, set it just before handing off the callback
void somefunc() {
...
gMyWindow = &windowObjectRef;
registerResizeCallback(my_callback);
windowObjectRef.SomeOtherWindowCallCausingCallbackInvoke();
...
}
// The callback in the same .c module as the global
void my_callback(int x, int y) {
Window *object = gMyWindow;
object->Resize(x, y);
}
No he compilado / ejecutado el código anterior, por lo que puede haber ajustes en los detalles, pero con suerte el concepto es claro: la devolución de llamada debe ser un puente entre C y C ++, y luego la pregunta es cómo hacer que su objeto "entre" la devolución de llamada es la instancia para la llamada a la función miembro.
Puede haber otras razones en su entorno por las que el ejemplo global anterior no funcionará, por lo que su tarea sería averiguar qué otro mecanismo además de los globales le permitiría pasar el objeto a la devolución de llamada en función de su situación.
Tengo una función en una biblioteca externa que no puedo cambiar con la siguiente firma:
void registerResizeCallback(void (*)(int, int))
Quiero pasar una función miembro como devolución de llamada, ya que mi devolución de llamada necesita modificar variables de instancia.
Obviamente esto no es posible con un simple:
registerResizeCallback(&Window::Resize);
así que no estoy seguro de cómo resolver el problema.
Verifique "[33.2] ¿Cómo paso una función de apuntador a miembro a un manejador de señal, devolución de llamada de evento X, llamada al sistema que inicia un hilo / tarea, etc.?" en C ++ FAQ Lite:
No lo hagas
Como una función miembro no tiene sentido sin un objeto para invocarla, no puede hacer esto directamente
...
Como un parche para el software existente, use una función de nivel superior (no miembro) como un contenedor que toma un objeto obtenido a través de alguna otra técnica.
Como indica Igor Oks , no puedes hacer esto. El resto de esta pregunta no es tanto una respuesta a su problema, sino una discusión sobre cómo algo así debería funcionar con una API de devolución de llamada diseñada correctamente (parece que la que está utilizando no lo está).
La mayoría de las interfaces de devolución de llamada bien diseñadas le permiten proporcionar un " void *
" o de alguna otra manera para obtener un contexto en la devolución de llamada. Una forma común de usar esto con C ++ es pasar un puntero de objeto en el parámetro de contexto void *
, luego la función de devolución de llamada puede devolverlo a un puntero de objeto y llamar al método miembro para hacer el trabajo real. Es una lástima que la API de devolución de llamada que está utilizando no proporcione datos contextuales.
Estrictamente hablando, la devolución de llamada debe ser extern "C"
, pero el uso de métodos de miembros estáticos para devolución de llamadas es común y creo que en la práctica nunca hay un problema. (Esto supone que la API de devolución de llamada es una interfaz C, que es con mucho la más común).
Un ejemplo:
// callback API declaration''s
extern "C" {
typedef unsigned int callback_handle_t;
typedef void (*callback_fcn_t)( void* context, int data1, int data2);
callback_handle_t RegisterCallback( callback_fcn_t, void* context);
void UnregisterCallback( callback_handle_t);
}
// ----------------------------------
// prototype for wrapper function that will receive the callback and
// transform it into a method call
extern "C"
static void doWorkWrapper( void* context, int data1, int data2);
// the class that does the real work
class worker {
public:
worker() {
hCallback = RegisterCallback( doWorkWrapper, this);
}
~worker() {
UnregisterCallback( hCallback);
}
void doWork( int data1, int data2) {
// ...
};
private:
callback_handle_t hCallback;
};
// the wrapper that transforms the callback into a method call
extern "C"
static void doWorkWrapper( void* context, int data1, int data2)
{
worker* pWorker = static_cast<worker*>( context);
pWorker->doWork( data1, data2);
}