2009-01-13 21 views
5

Antes que nada tengo que admitir que mis habilidades de programación son bastante limitadas y me hice cargo de un proyecto C++ OOP (realmente pequeño) donde intento introducir mis propios recursos. Desafortunadamente, Estoy experimentando un problema que va más allá de mi conocimiento y espero encontrar algo de ayuda aquí. Estoy trabajando con una biblioteca de terceros (que no se puede cambiar) para tomar imágenes de una cámara y usaré algunos nombres de marcadores de posición aquí.Puntero de función para problemas de función de miembro de clase

La biblioteca de terceros tiene una función "ThirdPartyGrab" para iniciar una captura continua en vivo y toma un puntero a una función que se invocará cada vez que llegue un nuevo marco. Así que en una aplicación normal C dice así:

ThirdPartyGrab (HookFunction); 

"HookFunction" tiene que ser declarado como:

long _stdcall HookFunction (long, long, void*); 

o "BUF_HOOK_FUNCTION_PTR", que se declara como

typedef long (_stdcall *HOOK_FUNCTION_PTR) (long, long, void*); 

Ahora Tengo una aplicación C++ y una clase "MyFrameGrabber" que debe encapsular todo lo que hago. Así que puse en la función de enlace como un miembro privado como esto:

long _stdcall HookFunction (long, long, void*); 

También hay una función pública vacío "StartGrab" en mi clase que debe comenzar el Grab. Dentro Trato de llamar:

ThirdPartyGrab (..., HookFunction, ...); 

cuales (como es lógico) falla. Dice que la llamada de función a MyFrameGrabber :: HookFunction pierde la lista de argumentos y debería intentar usar & MyFrameGrabber :: HookFunction para crear un puntero en su lugar. Sin embargo, al pasar "& MyFrameGrabber :: HookFunction" se produce otro error que no se puede convertir a BUF_HOOK_FUNCTION_PTR.

Después de leer el C++ FAQ function pointers creo que entiendo el problema pero no puedo encontrar una solución. Intenté que la función de enlace fuera estática, pero esto también da como resultado un error de conversión. También pensé en poner la función de gancho fuera de la clase, pero necesito usar funciones de clase dentro de la función de gancho. ¿Hay alguna otra manera o necesito cambiar todo mi concepto?

EDITAR 14.01.08: Probé la solución única porque no puedo cambiar la biblioteca de terceros y el puntero vacío es solo para los datos que se usan dentro de la función de enlace. Por desgracia, no funcionó de la caja como yo esperaba .... No sé si la función estática tiene que estar en una clase separada así que lo puse en mi clase "MyFrameGrabber":

static MyFrameGrabber& instance() 
{ 
     static MyFrameGrabber _instance; 
     return _instance; 
} 
long Hook(long, long, void*); // Implementation is in a separate cpp file 

en mi cpp que tienen la función call_hook:

long MFTYPE call_hook(long x, MIL_ID y, void MPTYPE *z) 
{ 
    return MyFrameGrabber::instance().Hook(x,y,z); 
} 
void 
MyFrameGrabber::grab() 
{ 
    ThirdPartyGrab(..., call_hook, ...); 
} 

Pero esto me da un error en static MatroxFrameGrabber _instance; que se encontró ningún constructor estándar a juego. Eso es correcto porque mi MyFrameGrabber constructor se ve así:

MyFrameGrabber (void* x, 
       const std::string &y, int z, 
       std::string &zz); 

traté de poner en un constructor vacío MyFrameGrabber(); pero esto resulta en un error de vinculador. ¿Debo pasar los parámetros vacíos al constructor MyFrameGrabber en el singleton? ¿O necesito tener una clase de enganche separada y, en caso afirmativo, cómo puedo acceder a las funciones de MyFrameGrabber? Gracias por adelantado.

