我希望能够像C ++一样使用Java的接口语义。起初,我使用boost::signal
来回调给定事件的显式注册成员函数。这非常有效。
但后来我决定一些函数回调池是相关的,抽象它们并立即注册所有实例的相关回调是有意义的。但我学到的是boost::bind
的特定性质和/或取this
的价值似乎使得这种突破。或者可能只是add_listener(X &x)
方法声明改变了boost::bind
生成的代码。
我非常粗略地理解为什么会出现这个问题,而且我认为它的设计可能正常运行。我很好奇:应该我做了什么?当然,有一种正确的方法可以做到这一点。
以下是一些示例代码:
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
using namespace std;
struct X;
struct Callback
{
virtual void add_listener(X &x) = 0;
};
struct X
{
X() {}
X(Callback &c) { c.add_listener(*this); }
virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; }
};
struct CallbackReal : public Callback
{
virtual void add_listener(X &x)
{
f = boost::bind<void>(boost::mem_fn(&X::go), x);
}
void go() { f(); }
boost::function<void (void)> f;
};
struct Y : public X
{
Y() {}
Y(Callback &c) { c.add_listener(*this); }
virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; }
};
int main(void)
{
CallbackReal c_x;
CallbackReal c_y;
X x(c_x);
Y y(c_y);
cout << "Should be 'X'" << endl;
boost::bind<void>(boost::mem_fn(&X::go), x)();
cout << "Should be 'Y'" << endl;
boost::bind<void>(boost::mem_fn(&X::go), y)();
cout << "------------------" << endl;
cout << "Should be 'X'" << endl;
c_x.go();
cout << "I wish it were 'Y'" << endl;
c_y.go();
return 0;
}
好的,我没有完全描述这个问题。这个标题具有误导性。
哦,伙计。请注意这个。我显然没有很好地描述这个问题,我认为这最终归结为语法错误。 :(
答案 0 :(得分:3)
boost::bind
按值获取参数并复制它们。这意味着
f = boost::bind<void>(boost::mem_fn(&X::go), x);
将传递x
的副本,它会切掉Y
段的Y
(如果它真的是boost::bind
开头)。要使虚拟调度工作,您需要将指针传递给f = boost::bind(&X::go, &x);
:
mem_fn
(请注意,您实际上不需要<void>
,或明确写boost::bind
,因为{{1}}和参数演绎会为您处理。{/ p>
答案 1 :(得分:0)
Java接口并不特别存在于C ++中。最接近的是纯抽象基类。这通常非常接近。
您的其余问题与接口无关。 Java使用Observer模式进行事件连接和调度。接口部分只是温和相关,因为观察者必须服从特定的接口(当然,否则你不知道该怎么叫)。
使用boost :: bind来创建仿函数实际上是接口之外的抽象,因此是一种更通用的解决方案。观察者模式和仿函数被组合成信号/插槽习语/模式,在各种库中实现,如boost :: signals,boost :: signals2和gtk ++。 Qt版本在力学方面有很大的不同,但在概念上却相似。
那么,这有什么意义可以帮助您了解什么,为什么以及在哪里?我建议先从Observer模式的搜索开始,然后尝试编写一些实现。