473,387 Members | 1,548 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

C2664 and passing member function pointer

I am attempting to use a wrapper class to the Win32 timer API in a Visual C++ 6.0 MFC application. The callback function needs to have access to the front panel, and as such needs to be a member of the front panel class. I kept getting compile error C2276 when I tried passing the address of a member function. After implementing a few changes suggested by the author of the class, I now get the following error when compiling:

error C2664: 'setCallbackFunction' : cannot convert parameter 1 from 'void (__stdcall CTestDlg::*)(int)' to 'void (__cdecl *)(int)'
There is no context in which this conversion is possible

The line that causes the error is:
Expand|Select|Wrap|Line Numbers
  1. timer1.setCallbackFunction(&CTestDlg::timer1Event);
The prototype of the callback function looks like this:
Expand|Select|Wrap|Line Numbers
  1. void CALLBACK CTestDlg::timer1Event(int i)
The prototype of the setCallbackFunction function looks like this:
Expand|Select|Wrap|Line Numbers
  1. VOID LRTimer::setCallbackFunction( VOID (*_pCallback)(int)) {
  2.         m_pCallback = _pCallback;
  3. }
Do you have any ideas as to how I might fix this? I would greatly appreciate it if I could get a fix within the next 48 hours - this is a rather important part of a project I'm working on. I tried contacting the author of the class, but it looks like he hasn't been active for a while.

Thank you!
Ian
Sep 9 '07 #1
3 4347
Banfa
9,065 Expert Mod 8TB
Expand|Select|Wrap|Line Numbers
  1. VOID LRTimer::setCallbackFunction( VOID (*_pCallback)(int)) {
  2.         m_pCallback = _pCallback;
  3. }
This function takes a pointer to a function, not a pointer to a function member of an object. That is internally setCallbackFunction (and LRTIMER) has no knowledge of the any object containing the callback function and does not perform any of the pointer manipulation (creating and passing this) that would be required to call a object member function. And in fact dopes not have access to the data required to create this.

Expand|Select|Wrap|Line Numbers
  1. void CALLBACK CTestDlg::timer1Event(int i)
This function is a member of CTestDlg and before calling requires that this is created and passed to timer1Event.

Solutions

You could make CTestDlg::timer1Event a static function. This means that timer1Event is a class method, it would be unable to access any object data through this as the this pointer is not set up for class methods. Obviously only you can say if you are able to work with this constraint. May be the data passed would be enough for you t identify the object required and then call a normal method on the object from the class member function.

You could change the prototype of setCallbackFunction if you have access to all it's source code (i.e. you are not using it as a library. In this case you change setCallbackFunction (or add an overload of it) and all the relevent places in the LRTimer class to accept a pointer to and object of type CTestDlg. And then internally call the relevent member function.

Expand|Select|Wrap|Line Numbers
  1. VOID LRTimer::setCallbackFunction( CTestDlg *pCallbackObject)
Sep 10 '07 #2
Expand|Select|Wrap|Line Numbers
  1. VOID LRTimer::setCallbackFunction( VOID (*_pCallback)(int)) {
  2.         m_pCallback = _pCallback;
  3. }
This function takes a pointer to a function, not a pointer to a function member of an object. That is internally setCallbackFunction (and LRTIMER) has no knowledge of the any object containing the callback function and does not perform any of the pointer manipulation (creating and passing this) that would be required to call a object member function. And in fact dopes not have access to the data required to create this.

Expand|Select|Wrap|Line Numbers
  1. void CALLBACK CTestDlg::timer1Event(int i)
This function is a member of CTestDlg and before calling requires that this is created and passed to timer1Event.

Solutions

You could make CTestDlg::timer1Event a static function. This means that timer1Event is a class method, it would be unable to access any object data through this as the this pointer is not set up for class methods. Obviously only you can say if you are able to work with this constraint. May be the data passed would be enough for you t identify the object required and then call a normal method on the object from the class member function.

You could change the prototype of setCallbackFunction if you have access to all it's source code (i.e. you are not using it as a library. In this case you change setCallbackFunction (or add an overload of it) and all the relevent places in the LRTimer class to accept a pointer to and object of type CTestDlg. And then internally call the relevent member function.

Expand|Select|Wrap|Line Numbers
  1. VOID LRTimer::setCallbackFunction( CTestDlg *pCallbackObject)
