繁体   English   中英

如何在C ++中实现回调?

[英]How do I implement a callback in C++?

我想在具有回调的c ++中实现一个类。

所以我想我需要一个有2个参数的方法:

  • 目标对象。 (假设* myObj)
  • 指向目标对象的成员函数的指针。 (所以我可以做* myObj-> memberFunc();)

条件是:

  • 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::functionboost::bind ,或者如果您的编译器支持tr1 / c ++ 0x,请使用std::tr1::functionstd::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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM