2015-12-12 10 views
7

न्यूबी से सी ++ यहां। मैं A Deeper Look at Signals and Slots पढ़ रहा था, जो दावा करता है कि 1) कॉलबैक स्वाभाविक रूप से टाइप-असुरक्षित हैं, और 2) उन्हें सुरक्षित बनाने के लिए आपको अपने फ़ंक्शन के चारों ओर शुद्ध वर्चुअल क्लास रैपर को परिभाषित करने की आवश्यकता है। मुझे समझ में मुश्किल हो रही है कि यह सच क्यों है। उदाहरण के लिए, यहाँ कोड क्यूटी पर प्रदान करता है उनके tutorial page for signals and slots:सादे पुराने कॉलबैक से सिग्नल और स्लॉट बेहतर क्यों हैं?

#include <functional> 
#include <vector> 

class Counter 
{ 
public: 
    Counter() { m_value = 0; } 

    int value() const { return m_value; } 
    std::vector<std::function<void(int)>> valueChanged; 

    void setValue(int value); 

private: 
    int m_value; 
}; 

void Counter::setValue(int value) 
{ 
    if (value != m_value) { 
     m_value = value; 
     for (auto func : valueChanged) { 
      func(value); 
     } 
    } 
} 

// Later on... 
Counter a, b; 
auto lambda = [&](int value) { b.setValue(value); }; 
a.valueChanged.push_back(lambda); 

a.setValue(12); 
b.setValue(48); 

आप देख सकते हैं, कॉलबैक संस्करण टाइप-सुरक्षित और कम है:

// Header file 
#include <QObject> 

class Counter : public QObject 
{ 
    Q_OBJECT 

public: 
    Counter() { m_value = 0; } 

    int value() const { return m_value; } 

public slots: 
    void setValue(int value); 

signals: 
    void valueChanged(int newValue); 

private: 
    int m_value; 
}; 

// .cpp file 
void Counter::setValue(int value) 
{ 
    if (value != m_value) { 
     m_value = value; 
     emit valueChanged(value); 
    } 
} 

// Later on... 
Counter a, b; 
QObject::connect(&a, SIGNAL(valueChanged(int)), 
       &b, SLOT(setValue(int))); 

a.setValue(12);  // a.value() == 12, b.value() == 12 
b.setValue(48);  // a.value() == 12, b.value() == 48 

यहाँ कि कोड कॉलबैक का उपयोग करके फिर से लिखा है क्यूटी संस्करण की तुलना में, despite them claiming that it's not। यह Counter से अलग किसी भी नए वर्ग को परिभाषित नहीं करता है। यह केवल मानक लाइब्रेरी कोड का उपयोग करता है और काम करने के लिए एक विशेष कंपाइलर (moc) की आवश्यकता नहीं है। फिर, कॉलबैक पर सिग्नल और स्लॉट पसंदीदा क्यों हैं? क्या सी ++ 11 ने इन अवधारणाओं को आसानी से अप्रचलित कर दिया है?

धन्यवाद।

+3

क्यूटी सी ++ 11 से बहुत पुराना है। क्यूटी दस्तावेज, श्वेतपत्र आदि में दावों को सी ++ 11 मानक के पहले "सी ++ के लिए बेहतर सी" के दावों के रूप में पढ़ा जाना चाहिए। विशेष रूप से मूर्खतापूर्ण दावों जैसे "कॉलबैक में दो मौलिक त्रुटियां होती हैं: सबसे पहले, वे टाइप-सुरक्षित नहीं होते हैं।" सी ++ के रूप में सी ++ के लिए बस कोई समझ न करें: इसे समझने के लिए शुद्ध सी प्रोग्रामिंग के संदर्भ में किसी को सोचना चाहिए। –

+2

अवधारणाओं और "स्लॉट्स" अवधारणा के साथ "संकेतों और स्लॉट्स के क्यूटी के कार्यान्वयन" को स्वीकार न करें। जब कॉलबैक की सूची के रूप में कुछ बनाए रखा जाता है और जब कोई ईवेंट होता है तो उन्हें कॉल करता है। आपके पास सिग्नल और स्लॉट का सार है। बाकी सब कुछ चीनी, वाक्यविन्यास, और विपणन है। आपके पास जो कुछ है, वह सरल है, यदि सिग्नल और स्लॉट सिस्टम का कार्यान्वयन सरल है। – GManNickG

+0

@GManNickG फिर मेरे कार्यान्वयन और क्यूटी के बीच क्या अंतर है? –

उत्तर

4

सिग्नल और स्लॉट सादे पुराने कॉलबैक से बेहतर क्यों हैं?

क्योंकि संकेत अतिरिक्त सुविधाओं के शीर्ष पर और क्यूटी एपीआई के साथ गहराई से एकीकृत होने के कारण सादे पुराने कॉलबैक की तरह हैं। यह रॉकेट विज्ञान नहीं है - कॉलबैक + अतिरिक्त विशेषताएं + गहरे एकीकरण अकेले कॉलबैक से अधिक है। अंततः सी ++ कॉलबैक करने के लिए एक क्लीनर तरीका पेश कर सकता है, लेकिन यह क्यूटी संकेतों और स्लॉट्स को प्रतिस्थापित नहीं करता है, बहुत कम उन्हें अप्रचलित प्रस्तुत करता है।

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

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

और क्यूएमएल के मामले में, जो आजकल क्यूटी का प्राथमिक केंद्र है, आप अनिवार्य रूप से क्यूटी के संकेतों से फंस गए हैं। तो मुझे लगता है कि सिग्नल रहने के लिए यहां हैं।

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

6

दोनों के बीच एक बड़ा अंतर है: धागे।

पारंपरिक कॉलबैक हमेशा कॉलिंग थ्रेड के संदर्भ में बुलाया जाता है। सिग्नल और स्लॉट के साथ ऐसा नहीं है - जब तक थ्रेड एक ईवेंट लूप चला रहा हो (जैसा कि यह होगा यदि यह QThread है) स्लॉट किसी भी थ्रेड में हो सकता है।

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

संबंधित मुद्दे