2009-04-20 24 views
54

Boost.org adresindeki öğreticinin şu adrese dikkatini çektim: Boost.org Signals Tutorial Örnekler tam ve biraz fazla basitleştirilmemiş. Buradaki örnekler içerme dosyalarını göstermez ve kodun bazı bölümleri biraz belirsizdir. İşte Boost :: Sign for for C++ Olayı'nı kullanarak tam örnek

ben gerekenler:
Sınıf A
ClassB bu olaylara abone birden fazla etkinlik/sinyalleri (Çoklu sınıflar abone olabilir) Projemde

Ben alt düzey ileti işleyicisi sınıf var yükseltir Olayları, bu iletilerin bazı işlemlerini yapan ve kullanıcı arabirimini (wxFrames) bildiren bir iş sınıfına taşır. Bunların nasıl kablolu hale getirilebileceğini bilmem gerekiyor (hangi düzen, kimin kim olduğunu, vb.).

cevap

82

Aşağıdaki kod, talep ettiğiniz şeylerin en az çalışan bir örneğidir. ClassA iki sinyal yayar; SigA parametresi göndermez (ve kabul etmez), SigB bir int gönderir. ClassB, her bir işlev çağrıldığında cout'a çıkacak iki işlevi vardır. Örnekte, ClassA (a) ve iki adet ClassB (b ve b2) örneği bulunmaktadır. main, sinyalleri bağlamak ve ateşlemek için kullanılır. ClassA ve ClassB'un birbirlerinden hiçbir şey bilmediğine dikkat etmek gerekir (yani derleme zamanı bağlı değil).

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

çıkışı: Ben normalde üretim kodunda kullanmak ister bazı kısayollar geçtiniz kısalık için

 
Foo 
Bar: 4 
Bar: 4 

(özellikle erişim kontrolü gevşek ve şimdi etsen normalde 'gizle' sinyal kaydı, KeithB'nin örneğinde olduğu gibi bir fonksiyonun arkasına kaydedilir).

boost::signal'daki zorluğun çoğu boost::bind'u kullanmaya alışkın görünüyor.Bu ilk başta biraz zihin bükme olduğunu! yardımcı olur

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

Hope: does değil bir int yayarlar ClassB::PrintInt bile SigA olsa yanıltıcıdır Örneğin ayrıca ClassA::SigA kanca bind kullanabilirsiniz!

+0

Bir işlevi aşırı yüklemek mümkün mü ve eğer öyleyse, bunu ekleyebilir misiniz? s.t. PrintNum (int) gibi bir şey var; ve PrintNum (şamandıra); – pyInTheSky

+0

@pyInTheSky Bir işlev türü kullanın (tam terimden emin değil): '(void (*) (int)) & PrintNum' – Qix

6

boost/libs/signals/example'a baktınız mı?

+0

Teşekkür! Bu örnekler biraz daha iyi, ama daha büyük, daha gerçekçi bir örneğe sahip olmak güzel olurdu. –

11

Burada kod tabanımızdan bir örnek var. Basitleştirildi, bu yüzden derleneceğini, ancak yakın olması gerektiğini garanti etmiyorum. Alt konum, A sınıfınız ve Slot1, B sınıfınızdır. Her biri farklı bir sinyal alt kümesine abone olan, bunun gibi bir dizi yuvaya sahibiz. Bu şemayı kullanmanın avantajları, Alt Yerleşimin herhangi bir yuva hakkında hiçbir şey bilmemesi ve yuvaların herhangi bir kalıtım hiyerarşisinin bir parçası olmaması ve yalnızca önem verdikleri yuvalar için uygulama işlevselliğine ihtiyaç duymalarıdır. Sistemimize özel bir işlevsellik eklemek için bunu çok basit bir arayüzle kullanıyoruz.

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

İyi örnek. Her ne kadar tartışmalı olsa da - oldukça güçlü bir şekilde - sinyallerin * değişmez olması ve addSignalXXX'in * yapının * olmaması gerekir. Genel arayüzün bir parçası ve kesinlikle SubLocation'ın davranışını değiştirirler. – MattyT

+0

Bu noktanın tartışmalı olduğunu düşünüyorum. Nereden geldiğini anlayabiliyorum. Diğer taraftan, bir yuva eklemek doğrudan herhangi bir alt konum durumunu değiştirmez. Ve eğer yuva arandığında durumu değiştirmek istiyorsa, alt konumun konsolide olmayan üye işlevlerini çağırmalıdır. Eğer bu bir kod incelemesinde gündeme getirilmişse, davamı belirtebilirim, ancak fikir birliği olsaydı önerdiğin değişikliği yapmazdım. – KeithB

+1

Argümanınızı da görebiliyorum ... muhtemelen ilginç bir kod inceleme tartışması olabilir. :) – MattyT

1

QT gibi sinyaller ve yuvaların kendi uygulamasını sağlar. Aşağıda uygulamanın bir örneği var.

Sinyal ve ad

için Yuvası bağlantısı Gstreamer adında bir ad düşünün

namespace GStremer 
{ 
    void init() 
    { 
    .... 
    } 
} 
İşte

sinyalini oluşturmak ve tetiklemek için nasıl

#include<boost/signal.hpp> 

... 

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

Sinyal ve Sınıf

için Yuvası bağlantısı

Eğlenerek GSTAdaptor adlı bir Sınıf düşünün ction İMZA aşağıdaki FUNC1 ve FUNC2 denilen

İşte
void GSTAdaptor::func1() 
{ 
... 
} 

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

sinyalini

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

yeni boost ile MattyT örneğini derlemek (F. E. oluşturmak ve tetiklemek için nasıl 1.61) o zaman uyarı bastırmak için BOOST_SIGNALS_NO_DEPRECATION_WARNING tanımlamak Yani ya bir uyarısını

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

verir veya kolayca buna göre örnek değiştirerek boost.signal2 geçiş olabilir:

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

using namespace boost::signals2; 
using namespace std;