使用Boost :: Signals进行C ++事件的完整示例
我知道在boost.org的教程,解决这个: Boost.org信号教程 ,但这些例子不完整,有些过于简化。 那里的例子没有显示包含文件,代码的一些部分有些模糊。
这是我需要的:
ClassA引发多个事件/信号
ClassB订阅这些事件(多个类可以订阅)
在我的项目中,我有一个较低级别的消息处理程序类,它将事件引发到对这些消息进行一些处理并通知UI(wxFrames)的业务类。 我需要知道这些所有可能如何连接(按什么顺序,谁称谁等)。
下面的代码是你所要求的一个最简单的例子。 ClassA
发出两个信号; SigA
发送(并接受)没有参数, SigB
发送一个int
。 ClassB
有两个函数,每个函数被调用时都会输出到cout
。 在这个例子中,有一个ClassA
( a
)的实例和两个ClassB
( b
和b2
)。 main
用于连接和发射信号。 值得注意的是, ClassA
和ClassB
知道对方(即它们不是编译时绑定的 )。
#include <boost/signal.hpp> #include <boost/bind.hpp> #include <iostream> using namespace boost; using namespace std; struct ClassA { signal<void ()> SigA; signal<void (int)> SigB; }; struct ClassB { void PrintFoo() { cout << "Foo" << endl; } void PrintInt(int i) { cout << "Bar: " << i << endl; } }; int main() { ClassA a; ClassB b, b2; a.SigA.connect(bind(&ClassB::PrintFoo, &b)); a.SigB.connect(bind(&ClassB::PrintInt, &b, _1)); a.SigB.connect(bind(&ClassB::PrintInt, &b2, _1)); a.SigA(); a.SigB(4); }
输出:
富 酒吧:4 酒吧:4
为了简洁起见,我已经采取了一些在生产代码中通常不会使用的快捷方式(特别是访问控制不严格,并且通常在KeithB的例子中隐藏信号注册后面的函数)。
看来,在boost::signal
大部分困难是在习惯于使用boost::bind
。 起初有一点点心灵弯曲! 对于一个棘手的例子,你也可以使用bind
来将ClassA::SigA
与ClassB::PrintInt
即使SigA
不发射int
:
a.SigA.connect(bind(&ClassB::PrintInt, &b, 10));
希望有所帮助!
这里是我们的代码库的一个例子。 它被简化了,所以我不保证它会编译,但应该是接近的。 Sublocation是你的A类,Slot1是你的B类。我们有一些这样的插槽,每一个订阅不同的信号子集。 使用这种scheme的优点是:Sublocation不知道任何有关的槽位,槽位不需要是任何inheritance层次结构的一部分,只需要实现他们关心的槽位的function。 我们使用这个来添加自定义function到我们的系统中一个非常简单的界面。
Sublocation.h
class Sublocation { public: typedef boost::signal<void (Time, Time)> ContactSignal; typedef boost::signal<void ()> EndOfSimSignal; void endOfSim(); void addPerson(Time t, Interactor::Ptr i); Connection addSignalContact(const ContactSignal::slot_type& slot) const; Connection addSignalEndOfSim(const EndOfSimSignal::slot_type& slot) const; private: mutable ContactSignal fSigContact; mutable EndOfSimSignal fSigEndOfSim; };
Sublocation.C
void Sublocation::endOfSim() { fSigEndOfSim(); } Sublocation::Connection Sublocation::addSignalContact(const ContactSignal::slot_type& slot) const { return fSigContact.connect(slot); } Sublocation::Connection Sublocation::addSignalEndOfSim(const EndOfSimSignal::slot_type& slot) const { return fSigEndOfSim.connect(slot); } Sublocation::Sublocation() { Slot1* slot1 = new Slot1(*this); Slot2* slot2 = new Slot2(*this); } void Sublocation::addPerson(Time t, Interactor::Ptr i) { // compute t1 fSigOnContact(t, t1); // ... }
Slot1.h
class Slot1 { public: Slot1(const Sublocation& subloc); void onContact(Time t1, Time t2); void onEndOfSim(); private: const Sublocation& fSubloc; };
Slot1.C
Slot1::Slot1(const Sublocation& subloc) : fSubloc(subloc) { subloc.addSignalContact(boost::bind(&Slot1::onContact, this, _1, _2)); subloc.addSignalEndSim(boost::bind(&Slot1::onEndSim, this)); } void Slot1::onEndOfSim() { // ... } void Slot1::onContact(Time lastUpdate, Time t) { // ... }
你看看boost / libs / signals / example吗?
像QT这样的提升提供了自己的信号和插槽的实现。 以下是其实施的一些例子。
信号和插槽连接的命名空间
考虑一个名为GStreamer的名称空间
namespace GStremer { void init() { .... } }
这里是如何创build和触发信号
#include<boost/signal.hpp> ... boost::signal<void ()> sigInit; sigInit.connect(GStreamer::init); sigInit(); //trigger the signal
信号和插槽连接的类
考虑一个名为GSTAdaptor的类,函数称为func1和func2,并带有以下签名
void GSTAdaptor::func1() { ... } void GSTAdaptor::func2(int x) { ... }
这里是如何创build和触发信号
#include<boost/signal.hpp> #include<boost/bind.hpp> ... GSTAdaptor g; boost::signal<void ()> sigFunc1; boost::signal<void (int)> sigFunc2; sigFunc1.connect(boost::bind(&GSTAdaptor::func1, &g); sigFunc2.connect(boost::bind(&GSTAdaptor::func2, &g, _1)); sigFunc1();//trigger the signal sigFunc2(6);//trigger the signal
当用新的boost(fe 1.61)编译MattyT的例子时,它会发出警告
error: #warning "Boost.Signals is no longer being maintained and is now deprecated. Please switch to Boost.Signals2. To disable this warning message, define BOOST_SIGNALS_NO_DEPRECATION_WARNING."
因此,要么定义BOOST_SIGNALS_NO_DEPRECATION_WARNING来抑制警告,要么通过相应地更改示例来轻松切换到boost.signal2:
#include <boost/signals2.hpp> #include <boost/bind.hpp> #include <iostream> using namespace boost::signals2; using namespace std;