Question

I'm having a great deal of problems trying to make a callback system. I want to pass a function to another class's function to receive data.

I want ExampleClass to call SeperateThread::operate, and I want SeperateThread::operate to be able to call ExampleClass::updateNumber(int) to return a value. I've been trying for hours with various function pointers etc but can't seem to get it to work.

SeperateThread is another thread so it doesn't block the main thread that ExampleClass is running in, but when SeperateThread has done it's calculations, I need to return the value to ExampleClass.

If that makes sense? Here's a run down of what I'm trying to do. In this example, I want SeperateThread::operate to call ExampleClass::updatenumber(15);...

class ExampleClass
{
    public:
        ExampleClass()
        {   
            int numberToPass = 10;
            // call SeperateThread::operate and pass value and updatenumber function as pointer
            thread.operate(numberToPass, *updatenumber(int number));
        }
        ~ExampleClass();

        void updatenumber(int number)
        {
            // Do some stuff to the number passed to this function
        }

    private:
        SeperateThread thread;
}



class SeperateThread
{
    public:
        SeperateThread();
        ~SeperateThread();

        void operate(int number, &FunctionToCallBack)
        {
            // Do some calculations (result 5 for example purposes)
            int result = numberToPass + 5;

            // Call the callback function and pass result int
            FunctionToCallBack(result);
        }
}
Was it helpful?

Solution 2

There is something important about pointing to a class member function, you have to keep in mind that a function pointer is just a regular pointer but instead of a value it points to a function, but in a class there is a special hidden variable this which makes it tricky.

One of the main problems here is that there is no pointer to the object since that would mean that you point to a function that exists within a specific object but it doesn't it just a plain function that contains this as a parameter.

thread.operate(numberToPass, *updatenumber(int number));

Here you call a function that is in another class and overall you never pass a pointer like this, it should be just the function's name since C will recognize that you want to pass it as a pointer. Generally the workaround would be to make the function static to avoid the problem with the this pointer.

One possible workaround would be to hold onto the class object and somehow hackishly call that function where you manually pass the this of the original object ( ExampleClass ).

You didn't say much about your design, but the fact that you put the source into the same field means that these classes "know" each other so why don't you just pass the class object and call the function that way like:

class BaseClass
{
public:

    BaseClass() {}
    ~BaseClass() {}

    virtual void updatenumber(int number)=0;    // pure virutal method, you MUST implement this in the subclasses!
}

class ExampleClass : public BaseClass
{
 public:
    ExampleClass()
    {   
        int numberToPass = 10;
        // call SeperateThread::operate and pass value and updatenumber function as pointer
        thread.operate(numberToPass, this);
    }
    ~ExampleClass();

    // this is now a virtual method
    void updatenumber(int number)
    {
    // Do some stuff to the number passed to this function
    }

 private:
    SeperateThread thread;
}

class SeperateThread
{
 public:
    SeperateThread();
    ~SeperateThread();

    void operate(int number,BaseClass* ObjectToCallBack)
    {
        // Do some calculations (result 5 for example purposes)
        int result = numberToPass + 5;

        // Call the callback function and pass result int
        // Note that here that this points to the BaseClass pointer but it can be a subclass of it effectively hiding it's "unneded members" at this specific point
        ObjectToCallBack->updatenumber(result);
    }
}

In case you want to hide the implementation you can just use a pure virtual class and pass that type of pointer to the SeperateThread class.

Edit : updated my example to use a base class.

OTHER TIPS

There are two issues here:

1. A Callback Function Is Not Enough

You'll need both an address for the code to call back, and the identity of the object on which the code should operate. The idiomatic C++ way to do this is to encapsulate this in an object:

class SeparateThread { 
public:
    class Callback {
    public:
        virtual void ThreadDone(int result) const = 0;
        virtual ~Callback() {}
    };
    void operate(int number, const Callback & callback)
    {
        // Calculate result
        callback.ThreadDone(result);
    }
 };

ExampleClass can then either inherit privately from SeparateThread::Callback and implement ThreadDone() or define a separate callback class:

class ExampleClassThreadCallback : public SeparateThread::Callback {
public:
    ExampleClassThreadCallback(ExampleClass * obj) : fObj(obj) {}
    void ThreadDone(int result) const override {
        fObj.updatenumber(result);
    private:
        ExampleClass * fObj;
    }
};

You then simply call the thread as:

thread.operate(number, ExampleClassThreadCallback(this));

2. Concurrency

In a design like this, where your class gets updated from a separate thread, you are likely to run into concurrency issues, so you'll have to design appropriate mechanisms to make sure that this updating does not cause problems.

There is a way to pass a member of a specific class instance to another function whether in a thread or not. If the callback is a member you need to wrap it together with the class instance you want the callback to affect.

template<typename T, typename F, typename R>
struct callback
{
    callback(T cthis, F func) : _this(cthis), _func(func) { }
    void operator()(R result)
    {
        (_this->*_func)(result);
    }
    T _this;
    F _func;
};


class SeperateThread
{
    public:
        SeperateThread() { }
        ~SeperateThread() { }

        template<typename T, typename F, typename R>
        void operate(int number, callback<T,F,R> cb)
        {
            // Do some calculations (result 5 for example purposes)
            int result = number + 5;

            // Call the callback function and pass result int
            cb(result);
        }
};

class ExampleClass
{
    public:
        ExampleClass()
        {   
            int numberToPass = 10;
            // call SeperateThread::operate and pass value and updatenumber function as pointer
            thread.operate(numberToPass, callback<ExampleClass * const, void (ExampleClass::*)(int), int>(this, &ExampleClass::updatenumber) );
        }
        ~ExampleClass() { }

        void updatenumber(int number)
        {
            // Do some stuff to the number passed to this function
            printf("Result is %d\n", number);
        }

    private:
        SeperateThread thread;
};



void test()
{
    ExampleClass a;

}

The above will print: Result is 15.

Please note that I did not address the synchronization issues due to multithreading.

If 'updatenumber' is called by more than one thread, and your code inside it accesses other data members, then you need to serialize it by adding a mutex lock at the beginning and unlock it before returning. Best is to use std::mutex if you have C++11 compiler, or do this within a small struct, locking in the constructor and unlocking in the destructor. Then you just create one such instance immediately on updatenumber() entry.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top