面向对象的C++回调?

Mat*_*Mat 8 c++ oop eiffel member-function-pointers callback

是否有一些库允许我在c ++中轻松方便地创建面向对象的回调?

例如,埃菲尔的语言具有"代理人"的概念,其或多或少的工作方式如下:

class Foo{
public:
    Bar* bar;

    Foo(){
        bar = new Bar();
        bar->publisher.extend(agent say(?,"Hi from Foo!", ?));
        bar->invokeCallback();
    }

    say(string strA, string strB, int number){
        print(strA + " " + strB + " " + number.out);
    }

}

class Bar{
public:
    ActionSequence<string, int> publisher;

    Bar(){}

    invokeCallback(){
        publisher.call("Hi from Bar!", 3);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出将是:嗨来自Bar!3来自Foo!

所以 - 代理允许将成员函数封装到一个对象中,沿着一些预定义的调用参数(来自Foo的Hi)给它,指定打开的参数(?),然后将它传递给其他对象,然后再调用它.

由于C++不允许创建非静态成员函数的函数指针,似乎并不容易实现容易在C++使用的东西.我在c ++中找到了一些关于面向对象回调的谷歌的文章,但是,实际上我正在寻找一些我可以导入的库或头文件,它允许我使用一些类似优雅的语法.

有人给我一些提示吗?

谢谢!

ste*_*anv 11

在C++中使用Callbacks的最OO方法是调用接口的函数,然后传递该接口的实现.

#include <iostream>

class Interface
{
  public:
  virtual void callback() = 0;
};

class Impl : public Interface
{
  public:
  virtual void callback() { std::cout << "Hi from Impl\n"; }
};

class User
{
  public:
  User(Interface& newCallback) : myCallback(newCallback) { }

  void DoSomething() { myCallback.callback(); }

  private:
  Interface& myCallback;
};

int main()
{
  Impl cb;
  User user(cb);
  user.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)


Pup*_*ppy 5

人们通常使用以下几种模式之一:

遗产.也就是说,您定义了一个包含回调的抽象类.然后你拿一个指针/引用它.这意味着任何人都可以继承并提供此回调.

class Foo {
    virtual void MyCallback(...) = 0;
    virtual ~Foo();
};
class Base {
    std::auto_ptr<Foo> ptr;
    void something(...) {
        ptr->MyCallback(...);
    }
    Base& SetCallback(Foo* newfoo) { ptr = newfoo; return *this; }
    Foo* GetCallback() { return ptr; }
};
Run Code Online (Sandbox Code Playgroud)

再次继承.也就是说,您的根类是抽象的,并且用户从它继承并定义回调,而不是具有具体的类和专用的回调对象.

class Foo {
    virtual void MyCallback(...) = 0;
    ...
};
class RealFoo : Foo {
    virtual void MyCallback(...) { ... }
};
Run Code Online (Sandbox Code Playgroud)

更多的继承 - 静态.这样,您可以使用模板来更改对象的行为.它与第二个选项类似,但在编译时而不是在运行时工作,这可能会产生各种好处和缺点,具体取决于上下文.

template<typename T> class Foo {
    void MyCallback(...) {
        T::MyCallback(...);
    }
};
class RealFoo : Foo<RealFoo> {
    void MyCallback(...) {
        ...
    }
};
Run Code Online (Sandbox Code Playgroud)

您可以使用和使用成员函数指针或常规函数指针

class Foo {
    void (*callback)(...);
    void something(...) { callback(...); }
    Foo& SetCallback( void(*newcallback)(...) ) { callback = newcallback; return *this; }
    void (*)(...) GetCallback() { return callback; }
};
Run Code Online (Sandbox Code Playgroud)

有功能对象 - 它们重载operator().您将需要使用或编写当前在std ::/boost :: function中提供的函数包装器,但我还将在此处演示一个简单的包装器.它与第一个概念类似,但隐藏了实现并接受了大量其他解决方案.我个人通常使用它作为我选择的回调方法.

class Foo {
    virtual ... Call(...) = 0;
    virtual ~Foo();
};
class Base {
    std::auto_ptr<Foo> callback;
    template<typename T> Base& SetCallback(T t) {
        struct NewFoo : Foo {
             T t;
             NewFoo(T newt) : t(newt) {}
             ... Call(...) { return t(...); }
        };
        callback = new NewFoo<T>(t);
        return this;
    }
    Foo* GetCallback() { return callback; }
    void dosomething() { callback->Call(...); }
};
Run Code Online (Sandbox Code Playgroud)

正确的解决方案主要取决于具体情况.如果需要公开C风格的API,那么函数指针是唯一的方法(记住用户参数的void*).如果需要在运行时改变(例如,在预编译库中公开代码),则不能在此处使用静态继承.

只是一个简单的说明:我手动掀起了那些代码,所以它不会是完美的(比如函数的访问修饰符等)并且可能有一些错误.这是一个例子.


the*_*row 2

C++ 允许在成员对象上使用函数指针。
请参阅此处了解更多详细信息。
您还可以使用boost.signalsboost.signals2(取决于您的程序是否是多线程的)。