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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3381829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 12:43:39  来源:igfitidea点击:

How do I implement a callback in C++?

c++callback

提问by nacho4d

I want to implement a class in c++ that has a callback.

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

So I think I need a method that has 2 arguments:

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

  • the target object. (let's say *myObj)
  • the pointer to a member function of the target object. (so i can do *myObj->memberFunc(); )
  • 目标对象。(假设 *myObj)
  • 指向目标对象成员函数的指针。(所以我可以做 *myObj->memberFunc(); )

The conditions are:

条件是:

  • myObj can be from any class.

  • the member function that is gonna be the callback function is non-static.

  • myObj 可以来自任何类。

  • 将成为回调函数的成员函数是非静态的。

I've been reading about this but it seems like I need to know the class of myObj before hand. But I am not sure how to do it. How can I handle this? Is this possible in C++?

我一直在阅读这个,但似乎我需要事先知道 myObj 的类。但我不知道该怎么做。我该如何处理?这在 C++ 中可能吗?

This is something I have in mind but is surely incorrect.

这是我想到的,但肯定是不正确的。

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

}

}

I appreciate any help.

我很感激任何帮助。

Thank you.

谢谢你。

UPDATE Most of you said Observing and Delegation, well that's i exactly what i am looking for, I am kind of a Objective-C/Cocoa minded guy. My current implementation is using interfaces with virtual functions. Is just I thought it would be "smarter" to just pass the object and a member function pointer (like boost!) instead of defining an Interface. But It seems that everybody agrees that Interfaces are the easiest way right? Boost seems to be a good idea, (assuming is installed)

更新你们中的大多数人都说观察和委托,这正是我正在寻找的,我是一个有 Objective-C/Cocoa 头脑的人。我当前的实现是使用带有虚函数的接口。只是我认为只传递对象和成员函数指针(如 boost!)而不是定义接口会“更聪明”。但似乎每个人都同意接口是最简单的方法,对吗?Boost 似乎是个好主意,(假设已安装)

回答by Artyom

The best solution, use boost::functionwith boost::bind, or if your compiler supports tr1/c++0x use std::tr1::functionand std::tr1::bind.

最好的解决方案是使用boost::functionwith boost::bind,或者如果您的编译器支持 tr1/c++0x 使用std::tr1::functionstd::tr1::bind.

So it becomes as simple as:

所以它变得很简单:

boost::function<void()> callback;
Target myTarget;
callback=boost::bind(&Target::doSomething,&myTarget);

callback(); // calls the function

And your set callback becomes:

你设置的回调变成:

class MyClassWithCallback{
public:
  void setCallback(boost::function<void()> const &cb)
  {
     callback_ = cb;
  }
  void call_it() { callback_(); }
private:
  boost::function<void()> callback_;
};

Otherwise you need to implement some abstract class

否则你需要实现一些抽象类

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

And then use:

然后使用:

myCaller.setCallback(new TargetCallback(&Target::doSomething,&myTarget));

When your class get modified into:

当您的班级被修改为:

class MyClassWithCallback{
public:
  void setCallback(callback *cb)
  {
     callback_.reset(cb);
  }
  void call_it() { callback_->call(); }
private:
  std::auto_ptr<callback> callback_;
};

And of course if the function you want to call does not change you may just implement some interface, i.e. derive Target from some abstract class with this call.

当然,如果你想调用的函数没有改变,你可以只实现一些接口,即通过这个调用从某个抽象类派生 Target。

回答by AndersK

One trick is to use interfaces instead, that way you don't need specifically to know the class in your 'MyClassWithCallback', if the object passed in implements the interface.

一个技巧是改用接口,如果传入的对象实现了接口,那么您不需要专门知道“MyClassWithCallback”中的类。

e.g. (pseudo code)

例如(伪代码)

struct myinterface
{
  void doSomething()=0;
};

class Target : public myinterface { ..implement doSomething... };

and

myinterface *targetObj; 
void setCallback(myinterface *myObj){
    targetObj = myObj;
};

doing the callback

做回调

targetObj->doSomething();

setting it up:

设置它:

Target myTarget;
MyClassWithCallback myCaller;
myCaller.setCallback(myTarget);

