回调函数C ++

时间:2014-03-02 19:18:30

标签: c++ multithreading function function-pointers

我在尝试建立一个回调系统时遇到了很多问题。我想将一个函数传递给另一个类的函数来接收数据。

我希望ExampleClass致电SeperateThread::operate,我希望SeperateThread::operate能够致电ExampleClass::updateNumber(int)以返回值。我已经用各种函数指针等尝试了几个小时,但似乎无法让它工作。

SeperateThread是另一个线程,所以它不会阻塞ExampleClass正在运行的主线程,但是当SeperateThread完成它的计算时,我需要将值返回给{ {1}}。

如果这有道理?这是我想要做的事情。在此示例中,我希望ExampleClass调用SeperateThread::operate ...

ExampleClass::updatenumber(15);

3 个答案:

答案 0 :(得分:1)

指向类成员函数有一些重要的事情,你必须记住,函数指针只是一个常规指针,而不是一个值,它指向一个函数,但在一个类中有一个特殊的隐藏变量 this 这使得它变得棘手。

这里的一个主要问题是没有指向对象的指针,因为这意味着你指向一个特定对象中存在的函数,但它不只是一个包含 this的普通函数作为参数。

  

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

在这里你调用另一个类中的函数,总的来说你永远不会传递这样的指针,它应该只是函数的名称,因为C会识别你想要将它作为指针传递。通常,解决方法是使函数保持静态以避免使用this指针的问题。

一种可能的解决方法是保留类对象,然后以某种方式hackishly调用该函数,您手动传递原始对象的这个(ExampleClass)。

你没有多说你的设计,但你把源放到同一个字段的事实意味着这些类“彼此”“知道”,所以你为什么不传递类对象并调用那个函数像:

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);
    }
}

如果您想要隐藏实现,您可以使用纯虚拟类并将该类型的指针传递给SeperateThread类。

编辑:更新我的示例以使用基类。

答案 1 :(得分:1)

这里有两个问题:

1。回调函数不够

您需要一个用于回调代码的地址,以及代码应在其上运行的对象的标识。惯用的C ++方法是将它封装在一个对象中:

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可以从SeparateThread::Callback私下继承并实现ThreadDone()或定义一个单独的回调类:

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

然后您只需将该主题调用为:

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

2。并发

在这样的设计中,您的类从单独的线程更新,您可能会遇到并发问题,因此您必须设计适当的机制以确保此更新不会导致问题。

答案 2 :(得分:0)

有一种方法可以将特定类实例的成员传递给另一个函数,无论是否在线程中。如果回调是成员,则需要将其与要求回调影响的类实例一起包装。

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;

}

以上将打印:结果为15。

请注意,由于多线程,我没有解决同步问题。

如果'updatenumber'被多个线程调用,并且其中的代码访问其他数据成员,则需要通过在开头添加互斥锁并在返回之前将其解锁来序列化它。如果你有C ++ 11编译器,最好是使用std :: mutex,或者在一个小结构中执行此操作,锁定构造函数并在析构函数中解锁。然后,您只需在updatenumber()条目上立即创建一个此类实例。