Quantcast

C++ member functions as callbacks

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

C++ member functions as callbacks

Jimmy Johnson-10
I have a problem for which I hope one of you c experts have a solution.  I must write an openGL application and am required to use C or C++ and glut.  I come from an object-oriented mindset, therefore I gravitate toward C++.  Now glut requires C-functions to be passed for the callbacks, but there is a mismatch between the type of a "c function" and a "c++ member function".  I was told, "Just hack something together with C."  Well, that goes against my grain.  I want all the benefits that come with OO, especially reuse.  (Besides, I have to be able to read my own code, and from what I see in the example c code I've been given, that is hard to achieve in C.)

Caveat:  I am new to C so my knowledge of the syntax, especially with pointers and pointers to functions, is lacking, so I will try to use pseudo-code in hopes that someone can clean it up if what I want to do is possible.

With that out of my system let me use one of the glut features as an example.

glutReshapeFunc (onReshape) tells glut to call onReshape when the window size changes.  onReshape must have two int arguments:
        onReshape (int aHeight, int aWidth)

Ideally, I would like to do this in main():

        displayable myWin;
                // where displayable is a C++ object whose class
// has method `onReshape' taking two int arguments.
        glutReshapeFunc (myWin::onReshape);

better yet, in the constructor for displayable:
        displayable() {
                glutCreateWindow();  // etc.
                glutReshapeFunc (onReshape);
        };
               
but this will not work because of the type mismatch as mentioned above.  So I do this:
        displayable* myWin := NULL
        void myWinReshapeWrapper (int h, int w) {
                myWin->onReshape;
        };
       
        int main(…) {
                // initialize glut
                glutCreateWindow("This creates a window");
                // …
                myWin = new displayable;
                glutReshapeFunc (myWinReshapeWrapper);
       
This is a problem because I [and any user of my class] will have to have a reference to and write a "reshape wrapper" for every single displayable he wants.  


So, given that
1) I can't use C++ member functions in a C callback
2) The "wrapper" method works, but is not scalable
Is there a way to:
        Have a method (c++ member, or a c-function included at the top of the class "displayable"), called in the constructor that can do this wrapping automatically.  Something like:

function* makeWrapper (displayable* dis, function* func)
        // given reference to a displayable and some function
        // return a new function that simulates "dis->func"

