Function Pointer Problems

Hello,

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 using Linux by the way and gcc/g++ compiler

Thanks
Last edited on
That is because t->add is not the correct type of function pointer (it has an implict this paramter, among other things)

1
2
3
4
5
6
7
8
9
int myFunc(int x, int y) {
   return x+y;
}

int main() {
   int (*fp)(int,int);
   fp = &myFunc;
   //...
}


This works because it is "just" a function (not a member or anything)
OK,

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 ?

Puzzled...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);
}
The type of MyClass::add is

int (MyClass::*)( int, int )

which is not the same as the type of fp.

fetag,

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 can't.

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class PhidgetAccelerometer
{
public:
  int RealFunc(CPhidgetAccelerometerHandle phid,int index,double acceleration)
  {
    // do whatever you want the callback to do here
  }

  static int StaticCallback(CPhidgetAccelerometerHandle phid,void* userPtr,int index,double acceleration)
  {
    // use 'userPtr' as the 'this' pointer, and call the non-static version with it:
    return static_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.
jsmith & Disch

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

thanks for the help anyway :)
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.

Unless I'm misunderstanding you....
Thanks Disch, problem sorted now :o)
Topic archived. No new replies allowed.