0

Here is some code:

typedef void (*ACallBack)(int i);

class SomeClass
{
private:
   ACallBack aCallBack;

public:
   void SetCallBack(ACallBack aCallBack);
};

void SomeClass::SetCallBack(ACallBack aCallBack)
{
   this->aCallBack = aCallBack;
}

class SomeOtherClass
{
private:
   SomeClass someClass;

public:
   void InitializeSomeClass();

private:
   void callBackMethod(int i);
};

void SomeOtherClass::InitializeSomeClass()
{
   this->changeVariable = 10;

   this->someClass.SetCallBack(this->callBackMethod); // DOESN'T WORK
   this->someClass.UseCallBack();
}

void SomeOtherClass::callBackMethod(int i)
{
}

void globalCallBack(int i)
{
   int myInt = i;
}

int main()
{
   SomeClass sC;
   sC.SetCallBack(globalCallBack); //WORKS!!
}

Basically if I try to set my callback function in SomeOtherClass it doesn't work but when I set it globally in main it does. What am I missing here?

Pittfall
  • 2,751
  • 6
  • 32
  • 61
  • 2
    Member functions have a hidden first argument that becomes the `this` pointer, so you can't use a normal (non-member) function pointer for member functions. Instead use e.g. [`std::function`](http://en.cppreference.com/w/cpp/utility/functional/function), possibly together with [`std::bind`](http://en.cppreference.com/w/cpp/utility/functional/bind). See e.g. [this old answer of mine](http://stackoverflow.com/a/14189561/440558) for an example on how to use `std::function` and `std::bind`. – Some programmer dude Mar 24 '15 at 19:50
  • so `void SetCallBack(std::function aCallBack, void* userData = NULL);` and then `this->someClass.SetCallBack(std::bind(&SomeOtherClass::callBackMethod, this, _1, _2));`. I was trying to avoid this so that I don't change the design in `SomeClass`. If there is some other way. – Pittfall Mar 24 '15 at 19:52
  • I don't think this compiles, SomeOtherClass::callBackMethod is not in a class definition. But is you make it static in the class definition it does satisfy the callback signature. – Philip Stuyck Mar 24 '15 at 19:55
  • Does [this](http://stackoverflow.com/questions/29240317/passing-member-function-to-another-objects-member-function-c/29240739#29240739) help? – James Adkison Mar 24 '15 at 19:59
  • You should consider using `std::function` and `std::bind` instead, `void *userData` is a C way – Slava Mar 24 '15 at 20:03
  • @JamesAdkison it does help but it still causes me to change my design of `SomeClass`. I'm not trying to be stubborn but it's not my design to change. I will take the hit if there's no other way/syntax to do this. – Pittfall Mar 24 '15 at 20:04
  • @Pittfall Why can't you change from a function pointer to `std::function` to achieve your result? – James Adkison Mar 24 '15 at 20:09
  • this->someClass.UseCallBack(); where is usecallback defined ? – Philip Stuyck Mar 24 '15 at 20:24

2 Answers2

1

Just use std::function and std::bind():

typedef std::function<void(int i)> ACallBack;

// old code pretty much the same

int main()
{
    using namespace std::placeholders;

    SomeClass sC;
    sC.SetCallBack(globalCallBack); //WORKS!!
    SomeOtherClass oC;
    sC.SetCallBack(std::bind(&SomeOtherClass::callBackMethod,oC,_1)); //WORKS AS WELL!!
}

In this case you do not really need to pass void *userData but may add it as well if you need old code to compile.

Slava
  • 43,454
  • 1
  • 47
  • 90
  • My only problem with this is that with bind you don't need to enforce that parameter `int i`. You can create your callback method without it and all `bind` cares about is that the parameters satisfy your callback method. I guess I will do more reading on `bind` and figure out a solution. – Pittfall Mar 25 '15 at 14:02
  • I do not really think that is a problem. Even if you enforce such parameter you can easily ignore it inside the function. On another side if such function uses that parameter that will enforce it's existence. Parameter existence will enforce that you pass at least something through `bind`. – Slava Mar 27 '15 at 18:19
0

You have to make the method static:

static void callBackMethod(int i, void* userData);

if you need a pointer to a method that is not static, ie an instance method, it becomes more complex.

typedef void ( myclass::*FUNC ) (int i, void* userData);

and if you want to use it, it becomes a hastlle :

myclass obj;        // instantiate myclass
FUNC f = &myclass::myfunc;  // assign address
( obj.*f ) ( 123, NULL );   // and call it
Philip Stuyck
  • 7,344
  • 3
  • 28
  • 39