是否有一些库可以让我轻松方便地在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);
}
}
输出将是: 嗨来自Bar! 3嗨来自Foo!
所以 - 代理允许将一个成员函数封装到一个对象中,给它一些预定义的调用参数(来自Foo的Hi),指定打开的参数(?),然后将它传递给其他可以调用它的对象后面。
由于c ++不允许在非静态成员函数上创建函数指针,因此在c ++中实现易于使用的东西似乎并不容易。我在c ++中找到了一些关于面向对象回调的谷歌的文章,但是,实际上我正在寻找一些我可以导入的库或头文件,它允许我使用一些类似优雅的语法。
任何人都有一些提示给我?
谢谢!
答案 0 :(得分: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();
}
答案 1 :(得分: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; }
};
再次继承。也就是说,你的根类是抽象的,用户继承它并定义回调,而不是具有一个具体的类和专用的回调对象。
class Foo {
virtual void MyCallback(...) = 0;
...
};
class RealFoo : Foo {
virtual void MyCallback(...) { ... }
};
更多的继承 - 静态。这样,您可以使用模板来更改对象的行为。它类似于第二个选项,但在编译时而不是在运行时工作,这可能产生各种好处和缺点,具体取决于上下文。
template<typename T> class Foo {
void MyCallback(...) {
T::MyCallback(...);
}
};
class RealFoo : Foo<RealFoo> {
void MyCallback(...) {
...
}
};
您可以使用和使用成员函数指针或常规函数指针
class Foo {
void (*callback)(...);
void something(...) { callback(...); }
Foo& SetCallback( void(*newcallback)(...) ) { callback = newcallback; return *this; }
void (*)(...) GetCallback() { return callback; }
};
有功能对象 - 它们会重载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(...); }
};
正确的解决方案主要取决于具体情况。如果需要公开C风格的API,那么函数指针是唯一的方法(记住用户参数的void *)。如果需要在运行时改变(例如,在预编译库中公开代码),则不能在此处使用静态继承。
只是一个简单的说明:我提起了那些代码,因此它不会很完美(比如函数的访问修饰符等)并且可能会有一些错误。这是一个例子。
答案 2 :(得分:2)
C ++允许在成员对象上使用函数指针 有关详细信息,请参阅here 您也可以使用boost.signals或boost.signals2(如果您的程序是多线程的,则为depanding)。
答案 3 :(得分:1)
有各种各样的库可以让你这样做。查看boost :: function。
或者尝试自己的简单实现:
template <typename ClassType, typename Result>
class Functor
{
typedef typename Result (ClassType::*FunctionType)();
ClassType* obj;
FunctionType fn;
public:
Functor(ClassType& object, FunctionType method): obj(&object), fn(method) {}
Result Invoke()
{
return (*obj.*fn)();
}
Result operator()()
{
return Invoke();
}
};
用法:
class A
{
int value;
public:
A(int v): value(v) {}
int getValue() { return value; }
};
int main()
{
A a(2);
Functor<A, int> fn(a, &A::getValue);
cout << fn();
}
答案 4 :(得分:1)
加入仿函数的想法 - 在注册之前使用std :: tr1 :: function和boost :: bind构建参数。
答案 5 :(得分:0)
C ++有很多种可能性,这个问题通常是语法之一。
boost::bind
结合使用,以获得更有趣......语法(*)()
运算符的对象,例如void Functor::operator()(int a) const;
,因为它是一个有状态的对象,可能来自一个公共接口std::function
+ lambda函数在表达方面真的很棒。我很感激对lambda语法的评论;)
Foo foo;
std::function<void(std::string const&,int)> func =
[&foo](std::string const& s, int i) {
return foo.say(s,"Hi from Foo",i);
};
func("Hi from Bar", 2);
func("Hi from FooBar", 3);
当然,func
仅在foo
可行(范围问题)时才可行,您可以使用foo
复制[=foo]
来指示按值传递而不是通过参考