2010-03-23 10 views
11

Ich weiß, das Ding funktioniert:Wie Übergeben einer Klassenmethode als ein Argument für eine andere Funktion in C++ und OpenGL?

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

so habe ich versucht, myDisplay() Funktion zu einer Klasse gehören, die ich gemacht. Weil ich es in der Zukunft mit einer anderen Klasse überladen möchte. Allerdings wirft der Compiler, dass

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

Hier ist das, was ich versuche zu machen:

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

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

Hat jemand weiß, wie man dieses Problem zu beheben? Danke vielmals.

Antwort

9

Erstens gibt es einen impliziten "this" -Zeiger in nicht statischen Elementfunktionen, so dass Sie Ihre void myDisplay() in ClassBlah als statisch ändern müssen. Es ist peinlich, diese Einschränkung zu umgehen, weshalb die C++ - FAQ-Lite sagt

Dann sollten Sie in der Lage sein, die Funktionen als ClassBlah::myDisplay übergeben.

Abhängig von Ihrer Motivation für das Überladen (dh werden Sie zur Laufzeit oder zur Kompilierungszeit Hotsplash-Implementierungen ausführen), könnten Sie eine statische statische Klasse "Handler" in Erwägung ziehen, die einen Zeiger auf Ihre Basisklasse enthält. und delegiert die Verantwortung dadurch.

1

Sie können Boost-bind für Elementfunktionen verwenden, beispielsweise ein Gewinde auf einer Elementfunktion zu schaffen:

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

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

Das ist cool. Funktioniert es ordnungsgemäß, wenn memberThreadFunc virtuell ist und & a auf eine Unterklasse verweist? – kibibu

+1

Ich bezweifle, boost :: bind wird hier funktionieren, da das sicherlich eine Struktur zurückgibt, die einen() -Operator hat, etwas, das GlutDisplayFunc nicht verwenden kann. – Thanatos

+4

Bind kann hier nicht helfen. Die aufgerufene Funktion erfordert einen Callback vom Typ 'void (*)()'. Ein 0-artiges Funktionsobjekt kann nicht verwendet werden. –

0

Sie können nicht. glutDisplayFunc nimmt einen Parameter vom Typ void(*)(), nicht void (ClassBlah::)(). Wenn Sie nicht bereit und in der Lage sind, die Quelle der Überschwem- mung zu verändern, haben Sie kein Glück.


Viele C-APIs, die Rückrufe verwenden passieren einen vom Benutzer angegebenen void* Parameter an die Funktion, die Sie einen Zeiger auf Ihre Klasse speichern können. Sie können dann eine freie Funktion übergeben, die die Benutzerdaten an einen Klassenzeiger sendet und dann die Elementfunktion aufruft. Die Art und Weise, wie Überschwem- mungen aufgebaut sind, lässt dies jedoch nicht zu.

5

Ich stieß auf dieses Problem beim Schreiben einer C++ Glut-Engine selbst. Hier ist, wie ich um ihn gearbeitet:

ich diese an der Spitze meiner program.cpp/main.cpp platziert

// 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); 

Weisen Sie diese Funktionen Schwemme der Rückrufe hier:

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

erstellen mein eigene Klasse, die diese eigenständig behandelt und dann den Inhalt unserer statischen Funktionen einfach Methoden für die Instanz dieser Klasse aufruft. Ihre Hauptfunktion sollte eine neue Instanz der Klasse in main erstellen (in meinem Fall ... 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); 
} 

Hoffe, dass es erklärt.

3

Mein Weg, um dies zu lösen, ist einfach:
Zuerst einen Zeiger vor der Hauptfunktion.
Am Anfang der Hauptfunktion setzen Sie Zeiger auf Instanz Ihrer Klasse.
Dann in neu definierten Funktion für das Rendern, können Sie Ihr Objekt mit globalen Zeiger zugreifen.

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

Hoffe, dass es für Sie arbeitet, für mich tut.

+0

Es hat für mich funktioniert, Danke! Aber ich bin neugierig zu wissen, wie gut es so ist? – Kahin

+1

Wie einige Leute erwähnt haben, muss glutDisplayFunc Zeiger auf Speicher abrufen, wo Sie Ihre Implementierung von Rendering speichern. Per Definition kann es keine Argumente empfangen, daher ist es nur möglich, mit einer globalen Variable zu arbeiten. Ich stimme zu, das ist brutal und hässlich und respektiert OOP nicht. Auf der anderen Seite ist C keine OOP-Sprache. gibt es viele Wrapper, und auch eine neue Version von API, die verwendet werden kann, um OOP zu erhalten. Man kann auch etwas wie @Corwin machen, er hat es auf eine sauberere Art und Weise gelöst, aber die ursprüngliche Idee ist, mit einer Variablen zu arbeiten, die von außen kommt. Meiner Meinung nach ist dies mehr oder weniger dieselbe Idee. – bartekordek

Verwandte Themen