Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Callback functions

Posted on 1999-07-06
9
Medium Priority
?
368 Views
Last Modified: 2010-05-18
I'm trying to set up a callback function in a class, but I'm getting errors at compiling time.

The following gets accepted:
class CEngine
{
public:
  void SetCallBack(void (*aFunction)(someclass))
  {
    aCallBackPointer = aFunction;
  }
  void CallFunction()
  {
    aCallBackPointer(some_correct_parameter);
  }
private:
  void (*aCallBackPointer)(someclass);
};

The following cause an error:
class CView
{
public:
  void Update(someclass aParameter);
  void SetCallBack()
  {
    CEngine eng;
    eng.SetCallBack(Update);
  }
};

The error gets generated for the "eng.SetCallBack(Update);" line.  The error description is: Can not convert parameter 1 from 'void (someclass)' to 'void (__cdecl *)(someclass)'.

Help !!
0
Comment
Question by:cfm
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
  • 3
9 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 1199368
A class' member function can only be a callback when it's declared 'static' (as the compiler tries to pass 'this' as the 1st parameter otherwise), e.g.

class CMyClass: public CWhatever
{
//...

static MyClassesTimerCallBack ( HWND, UINT, UINT, DWORD); // parameter signature for a timer callback

}

To use it (in a method of CMyClass):

// set timer callback procedure....
TIMERPROC lpTimerProc = ( TIMERPROC) MyClassesTimerCallBack´;


// create timer
if ( ! ( m_uTimerID = SetTimer ( NULL,
( UINT) this,
TIMER_DELAY,
lpTimerProc
)

To use it outside of CMyClass, you'll have to specify 'CMyClass::MyTimerCallBack' instead.

Let me know if you have further questions.
0
 
LVL 86

Expert Comment

by:jkr
ID: 1199369
BTW: The example is  a Windows timer callback, but it also suits your problem...

Feel free to ask if you need more information...
0
 

Author Comment

by:cfm
ID: 1199370
Static functions don't have access to the class members and I need that.

I also don't want to pass the class pointer to the engine, since the engine must work with any calling class.

Any other suggestions of doing this?

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 9

Expert Comment

by:jasonclarke
ID: 1199371
> A class' member function can only be a callback when it's
> declared 'static' (as the compiler tries to pass 'this'
> as the 1st parameter otherwise), e.g.

this is only true when you do not have control over how the callback is actually called, in this case where you are control both ends, everything is fine.

The program below shows the sort of thing you can do (I have not added a parameter to the callback, but this is very easy to do, if you want it).

class AbstractCallback {
public:
    virtual void operator()() = 0;
};

template <class T>
class SimpleCallback : public AbstractCallback  
{
public:
    typedef void (T::*CB)();
      
    SimpleCallback(T* instance, CB callback)
        : mInstance(instance), mCallback(callback)
      {}

    virtual ~SimpleCallback() {}

    virtual void operator()() {
        (mInstance->*mCallback)();
    }
protected:
    T* mInstance;
    CB mCallback;
};

class CEngine
{
public:
    void SetCallBack(AbstractCallback* cb) {
        mCb = cb;
    }
    void CallFunction() {
        (*mCb)();
    }
private:
    AbstractCallback* mCb;
};

class CView
{
public:
    void Update() {
        cout << "Hello" << endl; }
    void SetCallBack() {
        SimpleCallback<CView>* cb = new SimpleCallback<CView>(this, Update);
        CEngine eng;
        eng.SetCallBack(cb);
        eng.CallFunction();  // Force the callback
    }
};

void main()
{
    CView cv;
    cv.SetCallBack();
}


also, the program does not delete the callback pointer, either the caller or the client can do this depending on how you set things up, but the destructor of CEngine or CView should do this.

0
 
LVL 86

Expert Comment

by:jkr
ID: 1199372
>>Static functions don't have access to the class members
>>and I need that.

That's (partially) correct. However, there are several methods to get around this - could you explain the environment in which you're using the callback (e.g. the declaration of 'SetCallBack()', which is causing the compiler error)?

0
 

Author Comment

by:cfm
ID: 1199373
I'm writing an engine that controls communication and runs asynchronously.  The engine must somehow inform other functions if something was received (e.g. inform the view to display the info).

Creating a new message type and posting that to the message queue is not possible.  Asking the other classes to poll the engine is possible, but I don't like it.  A callback function seemed the way to go.

Some more info.  This all happens in a dll, so the declaration of static global variables is out.  The use of a static class variable storing the this pointer is possible if you are sure only one instance of the class will be created.

Any other solutions?
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 1199374
The solution I have posted should work for you (with no statics involved at all).  

In essence the callback function is wrapped in a class, and the use of an abstract base class and a templated derived class ensures that the solution is generic.
0
 

Author Comment

by:cfm
ID: 1199375
Thanks jasonclark.  Post something as an answer and I'll accept it.
0
 
LVL 9

Accepted Solution

by:
jasonclarke earned 400 total points
ID: 1199376
thanks.
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question