2009-10-25 19 views
7

क्या कक्षा वर्ग में मूल विधियों की परिभाषा को संशोधित किए बिना कक्षा में नई विधियों को जोड़ने का कोई तरीका है (यानी संकलित। Lib जिसमें कक्षा और संबंधित .h फ़ाइल है) जैसे सी # वर्ग वर्ग विधियां?सी ++ कक्षा विस्तार

+1

भविष्य के संदर्भ के लिए, इसे 'बंदर पैचिंग' कहा जाता है। – LiraNuna

उत्तर

15

नहीं सी ++ में ऐसी कोई क्षमता नहीं है।

अन्य उत्तर में उल्लेख किया है, आम कामकाज से जुड़े हैं:

  • एक व्युत्पन्न वर्ग को परिभाषित करें, शायद एक कारखाने वास्तविक क्रियान्वयन वर्ग
  • को छिपाने के लिए के साथ परिभाषित decorator वर्ग
  • कार्यों कि संचालित परिभाषित करें कक्षा
+0

[डबल प्रेषण] द्वारा भी किया जा सकता है (http://en.wikipedia.org/wiki/Double_dispatch) – Bossliaw

11

नहीं, आप सी ++ में ऐसा नहीं कर सकते हैं।

आप कुछ इस तरह प्राप्त करने के लिए चाहते हैं तो आप के 2 विकल्प है

  • आप वर्ग से विरासत सकता है (अगर यह एक विकल्प है, यह कानूनी नहीं हो सकता है के रूप में वर्ग के लिए लिखा गया है नहीं हो सकता है विरासत की अनुमति दें)
  • आप अपना खुद का रैपर वर्ग लिख सकते हैं जिसमें एक ही इंटरफ़ेस + आपकी नई विधियां और उस व्यक्ति को प्रतिनिधि हो जिसे आप विस्तारित करना चाहते हैं।

मैं प्रतिनिधिमंडल दृष्टिकोण पसंद करता हूं।

+4

"विरासत पर अनुपालन के पक्ष में" – Rob

+0

अच्छा उत्तर - लेकिन मुझे यकीन नहीं है कि कोई प्रश्न पूछेगा ये जानता है कि "वारिस" या "प्रतिनिधि" जैसे शब्दों को सुनते समय क्या कार्यान्वित किया जाए। –

+1

@ एमएच, शायद नहीं। लेकिन अब वे एसओ या Google खोज में डालने के लिए सही शर्तों को जानते हैं – Glen

-2

क्षमा करें, नहीं। एक बार आपका कोड obj में है, तो आप इसे बदल नहीं सकते हैं। यदि यह वीसी आंशिक कक्षाओं में किया जा सकता है तो पहले से ही समर्थित किया जाएगा। हालांकि एक अपवाद है, ऑपरेटर विधियों को वैश्विक कार्यों का उपयोग करके बढ़ाया जा सकता है, जैसे कि सीओटी < < एसटीएल में लागू किया गया है।

5

सी # कक्षा विस्तार विधियां ज्यादातर वाक्य रचनात्मक चीनी हैं। आपको मुफ्त कार्यों के साथ समान कार्यक्षमता मिलती है (यानी, एक संदर्भ के साथ कार्य करता है या आपके वर्ग के निरंतर संदर्भ को उनके पहले पैरामीटर के रूप में)। चूंकि यह एसटीएल के लिए अच्छा काम करता है, क्यों नहीं आपकी कक्षा के लिए?

-3

सुनिश्चित करें कि आप कर सकते हैं:


template <typename Ext> 
class Class: public Ext { /* ... */ }; 

कि इसका मतलब यह नहीं है कि यह सबसे अच्छा तरीका है, हालांकि है।

1

आम तौर पर नहीं। हालांकि, यदि लाइब्रेरी कक्षा के उदाहरण नहीं बनाती है जिसके लिए आपके एक्सटेंशन की आवश्यकता होती है और आप उस ऐप के सभी स्थानों को संशोधित करने में सक्षम होते हैं जो कक्षा का उदाहरण बनाते हैं और आपके एक्सटेंशन की आवश्यकता होती है, तो आप यहां जा सकते हैं:

  • एक फैक्ट्री फ़ंक्शन बनाएं जिसे क्लास के उदाहरण की आवश्यकता होती है और उदाहरण के लिए पॉइंटर लौटाता है (डिज़ाइन पैटर्न फैक्टरी, ... के लिए Google)।
  • अपने इच्छित एक्सटेंशन के साथ व्युत्पन्न कक्षा बनाएं।
  • फ़ैक्टरी फ़ंक्शन को मूल श्रेणी के बजाय अपनी व्युत्पन्न कक्षा वापस कर दें।

उदाहरण:


    class derivedClass: public originalClass { /* ... */}; 

    originalClass* createOriginalClassInstance() 
    { 
     return new derivedClass(); 
    } 
  • जब भी आप एक्सटेंशन का उपयोग करने की जरूरत है, तो आप, व्युत्पन्न वर्ग के मूल कलाकारों कास्ट करने के लिए निश्चित रूप से की जरूरत है।

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

1

एक ऐसा तरीका है जिसमें इसे किया जा सकता है। और यह आपकी आवश्यकताओं को थोड़ा सा आराम से कर रहा है। सी ++ में, लोग अक्सर कहते हैं कि किसी वर्ग के इंटरफ़ेस में केवल सदस्य सदस्य नहीं होते हैं, लेकिन क्लास पर काम करने वाले सभी फ़ंक्शन शामिल हैं।

यही है, गैर-सदस्य कार्य जिन्हें कक्षा को पैरामीटर के रूप में दिया जा सकता है उसे अपने इंटरफ़ेस का हिस्सा माना जाना चाहिए।

उदाहरण के लिए, std::find() या std::sort()std::vector के इंटरफ़ेस का हिस्सा हैं, भले ही वे कक्षा के सदस्य न हों।

और यदि आप इस परिभाषा को स्वीकार करते हैं, तो आप हमेशा गैर-कार्य कार्यों को जोड़कर कक्षा का विस्तार कर सकते हैं।

0

आप बाइनरी रूप में कक्षा फ़ाइल में भौतिक रूप से विधियों या डेटा को जोड़ नहीं सकते हैं। हालांकि, आप विस्तार कक्षाओं को लिखकर उस वर्ग की वस्तुओं को विधियों और डेटा (कार्यक्षमता और स्थिति) जोड़ सकते हैं। यह सीधे आगे नहीं है और मेटा-ऑब्जेक्ट-प्रोटोकॉल और इंटरफेस आधारित प्रोग्रामिंग की आवश्यकता है। आपको C++ में इसे प्राप्त करने के लिए बहुत कुछ करने की आवश्यकता है क्योंकि यह बॉक्स के प्रतिबिंब का समर्थन नहीं करता है। ऐसे कार्यान्वयन में जब आप मूल कक्षा ऑब्जेक्ट पॉइंटर के माध्यम से अपने नए एक्सटेंशन क्लास द्वारा कार्यान्वित इंटरफ़ेस के लिए क्वेरी करते हैं, तो मेटा ऑब्जेक्ट कार्यान्वयन मेटा क्लास ऑब्जेक्ट के माध्यम से इंटरफ़ेस पॉइंटर को उस एक्सटेंशन क्लास के लिए देता है जो इसे रनटाइम पर बनाता है। यह कितना अनुकूलन योग्य है (प्लगइन आधारित) सॉफ्टवेयर अनुप्रयोग ढांचे काम करते हैं। हालांकि, आपको याद रखना चाहिए कि उन सभी वर्गों के लिए मेटा ऑब्जेक्ट्स को इंस्टेंट करने के लिए कई अन्य एमओपी तंत्रों की आवश्यकता होती है जिनमें ऑब्जेक्ट रिलेशनशिप का वर्णन किया गया है और मूल और विस्तारित कक्षा वस्तुओं के लिए सही इंटरफ़ेस पॉइंटर्स प्रदान करते हैं। डेसॉल्ट सिस्टम 'कैटिया वी 5 सीएए वी 5 नामक इस तरह के एक आर्किटेक्चर में लिखा गया है जहां आप वांछित कार्यक्षमता के साथ नए एक्सटेंशन कक्षाओं को लिखकर मौजूदा घटकों का विस्तार कर सकते हैं।

3

सी ++ में आप मुफ्त कार्यों का उपयोग कर सकते हैं, लेकिन कभी-कभी एक्सटेंशन विधियां बेहतर काम करती हैं जब आप कई कार्यों को घोंसला करते हैं। हम C++ मुक्त समारोह का उपयोग कर इसे इस प्रकार दिखाई देगा यह लिखने के लिए तो

var r = numbers.Where(x => x > 2).Select(x => x * x); 

: इस सी # कोड पर एक नजर डालें

auto r = select(where(numbers, [](int x) { return x > 2; }), [](int x) { return x * x; }); 

न केवल पढ़ने के लिए इस मुश्किल है, लेकिन यह मुश्किल है लिखना। इसे हल करने का सामान्य तरीका एक पाइपबल फ़ंक्शन कहलाता है। ये फ़ंक्शन | पाइप ऑपरेटर (जो वास्तव में वास्तव में या ऑपरेटर है) को ओवरलोड करके बनाए जाते हैं। तो उपरोक्त कोड इस तरह लिखा जा सकता है:

auto r = numbers | where([](int x) { return x > 2; }) | select([](int x) { return x * x; }); 

जो पढ़ने और लिखना बहुत आसान है।कई पुस्तकालय श्रेणियों के लिए पाइप करने योग्य फ़ंक्शन का उपयोग करते हैं, लेकिन इसे अन्य कक्षाओं में भी विस्तारित किया जा सकता है। बूस्ट इसे range लाइब्रेरी में उपयोग करता है, pstade oven इसका उपयोग करता है, और यह सी ++ linq लाइब्रेरी भी इसका उपयोग करता है।

यदि आप अपना खुद का पाइप करने योग्य फ़ंक्शन लिखना चाहते हैं, तो यह बताएं कि here कैसे करें। अन्य पुस्तकालय, हालांकि, इसे आसान बनाने के लिए फ़ंक्शन एडेप्टर प्रदान करते हैं। Pstade अंडे में pipable adaptor है, और linq range_extension एडाप्टर प्रदान करता है ताकि कम से कम श्रेणियों के लिए एक पाइप करने योग्य फ़ंक्शन तैयार किया जा सके।

का प्रयोग LINQ, आपको पहले सिर्फ इस तरह एक समारोह वस्तु के रूप में अपने कार्य बनाने के लिए:

struct contains_t 
{ 
    template<class Range, class T> 
    bool operator()(Range && r, T && x) const 
    { return (r | linq::find(x)) != boost::end(r); }; 
}; 

तो फिर तुम इस तरह स्थिर आरंभीकरण का उपयोग कर समारोह प्रारंभ:

range_extension<contains_t> contains = {}; 

तो आप उपयोग कर सकते अपने इस तरह पाइप करने योग्य कार्य:

if (numbers | contains(5)) printf("We have a 5"); 
संबंधित मुद्दे