2012-04-02 21 views
6

मैं एक टाइपएफ़ ईवेंट बस को लागू करने की कोशिश कर रहा हूं। मैं EventBus::subscribe फ़ंक्शन के साथ फंस गया हूं क्योंकि यह मेरे ठोस ईवेंट हैंडलर को स्वीकार नहीं करता है। पहले के संस्करण में मेरे पास AbstractEventHandler केवल एक सारणी वर्ग के रूप में लागू किया गया था, बिना टेम्पलेट के। मुझे उस कार्यान्वयन में कोई समस्या नहीं थी। यही कारण है कि मुझे लगता है कि वास्तविक मुद्दा सार टेम्पलेट के साथ है।सी ++ फ़ंक्शन कंक्रीट कार्यान्वयन स्वीकार नहीं करता

नीचे दिया गया कोड मेरे कार्यान्वयन का एक अलग संस्करण है। पहला ब्लॉक घटना बस और इसके आवश्यक वर्गों के "कंकाल" से मिलता है जबकि दूसरा ब्लॉक घटना, घटना हैंडलर और मुख्य का वास्तविक कार्यान्वयन दिखाता है।

enum सभी अलग-अलग आयोजन उपलब्ध हैं। अमूर्त घटना वह आधार है जिसमें से सभी ठोस घटनाएं उत्पन्न होती हैं। इवेंट हैंडलर एक सारणी टेम्पलेट है जो टेम्पलेट क्लास के रूप में एक ईवेंट के साथ टाइप-सुरक्षा सुनिश्चित करता है। इवेंट बस सभी प्रकाशित कार्यक्रमों को अपने संबंधित हैंडलरों को वितरित करने के लिए ज़िम्मेदार है।

enum EVENT_TYPE 
{ 
    ON_EVENT_1, 
    ON_EVENT_2 
}; 

class AbstractEvent 
{ 
public: 
    AbstractEvent() {}; 
    virtual ~AbstractEvent() {}; 

    virtual EVENT_TYPE type() = 0; 
}; 

template<class T> 
class AbstractEventHandler 
{ 
public: 
    AbstractEventHandler() {}; 
    virtual ~AbstractEventHandler() {}; 

    virtual void on_event(T *event) = 0; 
}; 

class EventBus 
{ 
public: 
    EventBus() {}; 
    virtual ~EventBus() {}; 

    void subscribe(EVENT_TYPE type, 
        AbstractEventHandler<AbstractEvent> *eventHandler) { 
     // Add handler to vector for further use 
    } 

    void publish(AbstractEvent *event) { 
     // send event to each handler in respective vector 
    } 
}; 

नीचे मेरी ठोस घटना और ईवेंट हैंडलर और मुख्य()

class ConcreteEvent : public AbstractEvent 
{ 
public: 
    ConcreteEvent() {}; 
    virtual ~ConcreteEvent() {}; 

    EVENT_TYPE type() { 
     return ON_EVENT_1; 
    }; 
}; 

class ConcreteEventHandler : public AbstractEventHandler<ConcreteEvent> 
{ 
public: 
    ConcreteEventHandler() {} 
    virtual ~ConcreteEventHandler() {}; 

    void on_event(ConcreteEvent *event) { 
     // Do something 
    }; 
}; 

int main() 
{ 
    EventBus *eventBus = new EventBus(); 

    ConcreteEventHandler handler = ConcreteEventHandler(); 

    // This failes! 
    eventBus->subscribe(ON_EVENT_1, &handler); 
} 

एक त्रुटि कह

EventBus::subscribe(EVENT_TYPE, ConcreteEventHandler*) 

करने के लिए कॉल के लिए कोई मिलता-जुलता समारोह है कि वहाँ के साथ संकलक रिटर्न हैं और यह कि केवल उम्मीदवार

void EventBus::subscribe(EVENT_TYPE, AbstractEventHandler<AbstractEvent>*) 

मैं अपनी सार कक्षा के ठोस कार्यान्वयन को स्वीकार करने के लिए अपनी EventBus :: सदस्यता विधि कैसे कार्यान्वित कर सकता हूं?

अद्यतन: अपने संकेत के लिए

template<typename T> 
void subscribe(EVENT_TYPE type, AbstractEventHandler<T> *eventHandler) { 

} 

धन्यवाद, रोहन,: समाधान

मैं निम्नलिखित करने के लिए EventBus::subscribe की विधि विवरण बदल दिया गया है और अब अच्छी तरह से काम करता है! उन्होंने मुझे इस समाधान को खोजने में मदद की।

+0

+1। –

उत्तर

5

कारण है।

यह आश्चर्यजनक लग सकता है, लेकिन AbstractEventHandler<ConcreteEvent> की AbstractEventHandler<AbstractEvent> भी ConcreteEvent हालांकि AbstractEvent का एक उपवर्ग है एक उपवर्ग नहीं हो सकता।

कारण यह है कि, टेम्पलेट्स के साथ, टेम्पलेटिंग के रूप में आप चाहते हैं कि प्रकार की सुरक्षा की गारंटी नहीं है। आइए एक उदाहरण देखें। आइए बेस-क्लास Animal और उप-वर्ग Cat और Dog के मानक प्रतिमान पर जाएं।

std::list<Animals>* animals; 

और बिल्लियों की एक सूची: मान लीजिए कि हम पशु की एक सूची है चलो,

animals = &cats; 

कारण यह है कि:

std::list<Cat> cats; 

निम्नलिखित, एक वैध डाली नहीं है , अगर मैं ऐसा कर रहा हूं,

animals->add(new Dog("Ben")); 

