我在尝试建立一个回调系统时遇到了很多问题。我想将一个函数传递给另一个类的函数来接收数据。
我希望ExampleClass
致电SeperateThread::operate
,我希望SeperateThread::operate
能够致电ExampleClass::updateNumber(int)
以返回值。我已经用各种函数指针等尝试了几个小时,但似乎无法让它工作。
SeperateThread
是另一个线程,所以它不会阻塞ExampleClass
正在运行的主线程,但是当SeperateThread
完成它的计算时,我需要将值返回给{ {1}}。
如果这有道理?这是我想要做的事情。在此示例中,我希望ExampleClass
调用SeperateThread::operate
...
ExampleClass::updatenumber(15);
答案 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)
这里有两个问题:
您需要一个用于回调代码的地址,以及代码应在其上运行的对象的标识。惯用的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 :(得分: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()条目上立即创建一个此类实例。