2011-04-05 6 views
7

मैं हाल ही में मकसद से उत्साहित हो गया हूं और उन जगहों पर उनका उपयोग कर रहा हूं। तब स्थिति उत्पन्न हुई जहां मुझे दो अलग-अलग परिचालन करने के लिए अपने मज़ेदार की आवश्यकता थी और मैंने अपने मज़ेदार को एक और तरीका जोड़ने के बारे में सोचा ((ऑपरेटर ओवरलोडिंग नहीं)। चाहे यह बुरी आदत है या नहीं, मुझे यकीन नहीं है (शायद आप मुझे बता सकते हैं), लेकिन मुझे यह सोचने लगा कि मैं पहले स्थान पर क्यों नहीं हूं बल्कि न केवल वस्तुओं का उपयोग कर रहा हूं। तो मेरा सवाल है:नामित विधियों वाले ऑब्जेक्ट्स के लिए सी ++ फ़ैक्टर बेहतर क्यों हो सकते हैं?

क्या() ऑपरेटर को अधिभारित करने के बारे में कुछ खास है या क्या यह सामान्य नामित विधियों का उपयोग करने से बहुत ही सरल रूप से आकर्षक है?

अद्यतन:

सबसे पहले, मैं जानता हूँ कि क्यों functors संकेत के रूप में कार्य करने के लिए अन्य प्रश्न में विस्तार से बताया बेहतर हो सकता है। मैं जानना चाहता हूं कि क्यों वे नामित विधियों के साथ वस्तुओं के लिए बेहतर हो सकते हैं।

दूसरा, उदाहरण के लिए, जब मैं अपने मज़ेदार की एक अन्य संभवतः नामित विधि का उपयोग करना चाहता था: असल में मेरे पास दो कार्य हैं, जो एक ग्राफ विभाजन के मॉड्यूलरिटी नामक कुछ की गणना करता है - compute_modularity(), और दूसरा जो लाभ की गणना करता है compute_modularity_gain() विभाजन के कुछ परिवर्तन के बाद मॉड्यूलरिटी में। मैंने सोचा कि मैं एक ही फंक्शन के हिस्से के रूप में इन फ़ंक्शंस को एक ऑप्टिमाइज़ेशन एल्गोरिदम में पास कर सकता हूं, नामित फ़ंक्शन के रूप में लाभ के साथ। कारण मैं एल्गोरिदम में केवल दो म्यूटर्स को पास नहीं करता हूं, यह है कि मैं इसे लागू करना चाहता हूं कि compute_modularity_gain() केवल compute_modularity() के साथ संयोजन में उपयोग किया जाता है और अन्य फ़ैक्टर नहीं। compute_stability() (जो केवल compute_stability_gain() साथ किया जाना चाहिए। दूसरे शब्दों में, लाभ समारोह कसकर अपने भाई समारोह के साथ मिलकर किया जाना चाहिए। अगर वहाँ एक और तरीका है मैं इस बाधा लागू कर सकते हैं तो कृपया मुझे पता है।

+0

उस परिदृश्य का वर्णन करें जिससे आप एक और विधि जोड़ना चाहते हैं। –

+4

ऐसा लगता है कि यह शामिल किया गया है: [सी ++ फ़ैक्टर - और उनके उपयोग।] (Http://stackoverflow.com/q/356950/478288) – chrisaycock

+4

@chrisaycock: आपको केवल * सटीक * डुप्लिकेट को बंद करना चाहिए। यह प्रश्न समान है, लेकिन गुणात्मक रूप से अलग पहलू है: सामान्य नामित विधियों का उपयोग करके मज़ेदारों को क्यों लागू नहीं किया जा सकता है और वे केवल एक विधि को क्यों लागू कर सकते हैं? –

उत्तर

0

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

आप std :: function (या boost :: function में भी देखना चाहते हैं) कंपाइलर अभी तक इसका समर्थन नहीं करता है) जिसका उपयोग मिलान करने वाले कॉल हस्ताक्षर के साथ किसी भी प्रकार की ऑब्जेक्ट को अनुकूलित करने के लिए किया जा सकता है।

std :: बाइंड या बूस्ट :: बाइंड आपको फ़ंक्शन के पैरामीटर के साथ कंक्रीट तर्कों को जोड़ने देता है, यह एक मज़ेदार के निर्माता के माध्यम से उन्हें गुजरने के समान प्रभाव के लिए अनुमति देता है। आप इस सूचक को सदस्य कार्यों को प्रदान करने के लिए बाध्य का उपयोग भी कर सकते हैं ताकि उन्हें किसी ऑब्जेक्ट को स्पष्ट रूप से निर्दिष्ट किए बिना सादे मज़ेदार के रूप में भी कहा जा सके।

+0

"उनके प्रतिलिपि निर्माता के माध्यम से जानकारी इंजेक्शन भी हो सकती है" <- ठीक है, उनकी कॉपी कन्स्ट्रक्टर नहीं। बस सामान्य कन्स्ट्रक्टर। यह भी ध्यान रखें कि मज़ेदार [शुद्ध कार्य] होना चाहिए (http://en.wikipedia.org/wiki/Pure_function) - आपको एसटीएल मकानों में राज्य को स्टोर नहीं करना चाहिए क्योंकि एसटीएल को आपके मज़ेदार को मनमाने ढंग से कॉपी करने की अनुमति है और कई जितनी बार चाहें उतनी बार। –

+0

हां नहीं पता कि मैंने टाइपिंग कॉपी कन्स्ट्रक्टर को कैसे समाप्त किया, जबकि सामान्य कन्स्ट्रक्टर का अर्थ संपादित किया गया। ; ओ – xDD

1

एक मज़ेदार के पीछे मूल उद्देश्य कोड को डीक्यूपल करना है जो जानता है कि कोड से कुछ प्रकार का काम कैसे करना है, जो जानता है कि उस काम को कब करना है (क्लासिक उदाहरण यूआई बटन के साथ एक मजेदार को जोड़ रहा है)।

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

एक यूनरी इंटरफ़ेस का मुख्य लाभ यह है कि यह निर्माता और उपभोक्ताओं के उपभोक्ताओं के लिए लिंगुआ फ़्रैंका के रूप में कार्य करता है। आप कह सकते हैं, मज़दूरों को परिभाषित करने के लिए सभी को invoke() सदस्य फ़ंक्शन है, लेकिन फिर कुछ अन्य भीड़ do() पर मानकीकृत करने का निर्णय लेगी, और फिर भी कोई अन्य call() पर जा सकता है।और इन सभी समाधानों में अधिक टाइपिंग शामिल है।

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

एक decoupled उदाहरण एक हैश तालिका है जिसे समानता-तुलनित्र और हैश फ़ंक्शन की आवश्यकता होती है। इस मामले में, दो कार्य असंबद्ध हो सकते हैं: वर्ग के operator==() समानता के लिए लपेटें और हैश की गणना करने के लिए एक नि: शुल्क फ़ंक्शन लपेटें।

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

अंत में, एक functor में लपेटकर मौजूदा कार्यक्षमता अच्छी तरह से समझा जाता है और व्यापक रूप से, इस तरह के boost.bind के रूप में पुस्तकालयों द्वारा समर्थित फेंक-दूर कक्षाएं कि लागू बनाने जबकि doX() और doY() नहीं है। इसके अलावा, नया मानक लैम्बडास जोड़ता है, जो नाटकीय रूप से मज़दूरों के निर्माण को सरल बनाता है।

7

operator() के अधिभार का कारण फ़ंक्शन पॉइंटर्स के रूप में फ़ैक्टर के समान कॉल अर्थशास्त्र बनाना है - और वास्तव में यदि आप चाहें तो फ़ंक्शन पॉइंटर्स का उपयोग कर सकते हैं।

फ़ंक्शन का उपयोग करने के बजाय operator() ओवरलोड करने के कुछ कारण हैं - लेकिन सबसे महत्वपूर्ण बात यह है कि फ़ंक्शंस फ़ंक्शन पॉइंटर का उपयोग करते समय अप्रत्यक्ष फ़ंक्शन कॉल को शायद ही कभी ऑप्टिमाइज़ कर देगा, लेकिन वे लगभग हमेशा ऑप्टिमाइज़ करेंगे operator() कॉल - यही कारण है कि std::sort आमतौर पर std::qsort धड़कता है।

इसके लिए जटिल कारणों का पूरा समूह है लेकिन यह वास्तव में उबालता है कि अधिकांश (नहीं?) कंपाइलर फ़ंक्शन पॉइंटर कॉल को हटाने के अनुकूलन को लागू करते हैं, जो कि आधुनिक हार्डवेयर पर महंगा है।

तो स्थिति पैदा हुई, जहां मैं अपने functor जरूरत दो अलग-अलग कार्यों के

प्रदर्शन करने के लिए तो यह अब एक functor है। या तो आप जो चाहते हैं उसे करने के लिए दो मज़दूरों को पास करें, या template method कक्षा को परिभाषित करें। (आप रनटाइम ओवरहेड के बिना सी ++ में टेम्पलेट विधि पैटर्न प्राप्त करने के लिए मिक्स्सिन का भी उपयोग कर सकते हैं - लेकिन विकिपीडिया आलेख इसमें शामिल नहीं है) (नोट भी: सी ++ टेम्पलेट्स के समान नहीं है, हालांकि यदि आप जाते हैं तो सी ++ टेम्पलेट्स शामिल हो सकते हैं एओपी मार्ग)

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