63

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

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

在我的项目中,我有一个较低级别的消息处理程序类,该类将事件引发到业务类,该业务类对这些消息进行一些处理并通知 UI (wxFrames)。我需要知道这些都是如何连接起来的(什么顺序,谁打电话给谁,等等)。

4

6 回答 6

94

下面的代码是您所要求的最小工作示例。 ClassA发出两个信号;SigA不发送(并接受)任何参数,SigB发送一个int. ClassB有两个函数将cout在调用每个函数时输出。在示例中,有一个ClassA( a) 的实例和两个ClassB(bb2) 的实例。 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. 一开始有点想不通!对于一个更棘手的示例,您也可以使用tobind hook up ClassA::SigAwithClassB::PrintInt即使SigA不发出:int

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

希望有帮助!

于 2009-04-21T00:55:30.340 回答
12

这是我们代码库中的一个示例。它被简化了,所以我不保证它会编译,但它应该很接近。Sublocation 是您的 A 类,而 Slot1 是您的 B 类。我们有许多这样的插槽,每个插槽都订阅不同的信号子集。使用这种方案的优点是 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;
};

子定位.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);
  // ...
}

插槽1.h

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

  void onContact(Time t1, Time t2);
  void onEndOfSim();
private:
  const Sublocation& fSubloc;
};

插槽1.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)
{
  // ...
}
于 2009-04-20T21:13:54.367 回答
6

你看过boost/libs/signals/example吗?

于 2009-04-20T14:17:20.983 回答
1

QT 之类的 Boost 提供了自己的信号和插槽实现。以下是其实现的一些示例。

命名空间的信号和插槽连接

考虑一个名为 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
于 2012-11-28T12:57:49.250 回答
1

当使用更新的 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;
于 2016-11-24T13:43:23.053 回答
0

以上答案与signal2相同的答案很好,应该重写:

#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);
}
于 2021-10-13T05:37:16.343 回答