2010-03-23 3 views
11

So che questa cosa funziona:Come passare un metodo di classe come argomento per un'altra funzione in C++ e openGL?

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

così ho cercato di includere la funzione() per una classe che ho fatto myDisplay. Perché voglio sovraccaricarlo in futuro con una classe diversa. Tuttavia, il compilatore si lamenta che

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

Ecco la cosa che cerco di fare:

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

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

Qualcuno sa come risolvere questo problema? Grazie molto.

risposta

9

In primo luogo, esiste un puntatore "questo" implicito in funzioni membro non statiche, quindi sarà necessario modificare void myDisplay() in ClassBlah in modo statico. È scomodo lavorare su questa limitazione, motivo per cui il linguaggio C++ faq dice don't do it

Quindi, si dovrebbe essere in grado di passare le funzioni come ClassBlah::myDisplay.

A seconda della motivazione del sovraccarico (ad esempio, quando si eseguono le implementazioni di hotswap in runtime o solo in fase di compilazione?) Si può considerare una classe statica di "gestore" di utilità che contiene un puntatore alla classe di base, e delega la responsabilità attraverso questo.

1

È possibile utilizzare Boost si legano per le funzioni di membro, ad esempio la creazione di un thread su una funzione membro:

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

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

Questo è bello. funziona correttamente se memberThreadFunc è virtuale e & a punta a una sottoclasse? – kibibu

+1

Dubito boost :: bind funzionerà qui, poiché sicuramente restituisce una struttura che ha un operatore(), qualcosa che glutDisplayFunc non può usare. – Thanatos

+4

Bind non può aiutare qui. La funzione chiamata richiede una callback del tipo 'void (*)()'. Non è possibile utilizzare un oggetto funzione 0-ary. –

0

Non è possibile. glutDisplayFunc accetta un parametro di tipo void(*)(), non void (ClassBlah::)(). A meno che tu non sia disposto e in grado di modificare la fonte di eccesso, sei sfortunato.


molte API C che utilizzano le richiamate passare un parametro specificato dall'utente void* al callback, che può essere utilizzato per memorizzare un puntatore alla vostra classe. È quindi possibile passare una funzione gratuita che esegue il cast dei dati utente su un puntatore di classe e quindi chiama la funzione membro. Tuttavia, il modo in cui è progettato il glut non lo consente.

5

Mi sono imbattuto in questo problema scrivendo un motore C++ Glut da solo. Ecco come ho lavorato intorno ad esso:

ho messo questi in cima alla mia 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); 

assegnare queste funzioni ai callback di GLUT qui:

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

Crea il mio la propria classe che li gestisce da sola e quindi rende il contenuto delle nostre funzioni statiche chiama semplicemente i metodi sull'istanza di questa classe. La tua funzione principale dovrebbe creare una nuova istanza della classe in main (nel mio 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); 
} 

Spero che lo spieghi.

3

Il mio modo per risolvere questo è semplice:
Prima di eseguire un puntatore prima della funzione principale.
All'inizio della funzione principale impostare il puntatore sull'istanza della classe.
Quindi nella nuova funzione definita per il rendering, è possibile accedere all'oggetto con il puntatore globale.

/** 
     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(); 
} 

Spero che funzioni per Te, per me lo fa.

+0

Ha funzionato per me, grazie! Ma sono curioso di sapere quanto è bello farlo in questo modo? – Kahin

+1

Come indicato da alcune persone, glutDisplayFunc deve ottenere il puntatore sulla memoria in cui viene archiviata l'implementazione del rendering. Per definizione non può ricevere argomenti, quindi l'unico modo per farlo è quello di operare sulla variabile globale. Sono d'accordo che questo è brutto e brutto e non rispetta l'OOP. D'altra parte, C non è un linguaggio OOP. ci sono molti wrapper e anche una nuova versione di api che può essere usata per preservare OOP. Puoi anche fare qualcosa come @Corwin, l'ha risolto in modo molto più pulito, ma l'idea originale è quella di operare su variabili esterne. Secondo me è più o meno la stessa idea. – bartekordek