2009-07-15 13 views
43

कुछ ऑपरेटरों को केवल सदस्य कार्यों के रूप में अधिभारित किया जा सकता है, अन्य गैर-सदस्य "मुक्त" फ़ंक्शंस और बाकी दोनों के रूप में क्यों?क्यों कुछ ऑपरेटरों को केवल सदस्य कार्यों के रूप में अधिभारित किया जा सकता है, अन्य दोस्त के कार्यों के रूप में और बाकी दोनों को दोनों के रूप में क्यों?

उन लोगों के पीछे तर्क क्या है?

याद रखें कि कौन से ऑपरेटर को (सदस्य, मुफ़्त, या दोनों) के रूप में अधिभारित किया जा सकता है?

+5

@BROY आपका संपादन गलत है, _non-member_ फ़ंक्शन जरूरी नहीं है _friend_। (और मुझे यह भी पता चलता है कि आपका संपादन बदल गया है [बहुत] (http://stackoverflow.com/posts/1132600/revisions) मूल प्रश्न में।) –

उत्तर

7

तर्क यह है कि उनके लिए गैर-सदस्य होने का अर्थ नहीं होगा, क्योंकि ऑपरेटर के बाईं ओर की बात एक वर्ग उदाहरण होनी चाहिए।

a1.operator=(42); 

यह की एलएचएस पर बात के लिए कोई मतलब नहीं होगा:

उदाहरण के लिए, एक वर्ग एक

A a1; 
.. 
a1 = 42; 

पिछले बयान संभालने वास्तव में इस तरह एक फोन है। ए का उदाहरण नहीं होना चाहिए, और इसलिए फ़ंक्शन एक सदस्य होना चाहिए।

+2

मैं उपयोगों के बारे में सोच सकता हूं। उदाहरण के लिए, कक्षा बी सैद्धांतिक रूप से यह बदलना चाहता है कि ऑपरेटर = (ए और बी) को अधिभारित करके ए को कैसे असाइन किया गया है, लेकिन बी किसी कारण से किसी को कास्ट ऑपरेटर को परिभाषित नहीं करना चाहता (उदाहरण के लिए क्योंकि आप नहीं चाहते हैं अन्य अंतर्निहित घटनाएं होती हैं)। यह इच्छा सामान्य अभ्यास, आदि के खिलाफ मूर्खतापूर्ण हो सकती है, लेकिन मुझे यकीन नहीं है कि यह बकवास है या आपने इसके खिलाफ मामला बनाया है (अभी तक)। –

+0

खैर, यह वास्तव में कोई फर्क नहीं पड़ता कि मैंने मुकदमा नहीं किया है - हमें मानक को क्या स्वीकार करना है। और निश्चित रूप से आप किसी नामित मित्र फ़ंक्शन के माध्यम से अपनी पसंद के लगभग (लगभग) कुछ भी कर सकते हैं। –

+1

आदिम प्रकारों पर इस तरह के संचालन को अस्वीकार करना समझ में आता है, लेकिन वैश्विक * ऑपरेटर [] (कॉन्स्ट माईक्लास और, int) * की अनुमति क्यों न दें * और * ऑपरेटर [] (शून्य *, int) * विशेष रूप से आदिम के कारण त्रुटि उत्पन्न करें प्रकार? –

5

क्योंकि आप आदिम प्रकारों के अर्थशास्त्र को संशोधित नहीं कर सकते हैं। operator=int पर काम करता है, पॉइंटर को कैसे डिफरेंस करना है, या सरणी पहुंच कैसे काम करती है, यह परिभाषित करने के लिए यह समझ में नहीं आता है।

0

यहाँ एक उदाहरण है: जब आप एक class T के लिए << operator ओवरलोडिंग कर रहे हैं हस्ताक्षर हो जाएगा:

std::ostream operator<<(std::ostream& os, T& objT) 

कार्यान्वयन की जरूरत है जहां

{ 
//write objT to the os 
return os; 
} 

<< ऑपरेटर पहले के लिए होने के लिए तर्क को ओस्ट्रीम ऑब्जेक्ट और दूसरी कक्षा आपकी ऑब्जेक्ट टी ऑब्जेक्ट की आवश्यकता होती है।

यदि आप operator<< को सदस्य फ़ंक्शन के रूप में परिभाषित करने का प्रयास करते हैं तो आपको इसे std::ostream operator<<(std::ostream& os, T& objT) के रूप में परिभाषित करने की अनुमति नहीं दी जाएगी। ऐसा इसलिए है क्योंकि बाइनरी ऑपरेटर सदस्य फ़ंक्शन केवल एक तर्क ले सकते हैं और invoking ऑब्जेक्ट को this का उपयोग करके पहले तर्क के रूप में निहित रूप से पारित किया गया है।

यदि आप std::ostream operator<<(std::ostream& os) सदस्य फ़ंक्शन के रूप में हस्ताक्षर का उपयोग करते हैं तो आप वास्तव में सदस्य फ़ंक्शन std::ostream operator<<(this, std::ostream& os) के साथ समाप्त हो जाएंगे जो आप जो चाहते हैं वह नहीं करेंगे। इसलिए आपको ऐसे ऑपरेटर की आवश्यकता है जो सदस्य फ़ंक्शन नहीं है और सदस्य डेटा तक पहुंच सकता है (यदि आपके क्लास टी में निजी डेटा है जिसे आप स्ट्रीम करना चाहते हैं, operator<< कक्षा टी का मित्र होना आवश्यक है)।

28

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

  1. ऑपरेटरों जो सदस्यों के रूप में अतिभारित किया जाना है। ये काफी कम हैं:

    1. असाइनमेंट operator=()। गैर-सदस्य असाइनमेंट की अनुमति देने वाले ऑपरेटरों को अपहर्ताओं को अपहृत करने के लिए दरवाजा खोलना प्रतीत होता है, उदा।, const योग्यता के विभिन्न संस्करणों के लिए ओवरलोडिंग द्वारा। यह देखते हुए कि असाइनमेंट ऑपरेटर बल्कि मौलिक हैं जो अवांछित प्रतीत होते हैं।
    2. फ़ंक्शन कॉल operator()()। फ़ंक्शन कॉल और ओवरलोडिंग नियम पर्याप्त रूप से जटिल हैं। गैर-सदस्य फ़ंक्शन कॉल ऑपरेटरों को अनुमति देकर नियमों को जटिल बनाने की सलाह दी जाती है।
    3. सबस्क्रिप्ट operator[]()। रोचक इंडेक्स प्रकारों का उपयोग करना ऐसा लगता है कि ऑपरेटरों तक पहुंच में हस्तक्षेप हो सकता है। यद्यपि अधिभार को अपहरण करने का कोई खतरा नहीं है, लेकिन अत्यधिक गैर-स्पष्ट कोड लिखने के लिए बहुत अधिक लाभकारी लेकिन दिलचस्प संभावना प्रतीत नहीं होती है।
    4. कक्षा सदस्य का उपयोग operator->()। ऑफ-हाथ मैं इस ऑपरेटर को गैर-सदस्य ओवरलोड करने का कोई बुरा दुरुपयोग नहीं देख सकता। दूसरी ओर, मैं भी कोई नहीं देख सकता। साथ ही, कक्षा सदस्य एक्सेस ऑपरेटर के बजाय विशेष नियम हैं और इनके साथ हस्तक्षेप करने वाले संभावित अधिभारों के साथ खेलना एक अनावश्यक जटिलता प्रतीत होता है।

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

    यह कहा गया, उदाहरण के लिए, लैम्ब्डा अभिव्यक्ति लाइब्रेरी के लिए यह अच्छा होगा अगर इन सभी ऑपरेटरों को अधिभारित करना संभव हो और मुझे नहीं लगता कि इन ऑपरेटरों को अधिभारित होने से रोकने के लिए एक अंतर्निहित तकनीकी कारण है।

  2. ऑपरेटर जिन्हें गैर-सदस्य कार्यों के रूप में अधिभारित किया जाना है।

    1. उपयोगकर्ता परिभाषित शाब्दिक operator"" name()

    इस ऑपरेटर एक अजीब गेंद के कुछ यकीनन नहीं वास्तव में बहुत संचालक हो और,। किसी भी मामले में, इस सदस्य को कॉल करने के लिए कोई ऑब्जेक्ट नहीं है जिसके लिए सदस्यों को परिभाषित किया जा सकता है: उपयोगकर्ता द्वारा परिभाषित साहित्य के बाएं तर्क हमेशा अंतर्निहित प्रकार होते हैं।

  3. प्रश्न में आपका उल्लेख नहीं लेकिन वहां भी ऑपरेटर जिस पर सभी अतिभारित नहीं किया जा सकता हैं:

    1. सदस्य चयनकर्ता .
    2. सूचक करने वाली सदस्य वस्तु का उपयोग ऑपरेटर .*
    3. स्कोप ऑपरेटर ::
    4. टर्नरी ऑपरेटर ?:

    इन चार ऑपरेटरों को बिल्कुल दखल देने के लिए बहुत मौलिक माना जाता था। यद्यपि कुछ बिंदु पर operator.() ओवरलोडिंग करने का प्रस्ताव था, लेकिन ऐसा करने में मजबूत समर्थन नहीं है (मुख्य उपयोग केस स्मार्ट संदर्भ होगा)। यद्यपि निश्चित रूप से कुछ संदर्भ कल्पनाशील हैं जहां इन ऑपरेटरों को अधिभारित करना अच्छा होगा।

  4. ऑपरेटर जिन्हें सदस्यों या गैर-सदस्यों के रूप में अधिभारित किया जा सकता है।यह ऑपरेटरों के थोक है:

    1. पूर्व और बाद के वेतन वृद्धि/-decrement operator++(), operator--(), operator++(int), operator--(int)
    2. [एकल] operator*()
    3. [एकल] पता-की भिन्नता operator&()
    4. [एकल] संकेत operator+(), operator-()
    5. तार्किक निषेध operator!() (या operator not())
    6. बिटवाइज़ उलट operator~() (या operator compl())
    7. तुलना operator==(), operator!=(), operator<(), operator>(), operator<=(), और operator>()
    8. [द्विआधारी] गणित operator+(), operator-(), operator*(), operator/(), operator%()
    9. [बाइनरी ] bitwise operator&() (या operator bitand()), operator|() (या operator bit_or()), operator^() (या operator xor())
    10. बिटवाइज़ पारी operator<<() और operator>>()
    11. तर्क operator||() (या operator or()) और operator&&() (या operator and())
    12. आपरेशन/काम [email protected]=() (@ एक उपयुक्त ऑपरेटर प्रतीक() के लिए किया जा रहा
    13. अनुक्रम operator,() (जिसके लिए अधिभार वास्तव में अनुक्रम संपत्ति को मारता है!)
    14. पॉइंटर पॉइंटर-टू-सदस्य पहुंच operator->*()
    15. स्मृति प्रबंधन operator new(), operator new[](), operator new[](), और operator delete[]()

    ऑपरेटरों जो या तो सदस्यों के रूप में या गैर सदस्यों के रूप में अतिभारित किया जा सकता अन्य ऑपरेटरों के रूप में मौलिक वस्तु रखरखाव के लिए आवश्यक के रूप में नहीं हैं। यह कहना नहीं है कि वे महत्वपूर्ण नहीं हैं। वास्तव में, इस सूची में कुछ ऑपरेटरों जहां यह नहीं बल्कि संदिग्ध है कि क्या वे overloadable होना चाहिए (इसमें जैसे, पता-की operator&() या ऑपरेटरों जो आम तौर पर अनुक्रमण का कारण है, यानी, operator,(), operator||(), और operator&&()

बेशक, सी ++ मानक इस बात पर तर्क नहीं देता है कि चीजें किस तरह से की जाती हैं (और शुरुआती दिनों के रिकॉर्ड भी नहीं होते हैं जब इन निर्णयों को बनाया जाता है)। सबसे अच्छा तर्क शायद " डिजाइन और विकास सी ++ "बजेर्न स्ट्राउस्ट्रप द्वारा। मुझे याद है कि ऑपरेटर पर चर्चा की गई थी लेकिन ऐसा लगता है कि इलेक्ट्रॉनिक संस्करण उपलब्ध नहीं है।

कुल मिलाकर, मुझे नहीं लगता कि संभावित जटिलताओं के अलावा प्रतिबंधों के लिए वास्तव में मजबूत कारण हैं जिन्हें ज्यादातर प्रयास के लायक नहीं माना जाता था। हालांकि, मुझे संदेह होगा कि प्रतिबंधों को उठाया जाने की संभावना है क्योंकि मौजूदा सॉफ्टवेयर के साथ बातचीत अप्रत्याशित तरीकों से कुछ कार्यक्रमों के अर्थ को बदलने के लिए बाध्य है।