Banfa, thank you very much for your quick response. Unfortunately my automatic notification settings must be incorrect, and I didn't notice your response until this morning.

What I ended up doing was creating a non-member function to use as the callback, and calling member functions in the callback using a global pointer to "this".

Expand|Select|Wrap|Line Numbers
  1. VOID timer1Event()
  2. {
  3.      dialogObject->memberFunction(); //dialogObject is a pointer to the form object
  4. }
  5.  
I know global variables aren't exactly the best programming practice, but eventually I'll need several different timers each with a different callback function, and this was the easiest way that I could think of to do it.

Thanks again,
Ian
Sep 12 '07 #3
Banfa
9,065 Expert Mod 8TB
Banfa, thank you very much for your quick response. Unfortunately my automatic notification settings must be incorrect, and I didn't notice your response until this morning.
The automatic notification on this site is somewhat broken, I suggest you check back to the site itself every now and then and check your user control panel for updates.

What I ended up doing was creating a non-member function to use as the callback, and calling member functions in the callback using a global pointer to "this".

Expand|Select|Wrap|Line Numbers
  1. VOID timer1Event()
  2. {
  3.      dialogObject->memberFunction(); //dialogObject is a pointer to the form object
  4. }
  5.  
I know global variables aren't exactly the best programming practice, but eventually I'll need several different timers each with a different callback function, and this was the easiest way that I could think of to do it.
OK, that is definately the quick and dirty hack :D and you have the prototype of timer1Event wrong, it is supposed to accept an int parameter. This hack will not scale.

Here is what I would say is a better solution

You need a way to associate the LRTimer instance with the CTestDlg instance. Do you access to the code of both classes?

If so then pass a pointer to your CTestDlg instance to the LRTimer, the callback can then be a member function of CTestDlg which LRTimer can call directly, but you would have to handle the case of the CTestDlg instance being deleted before the LRTimer instance had timed out (i.e. the risk of LRTimer trying to use an invalid CTestDlg instance).

If you do not have access to both classes, particularly access to the LRTimer class then:

Firstly make the callback a static member of CTestDlg, if possible make it private. This will only be possible if you create the timer from within the CTestDlg class somewhere.

To associate the 2 instances you will need to have identifying data, this could be the pointer to the class or it could be an id, whatever it is it must uniquely identify the instance. You can then set up a map (again a private member of CTestDlg) which you will be able to consult to get the correct CTestDlg instance for any LRTimer callback and so call the correct object.

When instances are deleted you can simple remove the corresponding map member to prevent use of invalid pointers.
Sep 13 '07 #4

Sign in to post your reply or Sign up for a free account.

Similar topics

5
by: Newsgroup - Ann | last post by:
Gurus, I have the following implementation of a member function: class A { // ... virtual double func(double v); void caller(int i, int j, double (* callee)(double)); void foo() {caller(1,...
7
by: James Vanns | last post by:
Sounds nasty doesn't it!! Well it's kinda what I need to do! I have an external C struct (external to the C++ project/classes etc.) which is wants a function ptr assigned to one of it's members: ...
6
by: keepyourstupidspam | last post by:
Hi, I want to pass a function pointer that is a class member. This is the fn I want to pass the function pointer into: int Scheduler::Add(const unsigned long timeout, void* pFunction, void*...
17
by: Christopher Benson-Manica | last post by:
Does the following program exhibit undefined behavior? Specifically, does passing a struct by value cause undefined behavior if that struct has as a member a pointer that has been passed to...
11
by: cps | last post by:
Hi, I'm a C programmer taking my first steps into the world of C++. I'm currently developing a C++ 3D graphics application using GLUT (OpenGL Utility Toolkit written in C) for the GUI...
3
by: dice | last post by:
Hi, In order to use an external api call that requires a function pointer I am currently creating static wrappers to call my objects functions. I want to re-jig this so I only need 1 static...
7
by: TS | last post by:
I was under the assumption that if you pass an object as a param to a method and inside that method this object is changed, the object will stay changed when returned from the method because the...
18
by: tbringley | last post by:
I am a c++ newbie, so please excuse the ignorance of this question. I am interested in a way of having a class call a general member function of another class. Specifically, I am trying to...
8
by: S. | last post by:
Hi all, Can someone please help me with this? I have the following struct: typedef struct { char *name; int age; } Student;
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.