[英]How do I implement a callback in C++?
我想在具有回调的c ++中实现一个类。
所以我想我需要一个有2个参数的方法:
条件是:
myObj可以来自任何类。
将成为回调函数的成员函数是非静态的。
我一直在阅读有关此内容的信息,但似乎我需要事先了解myObj的类。 但是我不确定该怎么做。 我该如何处理? 这在C ++中可能吗?
这是我想到的,但肯定是不正确的。
class MyClassWithCallback{
public
void *targetObj;
void (*callback)(int number);
void setCallback(void *myObj, void(*callbackPtr)(int number)){
targetObj = myObj;
callback = callbackPtr;
};
void callCallback(int a){
(myObj)->ptr(a);
};
};
class Target{
public
int res;
void doSomething(int a){//so something here. This is gonna be the callback function};
};
int main(){
Target myTarget;
MyClassWithCallback myCaller;
myCaller.setCallback((void *)&myTarget, &doSomething);
}
感谢您的帮助。
谢谢。
更新你们中的大多数人都说观察和委派,这正是我所寻找的,我是一个具有Objective-C / Cocoa意识的人。 我当前的实现是将接口与虚函数一起使用。 只是我认为仅传递对象和成员函数指针(例如boost!)而不是定义接口将是“更智能的”。 但是似乎每个人都同意接口是最简单的方法吧? Boost似乎是一个好主意,(假设已安装)
最好的解决方案是将boost::function
与boost::bind
,或者如果您的编译器支持tr1 / c ++ 0x,请使用std::tr1::function
和std::tr1::bind
。
这样就变得很简单:
boost::function<void()> callback;
Target myTarget;
callback=boost::bind(&Target::doSomething,&myTarget);
callback(); // calls the function
您设置的回调变为:
class MyClassWithCallback{
public:
void setCallback(boost::function<void()> const &cb)
{
callback_ = cb;
}
void call_it() { callback_(); }
private:
boost::function<void()> callback_;
};
否则,您需要实现一些抽象类
struct callback {
virtual void call() = 0;
virtual ~callback() {}
};
struct TargetCallback {
virtual void call() { ((*self).*member)()); }
void (Target::*member)();
Target *self;
TargetCallback(void (Target::*m)(),Target *p) :
member(m),
self(p)
{}
};
然后使用:
myCaller.setCallback(new TargetCallback(&Target::doSomething,&myTarget));
当您的班级修改为:
class MyClassWithCallback{
public:
void setCallback(callback *cb)
{
callback_.reset(cb);
}
void call_it() { callback_->call(); }
private:
std::auto_ptr<callback> callback_;
};
当然,如果您要调用的函数没有更改,则可以实现一些接口,即,通过此调用从某些抽象类派生Target。
一种技巧是改用接口,这样,如果传入的对象实现了接口,则无需专门知道'MyClassWithCallback'中的类。
例如(伪代码)
struct myinterface
{
void doSomething()=0;
};
class Target : public myinterface { ..implement doSomething... };
和
myinterface *targetObj;
void setCallback(myinterface *myObj){
targetObj = myObj;
};
做回调
targetObj->doSomething();
设置:
Target myTarget;
MyClassWithCallback myCaller;
myCaller.setCallback(myTarget);
观察者设计模式似乎是您想要的。
您有一些基本选择:
1)指定回调将使用的类,以便知道对象指针和成员函数指针类型,并且可以在调用方中使用。 该类可能有多个具有相同签名的成员函数,可以在它们之间进行选择,但是您的选择非常有限。
您在代码中做错的一件事是C ++中的成员函数指针和自由函数指针不相同,并且不是兼容类型。 您的回调注册函数需要一个函数指针,但是您试图将其传递给成员函数指针。 不允许。 此外,“ this”对象的类型是成员函数指针的类型的一部分,因此在C ++中没有诸如“指向任何采用整数并返回void的成员函数的指针”这样的东西。 它必须是“指向Target的任何成员函数的指针,该函数采用整数并返回void”。 因此,有限的选择。
2)在接口类中定义纯虚函数。 因此,任何想要接收回调的类都可以从接口类继承。 由于多重继承,这不会干扰您的其他类层次结构。 这几乎与在Java中定义接口完全相同。
3)对回调使用非成员函数。 对于每个要使用它的类,您都编写了一个无存根的小函数,该函数接受对象指针并在其上调用正确的成员函数。 因此,在您的情况下,您将拥有:
dosomething_stub(void *obj, int a) {
((Target *)obj)->doSomething(a);
}
4)使用模板:
template<typename CB> class MyClassWithCallback {
CB *callback;
public:
void setCallback(CB &cb) { callback = &cb; }
void callCallback(int a) {
callback(a);
}
};
class Target {
void operator()(int a) { /* do something; */ }
};
int main() {
Target t;
MyClassWithCallback<T> caller;
caller.setCallback(t);
}
是否可以使用模板取决于您的ClassWithCallback是否是某个旧框架的一部分-如果是这样,则可能是不可能的(准确地说:可能需要更多技巧,例如从非模板类继承而来的模板类具有虚拟成员函数),因为您不一定必须为每个回调接收者实例化整个框架一次。
在C ++中,几乎不使用指向类方法的指针。 您实际上叫-它是委托人,不建议使用它们。 代替它们,您必须使用虚函数和抽象类。 但是,如果C ++不支持完全不同的编程概念,就不会那么喜欢我。 如果仍然需要委托,则应着眼于“增强功能”(C + +0 x的一部分),它允许使用指向类方法的指针,而不管类名如何。 此外,在C ++ Builder中,类型__closure-在编译器级别实现委托。
PS对不起,英语不好...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.