OO में, एक आम तौर पर इंटरफेस के साथ कॉलबैक लागू करता है: (किसी न किसी उदाहरण)इंटरफेस या फ़ंक्शन ऑब्जेक्ट्स के साथ कॉलबैक?
class Message {}
class IMsgProcessor {
public:
virtual void handle_msg(const Message& msg) = 0;
}
class RequestMsgProcessor : public IMsgProcessor {
virtual void handle_msg(const Message& msg) {
// process request message
}
}
class CustomSocket {
public:
Socket(IMsgProcessor* p) : processor_(p) {}
void receive_message_from_network(const Message& msg) {
// processor_ does implement handle_msg. Otherwise a compile time error.
// So we've got a safe design.
processor_->handle_msg(msg);
}
private:
IMsgProcessor* processor_;
}
अब तक तो अच्छा। सी ++ 11 के साथ, ऐसा करने का एक और तरीका है कस्टमसॉकेट को केवल std :: function ऑब्जेक्ट का एक उदाहरण प्राप्त होता है। यह परवाह नहीं करता है, जहां यह लागू किया गया है या यहां तक कि वस्तु अगर एक गैर शून्य मान है:
1. क्या प्रदर्शन प्रभावों के बारे में:
class CustomSocket {
public:
Socket(std::function<void(const Message&)>&& f) : func_(std:forward(f)) {}
void receive_message_from_network(const Message& msg) {
// unfortunately we have to do this check for every msg.
// or maybe not ...
if(func_)
func_(msg);
}
private:
std::function<void(const Message&)> func_;
}
अब यहाँ सवाल कर रहे हैं? मैं अनुमान लगा रहा हूं कि एक वर्चुअल फ़ंक्शन कॉल फ़ंक्शन ऑब्जेक्ट को कॉल करने से तेज़ है लेकिन कितनी तेज़ है? मैं एक तेज संदेश प्रणाली को कार्यान्वित कर रहा हूं और मैं किसी भी अनावश्यक प्रदर्शन दंड से बचना चाहता हूं।
2. सॉफ्टवेयर इंजीनियरिंग प्रथाओं के संदर्भ में, मुझे कहना है कि मुझे दूसरा दृष्टिकोण बेहतर पसंद है। कम कोड, कम फ़ाइलें, कम अव्यवस्था: कोई इंटरफ़ेस वर्ग नहीं। अधिक लचीलापन: आप केवल कुछ फ़ंक्शन ऑब्जेक्ट्स सेट करके और दूसरों को शून्य छोड़कर इंटरफ़ेस का सबसेट लागू कर सकते हैं। या आप अलग-अलग वर्गों में या मुक्त कार्यों या दोनों के संयोजन (एक एकल उपclass के बजाय) में लागू इंटरफ़ेस के विभिन्न हिस्सों को प्राप्त कर सकते हैं। इसके अलावा, कस्टमसॉकेट किसी भी वर्ग द्वारा आईएमएसएसप्रोसेसर के उप-वर्गों का उपयोग नहीं किया जा सकता है। यह मेरी राय में शानदार लाभ है।
आप क्या कहते हैं? क्या आप इन तर्कों में कोई मौलिक दोष देखते हैं?
रूप में एक ही क्षमता है '// दुर्भाग्य से हम हर msg.' के लिए इस चेक करना है - एक ही बात इंटरफ़ेस कोड के लिए सच होना चाहिए। आप कभी भी जांच नहीं करते कि क्या आप एक नल पॉइंटर पास नहीं करते हैं ... – Xeo
प्रतिरूप के बारे में: आभासी func मूल रूप से एक टेबल लुकअप जोड़ता है, std :: फ़ंक्शन एक विशेष एडाप्टर को कॉल अग्रेषित करता है। यदि आपका फ़ंक्शन/विधि वर्चुअल नहीं है तो इसे तेज़ होने के लिए अनुकूलित किया जा सकता है। बेंचमार्क करना है। यदि आप टेम्पलेट तर्क के साथ 'std :: function' को प्रतिस्थापित करते हैं तो आप इसे वर्चुअल कॉल से तेज़ी से बना सकते हैं। – Antoine
@Xeo जरूरी नहीं: इंटरफ़ेस कोड में मैं केवल कन्स्ट्रक्टर में जांच करूंगा कि पास ऑब्जेक्ट न्यूल नहीं है - एक पूर्ण स्वीकार करने से कोई अर्थ नहीं होता है। लेकिन दूसरे मामले में क्योंकि आप इंटरफ़ेस का आंशिक कार्यान्वयन कर सकते हैं (यानी, केवल कुछ फ़ंक्शन ऑब्जेक्ट्स नॉन-नल) आपको चेक की आवश्यकता है। – PoP