I decided to make a GlutApp class to make using glut easier. And faced with such a problem. I made a virtual function in the GlutApp class:

class GlutApp { //... virtual void Display(); //... }; 

And in the designer wrote the following:

 GlutApp::GlutApp(int argc, char **argv) { //... glutDisplayFunc(Display); //... } 

As a result, I got the error:

 glutapp.cpp:11:26: error: cannot convert 'void (GlutApp::*)()' to 'void (*)()' for argument '1' to 'void glutDisplayFunc(void (*)())' 

And three more similar. Why is that? How to rectify the situation? How to make a class method a callback function?

3 answers 3

In most cases, this can not be done. Even if you distort and use the reinterpret_cast convert a pointer to a member function to a pointer to a simple function, it will not work properly if it accesses the elements of its class. In fact, as one of the parameters, a pointer to an object is hidden (that same this ). Well, and then draw conclusions ...

However, I found a way out in one case: if an object is created in the global scope. Such a wrapper system is used.

 class A { int i; public: A(int i_) : i(i_) {} void say() { //функция, которую caller должен в конечном счете вызвать cout << "I say: " << i << endl; } }; void caller (void (*f) ()) { //вызыватель f(); } A a(77); void wrap () { //обертка, выполняющая роль call-back function a.say(); } int main() { caller (wrap); } 

In this case, you need to properly design the class so that, if necessary (if any) from another place, you can change its internal data.

In general, a perversion, of course.

  • one
    As far as I understand, you can make a static member function of a class and pass a pointer to it. Only after all, in principle, this function will not differ from the "free" function. - gecube
  • This is a well-known and uninteresting thing. My variant allows, in a specific case, to call exactly a member function that has access to non-static elements of an object. And the static function does not have one, naturally. - skegg
  • Why? In this case, we are limited by the fact that we cannot pass *this inside the function, because its signature is hard coded. But no one bothers us to create a static member of the class, which will save a link to an instance of the class. At Stack Overflow [1], this technique is applied. But as far as I understand the cant is that it turns out an object that can be created once ... The second copy will already work incorrectly ... [1]: stackoverflow.com/questions/3589422/… - gecube
  • Well, in general, the decision is close to mine. Although potentially dangerous. - skegg
  • one
    What are the disadvantages it has? I do not like that in your version everything is spread over the global namespace. In the case of a static member function class, all the mechanics remain inside ... Otherwise, there is no sense with the PLO in this case, IMHO. - gecube

When working with OpenGl and C ++, it is important to understand that OpenGl was not written in C ++ but in C code. Other languages ​​are also supported. The libraries are built in such a way that the function call goes through cdecl and here, apart from the declaration of static, nothing will help .... BUT !!! there is one very productive trick !!! C ++ itself is also a procedural programming language, and for procedures you do not need to specify static (with cdecl), and accordingly you can use dynamic addresses, address arrays, etc. And if you write your pipeline on the implementation of procedure calls from other classes? Well, that is, one global function that implements the processing of class objects by their addresses? Yes, for a long time, but not everything is built right away, but after all, OpenGl was not immediately written ... By writing it once, you can use it for any class ... And go ahead ... How does anyone think? I'm also looking for options - while trying to do this - it seems to work (and where will it go)))). And to redirect the addresses and subtilize with them differently - all this will be rested in the declaration of one function for all and there is no result. And is there an easier option?

    Suppose I did such a perversion.

     int *ptr=NULL; void (A::*_a)(void); _a = &A::say; _ptr= (int*) &_a; glutDisplayFunc((void(*)()) ( (int) *_ptr)); 

    And now, how will they reach the members of the class, are they not available due to the fact that the callback function works in a separate thread?

     void A:say() { cout << "I say: " << i << endl; //всё упало, здесь 77 ну никак получается }