webentwicklung-frage-antwort-db.com.de

Vollständiges Beispiel mit Boost :: Signals für C++ Eventing

Ich bin mir des Tutorials auf boost.org bewusst, das sich mit diesem Problem befasst: Boost.org Signals Tutorial , aber die Beispiele sind nicht vollständig und etwas zu stark vereinfacht. Die Beispiele dort zeigen nicht die Include-Dateien und einige Abschnitte des Codes sind etwas unbestimmt.

Hier ist was ich brauche:
ClassA löst mehrere Ereignisse/Signale aus
ClassB abonniert diese Ereignisse (es können mehrere Klassen abonniert werden) 

In meinem Projekt habe ich eine untergeordnete Message-Handler-Klasse, die Ereignisse für eine Business-Klasse auslöst, die diese Nachrichten verarbeitet und die Benutzeroberfläche (wxFrames) benachrichtigt. Ich muss wissen, wie diese alle verdrahtet werden könnten (in welcher Reihenfolge, wer ruft wer an, usw.).

55
Chris Andrews

Der folgende Code ist ein minimales Funktionsbeispiel für das, was Sie angefordert haben. ClassA gibt zwei Signale aus; SigA sendet (und akzeptiert) keine Parameter, SigB sendet eine int. ClassB hat zwei Funktionen, die beim Aufruf jeder Funktion an cout ausgegeben werden. Im Beispiel gibt es eine Instanz von ClassA (a) und zwei von ClassB (b und b2). main dient zum Anschließen und Auslösen der Signale. Es ist erwähnenswert, dass ClassA und ClassB nichts voneinander wissen (dh sie sind nicht Kompilierzeitgebunden).

#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);
}

Die Ausgabe:

 Foo
Bar: 4
Bar: 4 

Der Kürze halber habe ich einige Abkürzungen genommen, die Sie normalerweise nicht im Produktionscode verwenden würden (insbesondere ist die Zugriffskontrolle lax und Sie würden Ihre Signalregistrierung normalerweise hinter einer Funktion wie in KeithBs Beispiel "verstecken"). 

Es scheint, dass der größte Teil der Schwierigkeit in boost::signal darin besteht, sich an boost::bind zu gewöhnen. Es is zuerst etwas geistesabwesend! Für ein schwierigeres Beispiel könnten Sie auch bind verwenden, um ClassA::SigA mit ClassB::PrintInt zu verbinden, auch wenn SigAnicht eine int ausgeben soll:

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

Hoffentlich hilft das!

85
MattyT

Hier ist ein Beispiel aus unserer Codebase. Es wurde vereinfacht, daher kann ich nicht garantieren, dass es kompiliert wird, aber es sollte nahe sein. Sublocation ist Ihre Klasse A und Slot1 ist Ihre Klasse B. Wir haben eine Reihe von Slots wie diese, von denen jeder eine andere Teilmenge von Signalen abonniert. Die Vorteile bei der Verwendung dieses Schemas bestehen darin, dass Sublocation über keine der Slots etwas weiß und dass die Slots nicht Teil einer Vererbungshierarchie sein müssen und nur eine Funktionalität für die Slots benötigen, die sie interessieren. Wir verwenden dies, um unserem System mit einer sehr einfachen Schnittstelle benutzerdefinierte Funktionen hinzuzufügen.

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

Hast du dir boost/libs/signals/example angesehen?

6
Éric Malenfant

Boost like QT bietet eine eigene Implementierung von Signalen und Slots. Nachfolgend einige Beispiele für die Implementierung.

Signal- und Slot-Verbindung für Namespace

Betrachten Sie einen Namespace namens GStreamer

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

So erstellen Sie das Signal und lösen es aus

 #include<boost/signal.hpp>

 ...

 boost::signal<void ()> sigInit;
 sigInit.connect(GStreamer::init);
 sigInit(); //trigger the signal

Signal- und Steckplatzverbindung für eine Klasse

Betrachten Sie eine Klasse namens GSTAdaptor mit der Funktion func1 und func2 mit nachfolgender Signatur

void GSTAdaptor::func1()
 {
 ...
 }

 void GSTAdaptor::func2(int x)
 {
 ...
 }

So erstellen Sie das Signal und lösen es aus

#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
1
Vihaan Verma

Wenn Sie das Beispiel von MattyT mit einem neueren Boost (zB 1.61) kompilieren, wird eine Warnung ausgegeben 

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." 

Sie definieren also entweder BOOST_SIGNALS_NO_DEPRECATION_WARNING, um die Warnung zu unterdrücken, oder Sie können leicht zu boost.signal2 wechseln, indem Sie das Beispiel entsprechend ändern:

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

using namespace boost::signals2;
using namespace std;
0
psalong