2009-04-20 17 views
54

के लिए बूस्ट :: सिग्नल का उपयोग करके पूरा उदाहरण मुझे यह बताते हुए boost.org पर ट्यूटोरियल से अवगत है: Boost.org Signals Tutorial, लेकिन उदाहरण पूर्ण नहीं हैं और कुछ हद तक सरलीकृत हैं। उदाहरणों में फाइलें शामिल नहीं हैं और कोड के कुछ अनुभाग थोड़ा अस्पष्ट हैं।सीओ ++ इवेंटिंग

यहाँ मैं क्या जरूरत है:
ClassA कई घटनाओं/संकेतों
ClassB उन घटनाओं का सदस्य बनता (एकाधिक वर्गों सदस्य बन सकते हैं)

अपने प्रोजेक्ट में मैं एक निचले स्तर संदेश हैंडलर वर्ग है को जन्म देती है कि घटनाओं को एक बिजनेस क्लास में बढ़ाता है जो उन संदेशों की कुछ प्रसंस्करण करता है और यूआई (WxFrames) को सूचित करता है। मुझे यह जानने की ज़रूरत है कि ये सभी कैसे वायर्ड हो सकते हैं (कौन सा ऑर्डर, कौन कॉल करता है आदि)।

उत्तर

82

नीचे दिया गया कोड आपके द्वारा अनुरोधित किए गए कार्यों का एक न्यूनतम कार्य उदाहरण है। ClassA दो सिग्नल उत्सर्जित करता है; SigA कोई पैरामीटर भेजता है (और स्वीकार करता है), SigBint भेजता है। 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 

संक्षिप्तता मैं कुछ शॉर्टकट है कि आप सामान्य रूप से उत्पादन कोड में उपयोग नहीं होता लिया है के लिए (विशेष रूप से अभिगम नियंत्रण में ढीला है और आप चाहते सामान्य रूप से 'छिपाएं' कीथबी के उदाहरण में फ़ंक्शन के पीछे आपका सिग्नल पंजीकरण)।

ऐसा लगता है कि boost::signal में अधिकांश कठिनाई boost::bind का उपयोग करने के लिए उपयोग में लाई जा रही है।यह पहले थोड़ा सा दिमागी झुकाव है! एक जटिल काम उदाहरण के लिए आप भी bind इस्तेमाल कर सकते हैं के साथ ClassA::SigA ऊपर हुक करने ClassB::PrintInt भी SigA हालांकि करता नहीं एक int फेंकना:

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

आशा है कि मदद करता है!

+0

क्या फ़ंक्शन को अधिभारित करना संभव है, और यदि ऐसा है, तो क्या आप इसे जोड़ना चाहेंगे। s.t. आपके पास PrintNum (int) जैसा कुछ है; और प्रिंटनम (फ्लोट); – pyInTheSky

+0

@pyInTheSky फ़ंक्शन प्रकार का उपयोग करें (सटीक अवधि के बारे में सुनिश्चित नहीं है): '(शून्य (*) (int)) और PrintNum' – Qix

6

क्या आपने boost/libs/signals/example पर देखा था?

+0

धन्यवाद! ये उदाहरण थोड़ा बेहतर हैं, लेकिन यह एक बड़ा, अधिक यथार्थवादी उदाहरण होना अच्छा लगेगा। –

11

यहां हमारे कोडबेस से एक उदाहरण है। इसे सरलीकृत किया गया है, इसलिए मैं guarentee नहीं है कि यह संकलित होगा, लेकिन यह करीब होना चाहिए। Sublocation आपकी कक्षा ए है, और स्लॉट 1 आपकी कक्षा बी है। हमारे पास इस तरह के कई स्लॉट हैं, प्रत्येक जो सिग्नल के एक अलग सबसेट की सदस्यता लेता है। इस योजना का उपयोग करने के फायदे यह हैं कि सुब्बोकेशन किसी भी स्लॉट के बारे में कुछ भी नहीं जानता है, और स्लॉट को किसी भी विरासत पदानुक्रम का हिस्सा होने की आवश्यकता नहीं है, और केवल उन स्लॉट्स के लिए कार्यक्षमता लागू करने की आवश्यकता है जिनकी वे परवाह करते हैं। हम इसका उपयोग एक बहुत ही सरल इंटरफ़ेस के साथ हमारे सिस्टम में कस्टम कार्यक्षमता जोड़ने के लिए करते हैं।

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

अच्छा उदाहरण। हालांकि मैं तर्क दूंगा - काफी दृढ़ता से - संकेतों को * म्यूटेबल नहीं होना चाहिए और addSignalXXX को * नहीं होना चाहिए। वे सार्वजनिक इंटरफ़ेस का हिस्सा हैं और निश्चित रूप से उप-स्थानान्तरण के व्यवहार को बदलते हैं। – MattyT

+0

मुझे लगता है कि यह बिंदु बहस योग्य है। मैं समझ सकता हूं कि आप कहां से आ रहे हैं। दूसरी तरफ, एक स्लॉट जोड़ना सीधे किसी भी उपनगरीय स्थिति को नहीं बदलता है। और यदि स्लॉट इसे कॉल करते समय राज्य बदलना चाहता है, तो उसे उपन्यास के गैर-सदस्यीय कार्यों को कॉल करना होगा। अगर इसे कोड समीक्षा में लाया गया था, तो मैं अपना मामला बताउंगा, लेकिन अगर आप सर्वसम्मति से सुझाव देते हैं तो वह बदलाव करने में कोई फर्क नहीं पड़ता। – KeithB

+1

मैं भी आपका तर्क देख सकता हूं ... यह शायद एक दिलचस्प कोड समीक्षा चर्चा होगी। :) – MattyT

1

क्यूटी की तरह बूस्ट सिग्नल और स्लॉट का अपना कार्यान्वयन प्रदान करता है। इसके कार्यान्वयन के कुछ उदाहरण निम्नलिखित हैं।

सिग्नल और नाम स्थान

के लिए स्लॉट कनेक्शन एक namespace GStreamer कहा जाता है पर विचार करें

namespace GStremer 
{ 
    void init() 
    { 
    .... 
    } 
} 
यहाँ

बना सकते हैं और गति प्रदान करने के लिए कैसे संकेत है

#include<boost/signal.hpp> 

... 

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

सिग्नल और एक कक्षा

के लिए स्लॉट कनेक्शन

मज़ा के साथ GSTAdaptor नामक कक्षा पर विचार करें ction हस्ताक्षर के बाद साथ 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 
0

जब नए बढ़ावा साथ MattyT के उदाहरण संकलन (उदा है 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;