Полный пример с использованием Boost:: Signals for С++ Eventing
Мне известно об учебном пособии в boost.org, в котором говорится об этом:
Boost.org Signals Tutorial, но примеры не являются полными и несколько более упрощенными. Примеры там не показывают включенные файлы, а некоторые разделы кода немного расплывчаты.
Вот что мне нужно:
ClassA повышает количество событий/сигналов
ClassB подписывается на эти события (могут быть подписаны несколько классов)
В моем проекте у меня есть класс обработчика сообщений нижнего уровня, который вызывает события в бизнес-классе, который выполняет некоторую обработку этих сообщений и уведомляет пользовательский интерфейс (wxFrames). Мне нужно знать, как все это может быть подключено (какой порядок, кто звонит кому и т.д.).
Ответы
Ответ 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)
{
// ...
}
Ответ 3
Вы посмотрели boost/libs/signals/example?
Ответ 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;