2012-04-05 12 views
12

मैं एक सार-बेस-क्लास बना रहा हूं और सोच रहा था कि मैं शुद्ध वर्चुअल सिग्नल चाहता हूं। लेकिन जब मैं मैं शुद्ध आभासी संकेत मैं परिभाषित किया है के लिए एक चेतावनी प्राप्त संकलित:क्या यह C++/Qt में शुद्ध वर्चुअल सिग्नल को परिभाषित करने के लिए मान्य है?

../FILE1.h:27: Warning: Signals cannot be declared virtual 
../FILE1.h:28: Warning: Signals cannot be declared virtual 

यह सी ++/क्यूटी में एक शुद्ध आभासी संकेत परिभाषित करने के लिए मान्य है? क्या यह वर्चुअल सिग्नल को परिभाषित करने के लिए मान्य है?

Qt's signal and slot documentation page कहता है कि आप वर्चुअल स्लॉट को परिभाषित कर सकते हैं लेकिन सिग्नल के बारे में बात नहीं करते हैं। मुझे शुद्ध वर्चुअल सिग्नल पर अच्छी जानकारी नहीं मिल रही है।

+0

[एक असंबंधित नोट पर Qt शुद्ध आभासी स्लॉट की अनुमति देता है ... लेकिन शुद्ध आभासी संकेतों के बारे में कोई उल्लेख नहीं है।] (Http://stackoverflow.com/questions/2998216/does-qt-support-virtual-pure-slots) –

+1

आपको क्यों लगता है कि आप सिग्नल वर्चुअल बनाना चाहते हैं? – Chris

+0

सीआरटीपी और जेनेरिक बेस क्लास का उपयोग करते हुए एक अलग दृष्टिकोण दिया गया है [इस जवाब में] (http://stackoverflow.com/a/32124726/1329652)। यह कई 'QObject' व्युत्पन्न कक्षाओं के लिए सामान्य कोड से बाहर फैक्टरिंग की अनुमति देता है, भले ही वे विभिन्न आधार वर्गों से प्राप्त होते हैं (उन्हें सीधे' QObject' से प्राप्त करने की आवश्यकता नहीं है)। –

उत्तर

7
  • सिग्नल में कभी भी कार्यान्वयन नहीं होता है [1] (यानी आप अपनी .h फ़ाइल में सिग्नल को परिभाषित करते हैं और फिर .cpp में कोई कार्यान्वयन नहीं होता है)।
  • फ़ंक्शन शुद्ध वर्चुअल घोषित करने का मुख्य उद्देश्य विरासत वर्ग को कार्यान्वयन प्रदान करने के लिए मजबूर करना है।

उपरोक्त दो यहाँ बयानों को देखते हुए मेरी सोच है:

सिग्नल एक कार्यान्वयन नहीं है, लेकिन यह शुद्ध आभासी इनहेरीट वर्ग की आवश्यकता होगी एक कार्यान्वयन प्रदान करने के लिए की घोषणा ... जो सीधे "संकेत डॉन के साथ संघर्ष एक कार्यान्वयन नहीं है "। ऐसा लगता है कि किसी को दो स्थानों पर एक बार में रहने के लिए यह संभव नहीं है।

तो निष्कर्ष में ऐसा लगता है कि "शुद्ध वर्चुअल" "सिग्नल" घोषित करना एक त्रुटि होना चाहिए और इस प्रकार मान्य नहीं होना चाहिए।

जब एक समारोह की घोषणा केवल "आभासी" यह अभी भी चेतावनी देता है:


एक सार आधार वर्ग यहाँ के मामले में मैं क्या सोचता सही है। किसी भी चेतावनी से बचने के लिए मुझे लगता है कि समाधान किसी भी "वर्चुअल" या "शुद्ध वर्चुअल" के साथ सिग्नल को अर्हता प्राप्त नहीं करना है और फिर विरासत वर्ग किसी भी सिग्नल की घोषणा नहीं करेगा लेकिन बेस क्लास में परिभाषित संकेतों को अभी भी उत्सर्जित कर सकता है।

[1] जब मैं कहता हूं कि "सिग्नल में कभी भी कार्यान्वयन नहीं होता है" मेरा मतलब है कि कक्षा को लागू करने वाला व्यक्ति कार्यान्वयन प्रदान नहीं करता है। मैं समझता हूं कि दृश्य के पीछे क्यूटी के moc moc_FILE1.cpp में कार्यान्वयन प्रदान करता है।

2

मुझे लगता है कि (शुद्ध) वर्चुअल सिग्नल होने में बस कोई बात नहीं है। signals क्यूटी को प्रदान किया गया मैक्रो बस protected तक फैलता है, इसलिए आपके द्वारा घोषित किए जा रहे सभी सिग्नल वास्तव में संरक्षित तरीकों की घोषणाएं हैं। moc द्वारा उत्पन्न कोड उन कार्यों के कार्यान्वयन प्रदान करेगा।

0

शुद्ध वर्चुअल फ़ंक्शन बनाने का एक समाधान है जो दिए गए स्लॉट को सिग्नल या इसके विपरीत से कनेक्ट करेगा। उदा .:

class IBaseInterface 
{ 
    public: 
    virtual bool connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const = 0; 
}; 

class CDerived : public QObject, public IBaseInterface 
{ 
    Q_OBJECT 
    public: 
    virtual bool connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const; 
    signals: 
    void signal1(const QString& msg); 
}; 

bool CDerived::connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const 
{ 
if(bConnect) 
    return connect(this, SIGNAL(signal1(QString)), pReciever, pszSlot); 
return disconnect(this, SIGNAL(signal1(QString)), pReciever, pszSlot); 
} 

आगे ग्राहकों कोड में टाइप कर सकते हैं:

class CSomeClass : public QObject 
{ 
    Q_OBJECT 
protected /*or public, or private*/ slots: 
    void someSlot(const QString& msg); 
}; 
void CSomeClass::somefunction() 
{ 
    IBaseInterface* p = new CDerived; 
    if (!p->connectToSignal1(this, SLOT(someSlot(QString)), true)) 
    QMessageBox::warning(this, tr("Warning"), tr("Cannot connect ...."), QMessageBox::Ok); 
} 
+0

[यह] (http://stackoverflow.com/a/18113601/1329652) हालांकि, एक बेहतर समाधान है। –

4

चेतावनी बताया जाता है MOC द्वारा, सी ++ संकलक द्वारा नहीं, और यह सार इंटरफेस के विशिष्ट मामले को छोड़कर मान्य है।

वर्चुअल सिग्नल के लिए एकमात्र वैध उपयोग तब होता है जब QObject से detailed in this excellent answer से प्राप्त अमूर्त इंटरफेस को घोषित नहीं किया जाता है। उस दृष्टिकोण के साथ कुछ भी गलत नहीं है। मोक सहायक होने की कोशिश करता है, क्योंकि ज्यादातर मामलों में वर्चुअल सिग्नल एक गलती है।

फिर भी, के लिए सरल कामकाज चेतावनी प्राप्त करने के लिए इंटरफेस में signals: कीवर्ड को छोड़ना है। यह पूरी तरह से अनावश्यक है, के बाद से इंटरफ़ेस QObject से निकाले जाते हैं नहीं है और इस तरह बिल्कुल MOC द्वारा नहीं कार्रवाई की जानी चाहिए:

// https://github.com/KubaO/stackoverflown/tree/master/questions/virtual-slot-10029130 
#include <QtCore> 

class IDogInterface { 
public: 
    // no signals: section since it's not a QObject! 
    virtual void barks() = 0; // a signal 
}; 

class ADog : public QObject, public IDogInterface { 
    Q_OBJECT 
public: 
    Q_SIGNAL void barks() override; // implementation is generated by moc 
}; 

class Monitor : public QObject { 
    Q_OBJECT 
    int m_count{}; 
    Q_SLOT void onBark() { m_count++; } 
public: 
    int count() const { return m_count; } 
    void monitorBarks(IDogInterface * dog) { 
     QObject * dogObject = dynamic_cast<QObject*>(dog); 
     if (dogObject) { 
     connect(dogObject, SIGNAL(barks()), SLOT(onBark())); 
     } else { 
     qWarning() << "cannot monitor barking on dog instance" << (void*)dog; 
     } 
    } 
}; 

int main() { 
    ADog dog; 
    Monitor monitor; 
    monitor.monitorBarks(&dog); 
    emit dog.barks(); 
    Q_ASSERT(monitor.count() == 1); 
} 
#include "main.moc" 
0

दो परिदृश्यों जहां एक आभासी संकेत समझ में आता है:

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

दोनों परिदृश्यों को अन्य कम-ओओपी तरीकों से भी संभाला जा सकता है।