And then in the constructor:
        displayable() {
                glutCreateWindow();
                f = makeWrapper (this, onReshape)
                glutDisplayFunc (f);

To boil it down, I want to create new functions to be used as callbacks which will call a c++ method on the correct object.

To anyone who has read this far, I thank you.

Best regards,

Jimmy J. Johnson


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: C++ member functions as callbacks

John Gaughan
On 1/26/2010 12:53 PM, Jimmy Johnson wrote:
> To boil it down, I want to create new functions to be used as callbacks which will call a c++ method on the correct object.
>    

How about using static members of a class that either deal with static
state or delegate to a singleton?

--
John Gaughan
http://www.jtgprogramming.org/

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: C++ member functions as callbacks

Jimmy Johnson-10
I am not up to c-proficiency yet to understand what you mean.  Do you mean put these features/pattern into the class and make them static?

  displayable* myWin := NULL
  void myWinReshapeWrapper (int h, int w) {
    myWin->onReshape;
  };

In this pattern the reference to myWin represents the state on which to call onReshape.  I don't know how I could set the state in that case.  A callback would have to be executed on, say a mouse click, to set the "state" to the window referenced by myWind, but in order to execute the callback on that window I need the stat to already be that window.  Chick-and-egg.

What is "delegate to" a singleton?  I need to instantiate more than one object of type displayable so making it a singleton will not work.  Can you explain "delegate to a singleton"?

thanks,



--- In [hidden email], John Gaughan <john@...> wrote:

>
> On 1/26/2010 12:53 PM, Jimmy Johnson wrote:
> > To boil it down, I want to create new functions to be used as callbacks which will call a c++ method on the correct object.
> >    
>
> How about using static members of a class that either deal with static
> state or delegate to a singleton?
>
> --
> John Gaughan
> http://www.jtgprogramming.org/
>


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: C++ member functions as callbacks

mukesh sale
Hello,
         I tried a small program which gives me a callback function.
----------------------------------------------------------------------------
class callback{
public:
  int (*fp)();
  friend int display();
};

int display()
{
 cout<<"I am calling callback function....";
 return 1;
}
int main()
{
 callback instance;
 instance.fp=display;
 int nCheck=(*instance.fp)();
 if(nCheck==1)
 {
  cout<<"i m done with callback"<<endl;
 }
 getchar();
  return 0;
}



On Wed, Jan 27, 2010 at 5:46 PM, Jimmy Johnson <[hidden email]> wrote:

>
>
> I am not up to c-proficiency yet to understand what you mean. Do you mean
> put these features/pattern into the class and make them static?
>
>
> displayable* myWin := NULL
> void myWinReshapeWrapper (int h, int w) {
> myWin->onReshape;
> };
>
> In this pattern the reference to myWin represents the state on which to
> call onReshape. I don't know how I could set the state in that case. A
> callback would have to be executed on, say a mouse click, to set the "state"
> to the window referenced by myWind, but in order to execute the callback on
> that window I need the stat to already be that window. Chick-and-egg.
>
> What is "delegate to" a singleton? I need to instantiate more than one
> object of type displayable so making it a singleton will not work. Can you
> explain "delegate to a singleton"?
>
> thanks,
>
>
> --- In [hidden email] <c-prog%40yahoogroups.com>, John Gaughan
> <john@...> wrote:
> >
> > On 1/26/2010 12:53 PM, Jimmy Johnson wrote:
> > > To boil it down, I want to create new functions to be used as callbacks
> which will call a c++ method on the correct object.
> > >
> >
> > How about using static members of a class that either deal with static
> > state or delegate to a singleton?
> >
> > --
> > John Gaughan
> > http://www.jtgprogramming.org/
> >
>
>  
>



--
----------------------------
Regards
Shantibhushan Sale
Mumbai
+91 9769396331


[Non-text portions of this message have been removed]

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: C++ member functions as callbacks

John Gaughan
In reply to this post by Jimmy Johnson-10
On 1/27/2010 7:16 AM, Jimmy Johnson wrote:
> I am not up to c-proficiency yet to understand what you mean.  Do you mean put these features/pattern into the class and make them static?
>    

Yes. That may or may not work. Object functions have an implicit "this"
pointer in their argument list, which you may need in the callback
unless you can determine the object to use from the other parameters.

> What is "delegate to" a singleton?  I need to instantiate more than one object of type displayable so making it a singleton will not work.  Can you explain "delegate to a singleton"?
>    

A singleton is an object where there is only one object of its class
ever instantiated. Typically you use language features such as a private
constructor and non-virtual destructor to ensure the class cannot be
extended, then create the instance and set a static const variable to
it. You then provide a static function to get a reference to the singleton.

You can have static functions that delegate to object functions on the
singleton, so users of your class do not need to know about the specific
object. This works well for some designs, poorly for others. It really
depends on whether the singleton is hard-coded or configurable.

Another alternative is if you want to restrict object construction and
delegate from static functions, you can use a multiton pattern. You
would store references to your objects in a hashtable or tree, i.e. an
associative array. You would have some key provided by the callback
which would retrieve the object on which to act, and then act on it.

Try searching wikipedia for "design pattern (computer science)" for more
info. That's the basics. I am not sure if this will work for your
situation, but it sounds like it is a new topic for you so it is worth
learning about regardless.

--
John Gaughan
http://www.jtgprogramming.org/

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: C++ member functions as callbacks

Thomas Hruska
In reply to this post by Jimmy Johnson-10
Jimmy Johnson wrote:

> I have a problem for which I hope one of you c experts have a solution.  I must write an openGL application and am required to use C or C++ and glut.  I come from an object-oriented mindset, therefore I gravitate toward C++.  Now glut requires C-functions to be passed for the callbacks, but there is a mismatch between the type of a "c function" and a "c++ member function".  I was told, "Just hack something together with C."  Well, that goes against my grain.  I want all the benefits that come with OO, especially reuse.  (Besides, I have to be able to read my own code, and from what I see in the example c code I've been given, that is hard to achieve in C.)
>
> Caveat:  I am new to C so my knowledge of the syntax, especially with pointers and pointers to functions, is lacking, so I will try to use pseudo-code in hopes that someone can clean it up if what I want to do is possible.
>
> With that out of my system let me use one of the glut features as an example.
>
> glutReshapeFunc (onReshape) tells glut to call onReshape when the window size changes.  onReshape must have two int arguments:
> onReshape (int aHeight, int aWidth)
>
> Ideally, I would like to do this in main():
>
> displayable myWin;
> // where displayable is a C++ object whose class
> // has method `onReshape' taking two int arguments.
> glutReshapeFunc (myWin::onReshape);
>
> better yet, in the constructor for displayable:
> displayable() {
> glutCreateWindow();  // etc.
> glutReshapeFunc (onReshape);
> };
>
> but this will not work because of the type mismatch as mentioned above.  So I do this:
> displayable* myWin := NULL
> void myWinReshapeWrapper (int h, int w) {
> myWin->onReshape;
> };
>
> int main(…) {
> // initialize glut
> glutCreateWindow("This creates a window");
> // …
> myWin = new displayable;
> glutReshapeFunc (myWinReshapeWrapper);
>
> This is a problem because I [and any user of my class] will have to have a reference to and write a "reshape wrapper" for every single displayable he wants.  
>
>
> So, given that
> 1) I can't use C++ member functions in a C callback
> 2) The "wrapper" method works, but is not scalable
> Is there a way to:
> Have a method (c++ member, or a c-function included at the top of the class "displayable"), called in the constructor that can do this wrapping automatically.  Something like:
>
> function* makeWrapper (displayable* dis, function* func)
> // given reference to a displayable and some function
> // return a new function that simulates "dis->func"
>
> And then in the constructor:
> displayable() {
> glutCreateWindow();
> f = makeWrapper (this, onReshape)
> glutDisplayFunc (f);
>
> To boil it down, I want to create new functions to be used as callbacks which will call a c++ method on the correct object.
>
> To anyone who has read this far, I thank you.
>
> Best regards,
>
> Jimmy J. Johnson

I used GLUT once upon a time.  Pain in the butt and really not designed
for C++.  It was an OpenGL + GLUT + GLUI app.  They are the "poor-man's
toolkit" for OpenGL.  The main issue you are having is associating an
object with a function that doesn't support transmitting the object
pointer (i.e. it doesn't allow 'this' to be passed).  GLUT, if I recall,
pretty much assumes two things:  Single thread, single instance.

Your 'makeWrapper' idea is called a "thunk".  It can be done but it is
an ugly solution (yet, at the same time, it is somewhat elegant since
C++ offers no really good way to accomplish this sort of thing
natively).  Thunks are generally written in platform and
compiler-specific assembler.  I don't recommend this approach (using
static member functions is usually the "correct" way).  But if you want
to do the thunk route, you build up a string of assembler opcodes, put
them in an aligned executable page of memory (VirtualProtect()), and
flush the processor instruction cache (FlushInstructionCache()).  Then
return a pointer to the start of the dynamically generated "function".
In essence, your "function" will look like:

mov ecx, this;
jmp actual_function_address;

Or whatever your compiler requires for 'this' to work properly (ecx is
usually for 'fastcall').  It could get ugly if you have to modify the
stack but the 'this' pointer is _usually_ the last thing put on the stack:

push esp, this;
jmp actual_function_address;

In both cases, 'this' is the instance of your class and
'actual_function_address' is the address of the method you want to call.
  The above code is targeting the Intel architecture and is completely
untested other than recalling from the only time I've ever done thunking.

Besides the already big caveats mentioned, thunks also have another big
downside:  Debuggers get lost.  You can't stick a breakpoint inside the
thunk itself and most debuggers will generally get lost in whatever the
actual callback is (the call stack is usually screwy inside the
function).  After all, thunks are rare and unexpected.

You are probably better off writing function wrappers.  They work and
are cross-platform/compiler.

If you want to have something more "reusable", look into the 'virtual'
keyword.  You write a base class one time that calls derived functions
(in a derived class) IF they exist.  The base class does all the evil
stuff you are wanting to disappear from your code that is ugly and the
derived class is just the nice, clean code you are after.

--
Thomas Hruska
CubicleSoft President
Ph: 517-803-4197

*NEW* MyTaskFocus 1.1
Get on task.  Stay on task.

http://www.CubicleSoft.com/MyTaskFocus/



------------------------------------

To unsubscribe, send a blank message to <mailto:[hidden email]>.Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/c-prog/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http://groups.yahoo.com/group/c-prog/join
    (Yahoo! ID required)

<*> To change settings via email:
    [hidden email]
    [hidden email]

<*> To unsubscribe from this group, send an email to:
    [hidden email]

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/

Loading...