2010-03-23 25 views
11

Sé que esto funciona:¿Cómo pasar un método de clase como argumento para otra función en C++ y OpenGL?

void myDisplay() 
{ 
... 
} 
int main() 
{ 
... 
glutDisplayFunc(myDisplay) 
... 
} 

por lo que trataron de incluir la función() para una clase que hice myDisplay. Porque quiero sobrecargarlo en el futuro con una clase diferente. Sin embargo, el compilador se queja de que

argument of type 'void (ClassBlah::)()' does not match 'void(*)()' .

Aquí es el lo que trato de hacer:

class ClassBlah 
{ 
    .... 
    void myDisplay() 
    .... 
} 
...... 
int main() 
{ 

    ... 
    ClassBlah blah 
    glutDisplayFunc(blah.myDisplay) 
    ... 
} 

¿Alguien sabe cómo solucionar este problema? Muchas gracias.

Respuesta

9

En primer lugar, hay un puntero "this" implícito en las funciones miembro no estáticas, por lo que deberá cambiar su void myDisplay() en para que sea estático. Es difícil evitar esta limitación, razón por la cual el faq lite de C++ dice don't do it

Luego, debe poder pasar las funciones como ClassBlah::myDisplay.

Dependiendo de su motivación para la sobrecarga (es decir, ¿va a entrar y salir implementaciones de hotswap en tiempo de ejecución, o solo en tiempo de compilación?) Puede considerar una clase estática de "utilidad" de utilidad que contiene un puntero a su clase base. y delega la responsabilidad a través de eso.

1

Puede utilizar bind Boost para funciones miembro, por ejemplo la creación de un hilo en una función miembro:

class classA 
{ 
public: 
    void memberThreadFunc(int i); 
}; 

void main() 
{ 
    classA a; 
    boost::thread(boost::bind(&classA::memberFunc, &a, 123)); 
} 
+0

Eso es genial. ¿Funciona correctamente si memberThreadFunc es virtual y & a apunta a una subclase? – kibibu

+1

Dudo que boost :: bind funcione aquí, ya que seguramente devuelve una estructura que tiene un operador(), algo que glutDisplayFunc no puede usar. – Thanatos

+4

Bind no puede ayudar aquí. La función a la que se llama requiere una devolución de llamada de tipo 'void (*)()'. No se puede usar un objeto de función 0-ary. –

0

No se puede. glutDisplayFunc toma un parámetro del tipo void(*)(), no void (ClassBlah::)(). A menos que esté dispuesto y sea capaz de alterar la fuente del exceso, no tiene suerte.


Muchas API C que utilizan devoluciones de llamada pasa un parámetro especificado por el usuario void* a la devolución de llamada, que se puede utilizar para almacenar un puntero a su clase. A continuación, puede pasar una función gratuita que arroja los datos del usuario a un puntero de clase y luego llama a la función miembro. Sin embargo, la forma en que se diseña el exceso no lo permite.

5

Me encontré con este problema escribiendo un motor C++ Glut. Así es como yo trabajé alrededor de él:

coloqué éstos en la parte superior de mi program.cpp/main.cpp

// Function prototypes 
void doRendering(void); 
void processMouse(int, int) ; 
void processMouseClick(int button, int state, int x, int y); 
void keyboardInput(unsigned char c, int x, int y); 

Asignar estas funciones para las devoluciones de llamada de glut aquí:

glutDisplayFunc(doRendering); 
glutIdleFunc(doRendering); 
glutPassiveMotionFunc(processMouse); 
glutMotionFunc(processMouse); 
glutMouseFunc(processMouseClick); 
glutKeyboardFunc(keyboardInput); 

Crear mi propia clase que maneja esto por sí misma y luego hace que los contenidos de nuestras funciones estáticas simplemente invoquen métodos en la instancia de esta clase. Tu función principal debería crear una nueva instancia de la clase en main (en mi caso ... App * newApp).

void doRendering(void) 
{ 
    newApp->updateScene(); 
    newApp->drawScene(); 
} 

void processMouse(int x, int y) 
{ 
    newApp->processMouse(x, y); 
} 

void processMouseClick(int button, int state, int x, int y) 
{ 
    newApp->processMouseClick(button, state, x, y); 
} 

void keyboardInput(unsigned char c, int x, int y) 
{ 
    newApp->keyboardInput(c, x, y); 
} 

Espero que lo explique.

3

Mi manera de resolver esto es simple:
Primero haga un puntero antes de la función principal.
Al comienzo de la función principal, configure el puntero como instancia de su clase.
Luego, en la nueva función definida para la representación, puede acceder a su objeto con un puntero global.

/** 
     Class argon is defined in external header file. 
*/ 

Argon *argonPtr; 

void renderScene(); 

int main() 
{  
    Argon argon; 
    argonPtr = &argon; 

    glutDisplayFunc(render); 
} 

void render() 
{ 
    RenderStuff(); 
    argonPtr->Render(); 
} 

Espero que funcione para usted, para mí lo hace.

+0

Me funcionó, ¡Gracias! Pero tengo curiosidad de saber lo bueno que es hacerlo de esta manera? – Kahin

+1

Como mencionaron algunas personas, glutDisplayFunc debe tener un puntero en la memoria donde almacena su implementación de renderizado. Por definición, no puede recibir argumentos, por lo que la única forma de hacerlo es operar en la variable global. Estoy de acuerdo que esto es bruto y feo y no respeta la POO. Pero, por otro lado, C no es el lenguaje OOP. hay muchas envolturas, y también una nueva versión de api que se puede utilizar para preservar OOP. También puede hacer algo como @Corwin, lo resolvió de una manera mucho más limpia, pero la idea original es operar en una variable que proviene del exterior. En mi opinión, esta es más o menos la misma idea. – bartekordek

Cuestiones relacionadas