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

eanckbw9  于 2022-12-27  发布在  其他
关注(0)|答案(6)|浏览(177)

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

我需要的是

A类引发多个事件/信号
ClassB订阅这些事件(可以订阅多个类)
在我的项目中,我有一个较低级别的消息处理程序类,它将事件提升到一个业务类,后者对这些消息进行一些处理并通知UI(wxFrames)。我需要知道所有这些是如何连接起来的(什么顺序,谁调用谁,等等)。

h79rfbju

h79rfbju1#

下面的代码是您所请求的内容的最小工作示例。ClassA发出两个信号; SigA发送(并接受)无参数,SigB发送一个intClassB有两个函数,调用每个函数时输出到cout。示例中有一个ClassA示例(a)和两个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);
}

输出:

Foo
Bar: 4
Bar: 4

为了简洁起见,我使用了一些通常不会在生产代码中使用的快捷方式(特别是访问控制很松,通常会将信号注册"隐藏"在一个函数后面,如KeithB的示例)。
看起来boost::signal的大部分困难在于习惯使用boost::bind。一开始它 * 是 * 有点令人费解!对于一个更棘手的例子,你也可以使用bind来连接ClassA::SigAClassB::PrintInt,即使SigA * 不 * 发出int

a.SigA.connect(bind(&ClassB::PrintInt, &b, 10));

希望能有所帮助!

1mrurvl1

1mrurvl12#

这是我们代码库中的一个例子。它被简化了,所以我不保证它能编译,但是它应该是接近的。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;
};

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)
{
  // ...
}
q9rjltbz

q9rjltbz4#

当使用较新的boost(例如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;
oo7oh9g9

oo7oh9g95#

Boost像QT一样提供了自己的信号和插槽实现。下面是一些实现的例子。
命名空间的信号和插槽连接
考虑名为GStreamer的名称空间

namespace GStremer
 {
  void init()
  {
  ....
  }
 }

下面介绍如何创建和触发信号

#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)
 {
 ...
 }

下面介绍如何创建和触发信号

#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
eqzww0vc

eqzww0vc6#

以上答案与信号2相同,应改写:

#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include <iostream>

using namespace boost;
using namespace std;

struct ClassA
{
    signals2::signal<void ()>    SigA;
    signals2::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);
}

相关问题