I wo uld वास्तव में Cat एस की सूची में Dog जोड़ें। cats.last() यहां वास्तव में Dog लौटाएगा। इसलिए, इस मामले में, आप Cat एस की सूची में Dog अनिवार्य रूप से जोड़ रहे हैं। मैंने देखा है पर्याप्त लूनी ट्यून्स एपिसोड को पता है कि यह एक अच्छा विचार नहीं है: जैसा कि हम सभी जानते हैं कि एक Dog केवल bowbow() कर सकते हैं

cats.last().meow(); 

ऊपर निश्चित रूप से नहीं सच है, है।

संपादित

आपके प्रश्न का उत्तर के लिए, यहाँ मैं तुम क्या सुझाव है कि क्या है, ConcreteEventHandlerAbstractEventHandler<AbstractEvent> से प्राप्त करें, और कोड के भीतर, जहां भी आप ConcreteEvent का उपयोग करते हैं, dynamic_case का उपयोग AbstractEvent को ConcreteEvent पर डालने के लिए करें। यह रन-टाइम आत्मनिरीक्षण का उपयोग करेगा, जो प्रदर्शन को थोड़ा प्रभावित कर सकता है (मैंने गतिशील कलाकारों का उपयोग करने के विरोध में कुछ लोगों को भी देखा है), लेकिन आप डेटाटाइप का एक वैध अपवाद सफलतापूर्वक करने में सक्षम होंगे।

+0

ठीक है, सच है, लेकिन यह सवाल का जवाब नहीं देता है - मैं अपने सार वर्ग के ठोस कार्यान्वयन को स्वीकार करने के लिए अपनी EventBus :: सदस्यता विधि कैसे कार्यान्वित कर सकता हूं? –

+0

आपके त्वरित उत्तर के लिए धन्यवाद! मैं इस मुद्दे को बेहतर समझता हूं। समस्या यह है कि कंक्रीट हैंडलर को सही on_event() विधि को लागू करने के लिए मजबूर करने के लिए मुझे abstractEventHandler की आवश्यकता है। – Fabian

+1

क्या आप दोनों एक ही व्यक्ति की तरह हैं? –

-2

आपकी AbstractEventHandler<T> कक्षा AbstractEvent उत्तराधिकारी होनी चाहिए। यह शायद आपका इरादा था, आप बस इसे लिखना भूल गए थे। क्योंकि ConcreteEventHandlerAbstractEventHandler<ConcreteEvent> और नहीं AbstractEventHandler<AbstractEvent> का एक उपवर्ग है

template<class T> 
class AbstractEventHandler 
    :public AbstractEvent 
{ 
public: 
    AbstractEventHandler() {}; 
    virtual ~AbstractEventHandler() {}; 

    virtual void on_event(T *event) = 0; 
} 
+1

-1 सिर्फ गलत होने के लिए नहीं, बल्कि कोड को संकलित करने की कोशिश भी नहीं करने के लिए। –

+0

अर्थात्, एक घटनास्थल को कभी भी किसी ईवेंट का उत्तराधिकारी नहीं होना चाहिए। यह एक घटना नहीं है, यह उस घटना को संभालने वाला है। – stefaanv

1

रोहन ने पहले ही जवाब दिया है कि कोड संकलित क्यों नहीं होता है, हालांकि मैं एक और दृष्टिकोण सुझा सकता हूं।

आप इसे इस तरह कार्यान्वित कर सकते हैं कि इवेंटहैंडर सीधे EventGenerator पर सदस्यता लेता है। इस तरह घटना उत्पन्न करने और संभालने के बीच एक सीधा लिंक है।
इस कार्यक्रम को उसके जेनरेटर के संदर्भ में सब्सक्राइब किए गए हैंडलर तक पहुंचने के लिए एक संदर्भ रखना चाहिए और इवेंटबस घटना पर एक विधि को स्वयं को संभालने के लिए कॉल करता है।

इस तरह, इवेंटबस घटनाक्रमकों से अनजान है और आपको इवेंटटाइप एनम की भी आवश्यकता नहीं है।
हालांकि, आपको विभिन्न ईवेंट जेनरेटर की आवश्यकता है जिन्हें एक ईवेंटबस के विपरीत विभिन्न ईवेंटहैंडर्स द्वारा एक्सेस किया जाना आवश्यक है। प्रत्येक ईवेंटहैंडर केवल एक घटना को संभाल सकता है, इसलिए यदि अधिक घटनाओं की आवश्यकता होती है, तो ईवेंटहैंडर्स को एकत्रित किया जाना चाहिए (प्रतिनिधिमंडल या उत्तराधिकारी द्वारा)। एक अच्छी तरह से पूछे जाने वाले प्रश्न के लिए

+0

हूं आपके सुझाव के लिए धन्यवाद!मैं इस मार्ग के साथ दो कारणों से नहीं जाना चाहता: 1/ईवेंट बस एपीआई का हिस्सा है और मैं उन कार्यक्रमों को बेनकाब नहीं करना चाहता हूं जो घटनाएं उत्पन्न करते हैं। 2/जैसा कि प्रोजेक्ट बढ़ता है, मैं हैंडलर और ईवेंट जेनरेटर के बीच इंटरकनेक्शन के अनियंत्रित वेब में समाप्त होने का डर करता हूं। – Fabian

+0

पर्याप्त मेला, यह आपकी परियोजना है। लगभग 2 /, जोखिम को एक स्तरित दृष्टिकोण के साथ कम किया जाता है, जहां उच्च मॉड्यूल निम्न मॉड्यूल को जानते हैं और सब्सक्राइब कर सकते हैं और जहां ईवेंट केवल निम्न से उच्च मॉड्यूल में भेजे जाते हैं। – stefaanv

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