回答by Greg Sexton

The Observerdesign pattern seems to be what you're looking for.

观察者设计模式似乎是你在找什么。

回答by Steve Jessop

You have a few basic options:

您有几个基本选项:

1) Specify what class the callback is going to use, so that the object pointer and member function pointer types are known, and can be used in the caller. The class might have several member functions with the same signature, which you can choose between, but your options are quite limited.

1) 指定回调将要使用的类,这样对象指针和成员函数指针类型是已知的,并且可以在调用者中使用。该类可能有多个具有相同签名的成员函数,您可以在其中进行选择,但您的选择非常有限。

One thing that you've done wrong in your code is that member function pointers and free function pointers in C++ are not the same, and are not compatible types. Your callback registration function takes a function pointer, but you're trying to pass it a member function pointer. Not allowed. Furthermore, the type of the "this" object is part of the type of a member function pointer, so there's no such thing in C++ as "a pointer to any member function which takes an integer and returns void". It has to be, "a pointer to any member function of Targetwhich takes an integer and returns void". Hence the limited options.

您在代码中做错的一件事是 C++ 中的成员函数指针和自由函数指针不一样,并且是不兼容的类型。您的回调注册函数需要一个函数指针,但您试图将成员函数指针传递给它。不允许。此外,“this”对象的类型是成员函数指针类型的一部分,因此在 C++ 中没有“指向任何接受整数并返回 void 的成员函数的指针”这样的东西。它必须是“指向Target 的任何成员函数指针,它接受一个整数并返回 void”。因此选择有限。

2) Define a pure virtual function in an interface class. Any class which wants to receive the callback therefore can inherit from the interface class. Thanks to multiple inheritance, this doesn't interfere with the rest of your class hierarchy. This is almost exactly the same as defining an Interface in Java.

2) 在接口类中定义纯虚函数。因此,任何想要接收回调的类都可以从接口类继承。由于多重继承,这不会干扰类层次结构的其余部分。这几乎与在 Java 中定义接口完全相同。

3) Use a non-member function for the callback. The for each class which wants to use it, you write a little stub free function which takes the object pointer and calls the right member function on it. So in your case you'd have:

3) 对回调使用非成员函数。对于每个想要使用它的类,您编写一个小的存根自由函数,它接受对象指针并在其上调用正确的成员函数。因此,在您的情况下,您将拥有:

dosomething_stub(void *obj, int a) {
    ((Target *)obj)->doSomething(a);
}

4) Use templates:

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

Whether you can use templates depends whether your ClassWithCallback is part of some big old framework - if so then it might not be possible (to be precise: might require some more tricks, such as a template class which inherits from a non-template class having a virtual member function), because you can't necessarily instantiate the entire framework once for each callback recipient.

您是否可以使用模板取决于您的 ClassWithCallback 是否是某个大型旧框架的一部分-如果是,则可能不可能(准确地说:可能需要更多技巧,例如从非模板类继承的模板类具有一个虚拟成员函数),因为您不一定为每个回调接收者实例化整个框架一次。

回答by StuartLC

Also, look at the Observer Patternand signals and slots. This extends to multiple subscribers.

另外,看看观察者模式信号和插槽。这扩展到多个订阅者。

回答by Daminian

In C++, pointers to class methods are hardly used. The fact that you called in - it is delegates and their use is not recommended. Instead of them, you must use virtual functions and abstract classes. However, C++ would not have been so fond of me, if it not supported completely different concepts of programming. If you still want delegates, you should look towards "boost functional" (part of C + +0 x), it allows pointers to methods of classes regardless of the class name. Besides, in C++ Builder has type __closure - implementation of a delegate at the level of the compiler.

在 C++ 中,几乎不使用指向类方法的指针。您调用的事实 - 它是代表,不建议使用它们。您必须使用虚函数和抽象类来代替它们。但是,如果 C++ 不支持完全不同的编程概念,我就不会这么喜欢它。如果您仍然需要委托,则应该考虑“增强功能”(C++0 x 的一部分),它允许指向类方法的指针,而不管类名如何。此外,在 C++ Builder 中有 __closure 类型 - 在编译器级别实现委托。

P.S. Sorry for bad English...

PS抱歉英语不好...