SEGUNDA EDICIÓN 15.01.08: Apliqué los cambios y compila y enlaces ahora. Desafortunadamente, todavía no puedo probar esto en tiempo de ejecución porque es una DLL y aún no tengo Debug Caller Exe y hay otros problemas durante la inicialización, etc. Marcaré la publicación como respuesta porque estoy seguro de que esta es la manera correcta de hacerlo.

Respuesta

2

La razón "& MyFrameGrabber :: HookFunction" no se puede convertir a un BUF_HOOK_FUNCTION_PTR es que, al ser un miembro de la clase, tiene implícitamente como primer parámetro el puntero "this", por lo que no se puede convertir a una función miembro de una función no miembro: las dos firmas tienen el mismo aspecto pero son realmente diferentes.

Declararía una interfaz, definiendo la función a llamar, haga que su clase lo implemente y pase el objeto en lugar de la devolución de llamada (puede pensar en una interfaz como el reemplazo orientado a objetos de un puntero a función):

class IHookInterface{ 
public: 
    virtual long HookFunction(long, long, void*) = 0; 
}; 
class HookClass : public IHookInterface{ 
public: 
    virtual long Hook(long, long, void*) { 
     // your code here... 
    } 
}; 

// nueva definición: ThirdPartyGrab (..., IHookInterface, ...);

EDITAR - Otra posible solución en caso de que no pueda modificar la biblioteca: utilice una función singleton en lugar de estática.

class HookClass{ 
public: 
    static HookClass& instance(){ 
     static HookClass _instance; 
     return _instance; 
    } 
    long Hook(long, long, void*) { 
     // your code here... 
    } 
}; 

long call_hook(long x,long y,void * z){ 
    return HookClass::instance().Hook(x,y,z); 
} 

SEGUNDA EDICIÓN: es posible modificar ligeramente la clase singleton con un método de inicialización para llamar al constructor con los parámetros adecuados, pero tal vez no es más elegante que la siguiente solución, que es más simple:

class HookClass{ 
public: 

    HookClass(string x,string y...){ 
    } 

    long Hook(long, long, void*) { 
     // your code here... 
    } 
}; 

static HookClass * hook_instance = 0; 

long call_hook(long x,long y,void * z){ 
    if (0 != hook_instance){ 
     return hook_instance->Hook(x,y,z); 
    } 
} 

int main(){ 
    hook_instance = new HookClass("x","y"); 
    ThirdPartyGrab(..., call_hook, ...); 
} 
+0

Creo que con "biblioteca de terceros" el PO quiere decir que no puede cambiar la biblioteca. Sin embargo, mi suposición puede estar equivocada. – gimpf

+0

@gimpf - gracias, que probablemente tengan razón ... –

+0

Un uso común del vacío * parámetro en C devoluciones de llamada es como el puntero this-> para C++. Eso significa que escribirás mucho (Hook, Hook) y omitirás la static hook_instance – MSalters

7

Su método de miembro privado tiene una implícita this puntero como primer argumento. Si lo escribe, es obvio que las firmas de función no coinciden.

Necesita escribir una función de miembro estático, que se puede pasar como la función de devolución de llamada a la biblioteca. . El último argumento de la HookFunction, un void*, me parece muy parecido a una galleta, donde se puede pasar a la propia puntero en

Así que, en definitiva, debería ser algo como esto:

 
class MyClass { 
    long MyCallback(long, long) { 
    // implement your callback code here 
    } 

    static long __stdcall ThirdPartyGrabCallback(long a, long b, void* self) { 
    return reinterpret_cast<MyClass*>(self)->MyCallback(a, b); 
    } 
public: 
    void StartGrab() { 
    ThirdPartyGrab(..., &MyClass::ThirdPartyGrabCallback, ..., this, ...); 
    } 
}; 

Por supuesto, esto sólo funciona si el argumento void* está haciendo lo que dije. La posición de la this en la llamada ThirdPartyGrab() debe ser fácil de encontrar al tener la firma de función completa que incluye los nombres de los parámetros disponibles.

Cuestiones relacionadas