2011-02-15 24 views
8

Estoy usando MSVC++ y freeglut para usar OpenGL. Ahora, tengo una clase llamada Camera, que es bastante simple, pero también contiene la función para la remodelación de mi ventana.Función de devolución de llamada en freeglut desde el objeto

Mi pregunta es: ¿cómo puedo configurar glutReshapeFunc(void (*callback)(int,int)) para mi función en mi cámara?

tengo el siguiente código, que no va a funcionar, debido a un error del compilador:

int main(int argc, char **argv) 
{ 
    Camera *camera = new Camera(); 
    glutReshapeFunc(camera->ReshapeCamera); 
} 

y mi clase de la cámara es la siguiente con Camera.h:

class Camera 
{ 
public: 
    Camera(void); 
    ~Camera(void); 
    void ReshapeCamera(int width, int height); 
}; 

Tal vez esta es solo una pregunta de devolución de llamada más general, pero lo único que encontré en Internet fue crear una clase de envoltura alrededor de la devolución de llamada. Pero no parece que esto debería ser tan difícil. Gracias de antemano.

Respuesta

10

No hay una manera clara de hacerlo. C no sabe acerca de los objetos, por lo que los punteros a los miembros no funcionan. C no hace plantillas, por lo que los funtores no funcionan. La API ni siquiera le permite pasar un void *userData arbitrario a su devolución de llamada, por lo que tampoco puede pasar el objeto de esa manera.

Así que, de hecho, tendrá que crear una función de contenedor que no sea una función miembro, y tendrá que darle acceso a la instancia de objeto Camera de alguna manera, a través de una variable estática y/o global.

Si puede haber varios objetos escuchando este evento, puede crear una clase singleton que le permita registrar escuchas arbitrarios.

2

No se puede conectar directamente. ReshapeCamera es una función miembro, necesita una instancia de cámara para ejecutarse. La devolución de llamada glut es una función C, que no tiene una instancia de cámara para llamar a su método. Necesita crear una función que llame al método de remodelación de la cámara.

1

No tiene nada que ver con una cosa de "C vs C++". Solo necesita comprender lo que implica una llamada a función de miembro y, básicamente, con qué se compila.

myObject.memberFunction(); // This is what the programmer sees. 
memberFunction(&myObject); // This is what the compiler sees. 

Una función de miembro es una descripción elegante de una función que simplemente toma el objeto como primer parámetro. Es simplemente invisible en la lista de parámetros reales.

void MyClass::memberFunction() // This is the declaration the programmer sees. 
void memberFunction(MyClass* this) // This is what the compiler sees. 

A partir de ahí, C++ agrega una semántica especial para facilitar el trabajo de forma orientada a objetos. Por lo tanto, aunque su objeto tenga una función miembro del formato void (int, int), en realidad tiene el formato void (Camera *, int, int) y no coincide con el formato deseado. Esta es la razón por la cual los miembros de la función estática pueden ser usados ​​para tales indicadores de función. ¿Alguna vez se dio cuenta de que las funciones de miembros estáticos no pueden acceder a los miembros de "esto"? Esto se debe a que las funciones miembro estáticas hacen no pasan una instancia del objeto que representa "esto".

En efecto, puede emular gran parte de la programación orientada a objetos en el plano C. Si realiza un conjunto de funciones que toman un puntero struct como el primer parámetro, ¡obtendrá muchas de las mismas ventajas!

+0

Así que creé una función estática en mi clase ahora, pero parece que no se puede convertir de __thiscall a __decl. 'Error 1 error C2664: 'glutReshapeFunc': no ​​se puede convertir el parámetro 1 de 'void (__thiscall Camera :: *) (int, int)' a 'void (__cdecl *) (int, int)''. Y agregar un __cdecl explícito da una advertencia sobre la 'Camera ::' -part. – Marnix

+0

@Marnix: El '__thiscall' me sugiere que' glutReshapeFunc' no está declarado como 'static'. – Thomas

+0

@Thomas: No, glutReshapeFunc es probablemente una función en C, la función que proviene de mi clase de cámara es estática, pero tiene por lo tanto otro espacio de nombres. Entonces no parece entender esto. – Marnix

0

A continuación se muestra cómo registrar una función de devolución de c desde C++ Es generalmente útil, no específico para exceso.

Aquí es su cliente programa en C++

int main(int argc, char *argv[]) { 

std::cout << "launching Camera ..." << std::endl; 

Camera * camera = new Camera(); 

// ------ glut new window boilerplate ------- // 

int WindowHandle = 0; 
glutInit(&argc, argv); 
WindowHandle = glutCreateWindow("hello there"); 
if(WindowHandle < 1) { 
    std::cerr << "ERROR: Could not create a new rendering window" << std::endl; 
    exit(EXIT_FAILURE); 
} 
// ------------------------------------------ // 

camera->setup_callback(); 

glutMainLoop(); 

return 0; 

}

Aquí está el Camera.cpp

Camera * ptr_global_instance = NULL; 

extern "C" void ReshapeCamera_callback(int width, int height) { 
    // c function call which calls your c++ class method 
    ptr_global_instance->ReshapeCamera_cb(width, height); 
} 

void Camera::ReshapeCamera_cb(int width, int height) { 
    std::cout << "width " << width << " height " << height << std::endl; 
} 

void Camera::setup_callback() { 
    // c++ method which registers c function callback 
    ::ptr_global_instance = this; 
    ::glutReshapeFunc(::ReshapeCamera_callback); 
} 

y su Camera.h cabecera

class Camera { 
public: 
    void ReshapeCamera_cb(int width, int height); 
    void setup_callback(); 
}; 

Aviso del uso de un puntero de clase global de C++ ptr_global_instance

Cuestiones relacionadas