使用Boost :: Signals进行C ++事件的完整示例

我知道在boost.org的教程,解决这个: Boost.org信号教程 ,但这些例子不完整,有些过于简化。 那里的例子没有显示包含文件,代码的一些部分有些模糊。

这是我需要的:
ClassA引发多个事件/信号
ClassB订阅这些事件(多个类可以订阅)

在我的项目中,我有一个较低级别的消息处理程序类,它将事件引发到对这些消息进行一些处理并通知UI(wxFrames)的业务类。 我需要知道这些所有可能如何连接(按什么顺序,谁称谁等)。

下面的代码是你所要求的一个最简单的例子。 ClassA发出两个信号; SigA发送(并接受)没有参数, SigB发送一个intClassB有两个函数,每个函数被调用时都会输出到cout 。 在这个例子中,有一个ClassAa )的实例和两个ClassBbb2 )。 main用于连接和发射信号。 值得注意的是, ClassAClassB知道对方(即它们不是编译时绑定的 )。

 #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::SigAClassB::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;