使用Boost :: Signals for C++ Eventing的完整示例

Chr*_*ews 56 c++ boost-signals

我知道boost.org上的教程解决了这个问题: Boost.org Signals Tutorial,但这些例子并不完整,有些过于简化.那里的例子没有显示包含文件,代码的某些部分有点模糊.

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

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

Mat*_*tyT 86

下面的代码是您请求的最小工作示例. ClassA发出两个信号; SigA发送(并接受)没有参数,SigB发送一个int. ClassB有两个函数将cout在调用每个函数时输出.在该示例中,有一个ClassA(a)实例和两个ClassB(bb2)实例. 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);
}
Run Code Online (Sandbox Code Playgroud)

输出:

Foo
Bar: 4
Bar: 4

为了简洁起见,我采用了一些你通常不会在生产代码中使用的快捷方式(特别是访问控制是松散的,你通常'隐藏'你的信号注册背后的功能,如KeithB的例子).

似乎大多数困难在于boost::signal习惯使用boost::bind.这一个有点令人费解的第一!对于一个更为复杂的例子,你也可以使用bind挂钩ClassA::SigAClassB::PrintInt即使SigA没有没有发出int:

a.SigA.connect(bind(&ClassB::PrintInt, &b, 10));
Run Code Online (Sandbox Code Playgroud)

希望有所帮助!


Kei*_*thB 11

以下是我们的代码库中的示例.它被简化了,所以我不保证它会编译,但它应该是接近的.Sublocation是你的A类,Slot1是你的B类.我们有很多这样的插槽,每个插槽都订阅不同的信号子集.使用这种方案的好处是Sublocation不知道任何槽的任何内容,并且槽不需要是任何继承层次结构的一部分,并且只需要为它们关心的槽实现功能.我们使用它通过非常简单的界面将自定义功能添加到我们的系统中.

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;
};
Run Code Online (Sandbox Code Playgroud)

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);
  // ...
}
Run Code Online (Sandbox Code Playgroud)

Slot1.h

class Slot1
{
public:
  Slot1(const Sublocation& subloc);

  void onContact(Time t1, Time t2);
  void onEndOfSim();
private:
  const Sublocation& fSubloc;
};
Run Code Online (Sandbox Code Playgroud)

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)
{
  // ...
}
Run Code Online (Sandbox Code Playgroud)