I'm having problems understanding/using function pointers. I'm trying to use a member function of an instantiated class i.e. non-static as a call back function and need to pass a function pointer to the caller.
I've posted an example below which will result in the same compile error in my code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class MyClass {
public:
MyClass(){};
virtual ~MyClass(){};
int add(int oneNumber, int twoNumber){return (oneNumber + twoNumber);};
};
int main(){
MyClass* t = new MyClass();
int (*fp)(int,int); // Create a function pointer - will point to a member function of an INSTANCE of class MyClass
fp = t->add; // Results in a compiler error
delete(t);
}
The compiler gives :
test.cpp:12: error: argument of type ‘int (MyClass::)(int, int)’ does not match ‘int (*)(int, int)
Just how do I pass a (*) pointer ? (and what is a (*) pointer anyway ???) Unfortunately I cannot change the calling function as it is code not written by myself and it is has been written in C. How do I pass a pointer to a function of a class instance ?
I'm no expert programmer by any means, and I don't really understand why this->add doesn't pass the address of the member function add().
Is there anyway I can pass the address of the member function ? I mean &myFunc just results in an address in memory being passed, which is just the same as this->add except the address is determined at runtime obviously. I don't understand why it would be a problem to compile the program. the 'this' keyword is there to determine the address of an object at runtime, so why can't it be used to determine the address of one of its member function ?
class MyClass {
public:
MyClass(){};
virtual ~MyClass(){};
int add(int oneNumber, int twoNumber){return (oneNumber + twoNumber);};
};
int main(){
MyClass* t = new MyClass();
int (MyClass::*fp)(int, int) = &MyClass::add;
(t->*fp)(20, 30);
delete(t);
}
Thanks for that, that works in my simple example, but now I'm having problems implementing it in my actual code;
I need to set a callback function using a predetermined C function whose prototype is :
1 2 3
int CPhidgetAccelerometer_set_OnAccelerationChange_Handler (CPhidgetAccelerometerHandle phid,
int(*fptr)(CPhidgetAccelerometerHandle phid, void *userPtr, int index, double acceleration), //This is the problematic line
void *userPtr)
To do so I have tried this code, where I have set up a function pointer in a manner described in your post :
1 2 3 4
/* Set up the callback */
int (PhidgetAccelerometer::*fp)(CPhidgetAccelerometerHandle phid, void *userPtr, int index, double acceleration);
fp = &PhidgetAccelerometer::callBack;
int r = CPhidgetAccelerometer_set_OnAccelerationChange_Handler(this->accel,fp,NULL); //the line that fails compilation
However I'm still getting the same error :
phidgetaccelerometer.cpp:12: error: cannot convert ‘int (PhidgetAccelerometer::*)(_CPhidgetAccelerometer*, void*, int, double)’ to ‘int (*)(_CPhidgetAccelerometer*, void*, int, double)’ for argument ‘2’ to
‘int CPhidgetAccelerometer_set_OnAccelerationChange_Handler(_CPhidgetAccelerometer*, int (*)(_CPhidgetAccelerometer*, void*, int, double), void*)’
Now as jsmith pointed out with my simple example, the compile failed as I was trying to deal with dissimilar types. But how can I cast (PhidgetAccelerometer::*) as (*) ? In C it's easy as I just give the name of the function but in C++ trying to pass a pointer to a member function of an instance seems impossible, or is it the fact that I'm trying to interface with C code ?
You have to make PhidgetAccelerometer::callBack a static member function of the class (but then it has no "this" pointer.) Welcome to the wonderful world of C callbacks.
You can't use a non-static member function because it takes a hidden "this" pointer as a parameter. Therefore the C callback doesn't have all the right parameters.
As has been said, there is no way to do this directly, although C callbacks often provide a generic "this" pointer in the form of a "user pointer" (typically a void*). As is the case here. You can take advantage of this:
class PhidgetAccelerometer
{
public:
int RealFunc(CPhidgetAccelerometerHandle phid,int index,double acceleration)
{
// do whatever you want the callback to do here
}
staticint StaticCallback(CPhidgetAccelerometerHandle phid,void* userPtr,int index,double acceleration)
{
// use 'userPtr' as the 'this' pointer, and call the non-static version with it:
returnstatic_cast<PhidgetAccelerometer*>(userPtr)->RealFunc(phid,index,acceleration);
}
};
//-----------------
// then to supply the callback -- use 'RealFunc' as the callback instead, and supply the desired
// object as the userPtr parameter
CPhidgetAccelerometer_set_OnAccelerationChange_Handler(this->accel,
&PhidgetAccelerometer::StaticCallback,
this ); // <--
Of course if you dont' need 'this' in the callback, you can simply make it static and be done with it.
Also... good god at these absurdly long class/function names. I'm all for being descriptive, but CPhidgetAccelerometer_set_OnAccelerationChange_Handler is just downright ridiculous.
Thanks.. for that, seems that what I want to achieve can't be achieved the way I want. I'll have to declare a static class callback and keep a map of all instances of my modules and call the relevant instance method frm that.
As regards functuion names.. they're not my choosing ! :p
I'll have to declare a static class callback and keep a map of all instances of my modules and call the relevant instance method frm that.
Err... no you don't have to do this.
Use the "userdata" pointer. You can give it any pointer, and it will pass it to the callback function unaltered. It's there specifically for this purpose.