Pregunta

En primer lugar, tengo que admitir que mis habilidades de programación son bastante limitadas y me hice cargo de un proyecto C ++ OOP existente (realmente pequeño) en el que trato de introducir mis propias cosas. Desafortunadamente, estoy experimentando un problema que va más allá mi conocimiento y espero encontrar 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 marcador de posición aquí.

La biblioteca de terceros tiene una función " ThirdPartyGrab " para comenzar una captura continua en vivo y lleva un puntero a una función que se llamará cada vez que llegue un nuevo marco. Entonces, en una aplicación C normal, es así:

ThirdPartyGrab (HookFunction);

" Función de gancho " debe declararse 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 debería encapsular todo lo que hago. Así que puse la función de enlace como miembro privado de esta manera:

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

También hay una función pública anulada " StartGrab " en mi clase que debería comenzar el Grab. En el interior trato de llamar:

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

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

Después de leer los C ++ FAQ punteros de función Creo que entiendo el problema pero no puedo inventar una solución. Traté de hacer que la función de enlace sea estática, pero esto también produce un error de conversión. También pensé en colocar la función de enlace fuera de la clase pero necesito usar funciones de clase dentro de la función de enlace. ¿Hay otra forma o necesito cambiar todo mi concepto?

EDITAR 14.01.08: Probé la solución de singleton ya que no puedo cambiar la biblioteca de terceros y el puntero vacío es solo para los datos que se utilizan dentro de la función de enlace. Desafortunadamente, no funcionó de la caja como esperaba ... No sé si la función estática debe estar en una clase separada, así que la puse en mi "MyFrameGrabber". clase:

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, ...);
}

En mi archivo cpp tengo la función call_hook:

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

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

<*>

Traté de poner un constructor vacío MyFrameGrabber (); pero esto resulta en un error de enlazador. ¿Debo pasar parámetros vacíos al constructor MyFrameGrabber en el singleton? ¿O necesito tener una clase Hook 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 ahora compila y enlaza. Desafortunadamente, aún no puedo probar esto en tiempo de ejecución porque es una DLL y todavía 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 forma correcta de hacerlo.

¿Fue útil?

Solución

La razón " & amp; MyFrameGrabber :: HookFunction " no se puede convertir en un BUF_HOOK_FUNCTION_PTR es que, como miembro de la clase, tiene implícitamente como primer parámetro el " this " puntero, por lo que no puede convertir una función miembro en una función no miembro: las dos firmas se ven iguales pero en realidad son diferentes.

Declararía una interfaz, definiendo la función a llamar, que su clase la 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 de 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: use un singleton en lugar de una función 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: puede 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 sea 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, ...);
}

Otros consejos

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

Debe escribir una función miembro estática, que se puede pasar como función de devolución de llamada a la biblioteca. El último argumento de HookFunction , un void * , se parece mucho a una cookie, en la que se puede pasar el puntero.

Entonces, en general, 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, ...);
  }
};

Esto, por supuesto, solo funciona si el argumento void * está haciendo lo que dije. La posición de this en la llamada ThirdPartyGrab () debe ser fácil de encontrar cuando se tiene la firma de función completa, incluidos los nombres de parámetros disponibles.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top