Подтвердить что ты не робот

Полный пример с использованием Boost:: Signals for С++ Eventing

Мне известно об учебном пособии в boost.org, в котором говорится об этом: Boost.org Signals Tutorial, но примеры не являются полными и несколько более упрощенными. Примеры там не показывают включенные файлы, а некоторые разделы кода немного расплывчаты.

Вот что мне нужно:
ClassA повышает количество событий/сигналов
ClassB подписывается на эти события (могут быть подписаны несколько классов)

В моем проекте у меня есть класс обработчика сообщений нижнего уровня, который вызывает события в бизнес-классе, который выполняет некоторую обработку этих сообщений и уведомляет пользовательский интерфейс (wxFrames). Мне нужно знать, как все это может быть подключено (какой порядок, кто звонит кому и т.д.).

4b9b3361

Ответ 1

Ниже приведенный ниже минимальный рабочий пример того, что вы запросили. 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);
}

Выход:

Foo
Bar: 4
Bar: 4

Для краткости я сделал несколько ярлыков, которые вы обычно не использовали в производственном коде (в частности, управление доступом является слабым, и вы обычно "спрятали" регистрацию вашего сигнала за функцией, подобной примеру KeithB).

Похоже, что большая часть сложности в boost::signal используется при использовании boost::bind. Сначала он немного сгибается! Для более сложного примера вы также можете использовать bind для подключения ClassA::SigA с помощью ClassB::PrintInt, хотя SigA не выделяет int:

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

Надеюсь, что это поможет!

Ответ 2

Вот пример из нашей кодовой базы. Он был упрощен, поэтому я не гарантирую, что он скомпилируется, но он должен быть близок. 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)
{
  // ...
}

Ответ 4

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

Ответ 5

При компиляции примера MattyT с более новым повышением (f.e. 1.61), он дает предупреждение

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;