वस्तुओं को संदर्भ से क्यों पारित किया जाता है?


31

एक युवा सह-कार्यकर्ता जो OO का अध्ययन कर रहा था, उसने मुझसे पूछा है कि हर वस्तु को संदर्भ द्वारा पारित किया जाता है, जो कि आदिम प्रकार या संरचना के विपरीत है। यह जावा और C # जैसी भाषाओं की एक सामान्य विशेषता है।

मुझे उसके लिए अच्छा जवाब नहीं मिला।

इस डिजाइन निर्णय के लिए प्रेरणा क्या हैं? क्या इन भाषाओं के डेवलपर्स हर बार पॉइंटर्स और टाइपडेफ़ बनाने के लिए थक गए थे?


2
क्या आप पूछ रहे हैं कि जावा और सी # को आपने मान के बजाय संदर्भ से, या सूचक के बजाय संदर्भ से पारित किया है?
रॉबर्ट

@ रॉबर्ट, उच्च स्तर पर "पॉइंटर के बजाय संदर्भ" के बीच कोई अंतर है? आपको लगता है क्यों वस्तु हमेशा संदर्भ हैं मैं की तरह 'कुछ करने के लिए शीर्षक बदलने चाहिए "?
गुस्तावो कार्डोसो

सन्दर्भ सूचक हैं।
९'११

2
@ एंटो: एक जावा संदर्भ सभी तरह से उपयोग किए जाने वाले सी पॉइंटर के समान है (ठीक से उपयोग किया गया: टाइप-कास्ट नहीं, अमान्य मेमोरी पर सेट नहीं है, शाब्दिक द्वारा सेट नहीं है)।
ज़ेन लिंक्स

5
वास्तव में पांडित्यपूर्ण होने के लिए, शीर्षक गलत है (कम से कम जहाँ तक .net का संबंध है)। वस्तुओं को संदर्भ से पारित नहीं किया जाता है, संदर्भ मूल्य द्वारा पारित किए जाते हैं। जब आप किसी विधि को ऑब्जेक्ट पास करते हैं, तो संदर्भ मान को विधि बॉडी के भीतर एक नए संदर्भ में कॉपी किया जाता है। मुझे लगता है कि इसकी शर्म की बात है कि "वस्तुओं को संदर्भ द्वारा पारित किया जाता है" आम प्रोग्रामर उद्धरणों की सूची में दर्ज किया गया है जब यह गलत है और नए प्रोग्रामर के लिए संदर्भों की खराब समझ शुरू होती है।
सीक्रेटडायलर

जवाबों:


15

इसके मूल कारण निम्न हैं:

  • पॉइंटर्स सही होने के लिए तकनीकी हैं
  • आपको कुछ डेटा संरचनाओं को लागू करने के लिए पॉइंटर्स की आवश्यकता होती है
  • आपको मेमोरी उपयोग में कुशल होने के लिए पॉइंटर्स की आवश्यकता होती है
  • अगर आपको सीधे हार्डवेयर का उपयोग नहीं करना है तो आपको काम करने के लिए मैनुअल मेमोरी इंडेक्सिंग की आवश्यकता नहीं है।

इसलिए, संदर्भ।


32

सरल उत्तर:

स्मृति की खपत
और
सीपीयू समय को कम करने और हर वस्तु की गहरी प्रतिलिपि बनाने में कहीं न कहीं पारित कर दिया।


मैं आपसे सहमत हूं, लेकिन मुझे लगता है कि इन लोगों के साथ कुछ सौंदर्य या ओओ डिजाइन प्रेरणा भी है।
गुस्तावो कार्डसो

9
@ गुस्तावो कार्डसो: "कुछ सौंदर्य या ओओ डिजाइन प्रेरणा"। नहीं, यह केवल एक अनुकूलन है।
एस.लॉट

6
@ S.Lott: नहीं, यह संदर्भ से गुजरने के लिए OO शब्दों में समझ में आता है क्योंकि, शब्दार्थ, आप वस्तुओं की प्रतियाँ नहीं बनाना चाहते हैं। आप इसकी एक प्रति के बजाय ऑब्जेक्ट पास करना चाहते हैं । यदि आप मूल्य से गुजर रहे हैं, तो यह OO रूपक को कुछ हद तक तोड़ देता है क्योंकि आपको इन सभी वस्तुओं के क्लोन सभी जगह उत्पन्न हो रहे हैं जो उच्च स्तर पर समझ में नहीं आते हैं।
intuited

@ गुस्तावो: मुझे लगता है कि हम एक ही बिंदु पर बहस कर रहे हैं। आप ओओपी के शब्दार्थों का उल्लेख करते हैं और ओओपी के रूपक का संदर्भ मेरे स्वयं के अतिरिक्त कारणों से लेते हैं। यह मुझे लगता है कि OOP के रचनाकारों ने इसे "मेमोरी की खपत को कम करने" और "सीपीयू के समय को बचाने" के लिए किया था
टिम

14

C ++ में, आपके पास दो मुख्य विकल्प हैं: मान द्वारा लौटें या पॉइंटर द्वारा वापस लौटें। आइए पहले एक नजर डालते हैं:

MyClass getNewObject() {
    MyClass newObj;
    return newObj;
}

मान लें कि आपका कंपाइलर रिटर्न वैल्यू ऑप्टिमाइज़ेशन का उपयोग करने के लिए पर्याप्त स्मार्ट नहीं है, तो यहां क्या होता है:

  • newObj को एक अस्थायी ऑब्जेक्ट के रूप में बनाया गया है और इसे स्थानीय स्टैक पर रखा गया है।
  • NewObj की एक प्रति बनाई और वापस कर दी जाती है।

हमने ऑब्जेक्ट की एक प्रति व्यर्थ कर दी है। यह प्रसंस्करण समय की बर्बादी है।

आइए इसके बजाय रिटर्न-बाय-पॉइंटर देखें:

MyClass* getNewObject() {
    MyClass newObj = new MyClass();
    return newObj;
}

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

MyClass someObj = getNewObject();
delete someObj;

यह जानना कि इस तरह से आवंटित की गई वस्तु को हटाने के लिए कौन जिम्मेदार है, कुछ ऐसा है जिसे केवल टिप्पणियों या सम्मेलन द्वारा ही सूचित किया जा सकता है। यह आसानी से मेमोरी लीक की ओर जाता है।

इन दो मुद्दों को हल करने के लिए बहुत सारे समाधान सुझाए गए हैं - रिटर्न वैल्यू ऑप्टिमाइज़ेशन (जिसमें कंपाइलर काफी स्मार्ट है रिटर्न-बाय-वैल्यू में निरर्थक कॉपी नहीं बनाने के लिए), विधि का संदर्भ देते हुए (इसलिए फ़ंक्शन एक में इंजेक्ट होता है मौजूदा वस्तु एक नया बनाने के बजाय), स्मार्ट पॉइंटर्स (ताकि स्वामित्व का सवाल मूट हो)।

जावा / सी # रचनाकारों ने महसूस किया कि हमेशा संदर्भ द्वारा वस्तु लौटाना एक बेहतर समाधान था, खासकर अगर भाषा ने मूल रूप से इसका समर्थन किया। इसमें बहुत सी अन्य विशेषताएं हैं, जैसे कि भाषाओं में कचरा संग्रह इत्यादि।


रिटर्न-बाय-वैल्यू काफी खराब है, लेकिन पास-बाय-वैल्यू तब भी बदतर है जब यह वस्तुओं की बात आती है, और मुझे लगता है कि यही वास्तविक समस्या थी जिससे वे बचने की कोशिश कर रहे थे।
मेसन व्हीलर

सुनिश्चित करने के लिए कि आपके पास एक वैध बिंदु है। लेकिन OO की समस्या यह है कि @ मेसन ने बताया कि बदलाव की अंतिम प्रेरणा थी। जब आप संदर्भ का उपयोग करना चाहते हैं तो संदर्भ और मूल्य के बीच अंतर रखने का कोई अर्थ नहीं था।
गुस्तावो कार्डसो

10

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

संदर्भों का उपयोग करना स्मार्ट है। चीजों को कॉपी करना खतरनाक है।

जैसा कि दूसरों ने कहा है, जावा में, कोई प्राकृतिक "क्लोन" नहीं है। यह केवल एक लापता सुविधा नहीं है। आप कभी नहीं चाहते कि कोई वस्तु में सिर्फ विली-नीली * कॉपी (चाहे छिछली या गहरी) हो। क्या होगा यदि वह संपत्ति एक डेटाबेस कनेक्शन थी? आप एक डेटाबेस कनेक्शन को सिर्फ "क्लोन" नहीं कर सकते, इससे अधिक आप एक मानव क्लोन कर सकते हैं। प्रारंभिक कारण से मौजूद है।

कितना गहरा आप करते हैं - दीप प्रतियां उनकी खुद की एक समस्या है वास्तव में जाना? आप निश्चित रूप से ऐसी किसी भी चीज़ की नकल नहीं कर सकते जो स्थिर है (किसी भी Classवस्तु सहित )।

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


* टिप्पणियां देखें - इस "कभी नहीं" बयान से मेरा मतलब एक ऑटो-क्लोन है जो हर संपत्ति को क्लोन करता है। जावा ने एक प्रदान नहीं किया है, और यह संभव नहीं है कि आपके लिए भाषा का एक उपयोगकर्ता के रूप में आपके स्वयं के लिए एक अच्छा विचार है, यहां सूचीबद्ध कारणों के लिए। केवल गैर-क्षणिक क्षेत्रों की क्लोनिंग एक शुरुआत होगी, लेकिन तब भी आपको transientजहां उचित हो, परिभाषित करने के लिए मेहनती होना चाहिए ।


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

2
@ इंका - आप मुझे गलत समझ सकते हैं। जानबूझकर लागू किया cloneजाना ठीक है। "विली-नीली" से मेरा मतलब है कि इसके बारे में सोचे बिना सभी गुणों की नकल करना - उद्देश्यपूर्ण इरादे के बिना। जावा भाषा डिजाइनरों ने उपयोगकर्ता-निर्मित कार्यान्वयन की आवश्यकता से इस आशय को मजबूर किया clone
निकोल

अपरिवर्तनीय वस्तुओं के संदर्भ का उपयोग करना स्मार्ट है। दिनांक उत्परिवर्तन जैसे सरल मूल्य बनाना, और फिर उनके लिए कई संदर्भ बनाना नहीं है।
केविन क्लाइन

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

गहरी प्रतिलिपि पहलू एक महत्वपूर्ण बिंदु है। ऑब्जेक्ट को कॉपी करना तब समस्याग्रस्त होता है, जब वे अन्य ऑब्जेक्ट्स के संदर्भ में होते हैं, खासकर यदि ऑब्जेक्ट ग्राफ़ में उत्परिवर्तित ऑब्जेक्ट होते हैं।
कालेब

4

जावा में वस्तुओं को हमेशा संदर्भित किया जाता है। वे कभी भी अपने आस-पास से गुजरते नहीं हैं।

एक फायदा यह है कि इससे भाषा सरल हो जाती है। C ++ ऑब्जेक्ट को एक मान या संदर्भ के रूप में दर्शाया जा सकता है, जिससे एक सदस्य तक पहुँचने के लिए दो अलग-अलग ऑपरेटरों का उपयोग करने की आवश्यकता होती है: .और ->। (ऐसे कारण हैं कि इसे समेकित नहीं किया जा सकता है; उदाहरण के लिए, स्मार्ट पॉइंटर्स ऐसे मान हैं जो संदर्भ हैं, और उन विशिष्टों को रखना है।) जावा को केवल जरूरत है .

एक और कारण यह है कि बहुरूपता को संदर्भ से किया जाना चाहिए, मूल्य से नहीं; मूल्य द्वारा उपचारित एक वस्तु बस वहाँ है, और एक निश्चित प्रकार है। C ++ में इसे स्क्रू करना संभव है।

इसके अलावा, जावा डिफ़ॉल्ट असाइनमेंट / कॉपी / जो भी हो स्विच कर सकता है। C ++ में, यह कम या ज्यादा गहरी कॉपी है, जबकि जावा में यह एक सरल पॉइंटर असाइनमेंट / कॉपी / जो कुछ भी है, .clone()और इस तरह के मामले में आपको कॉपी करने की आवश्यकता है।


जब आप '(* ऑब्जेक्ट) ->'
Gustavo Cardoso

1
यह ध्यान देने योग्य है कि C ++ संकेत, संदर्भ और मूल्यों के बीच अंतर करता है। SomeClass * किसी ऑब्जेक्ट का पॉइंटर है। SomeClass & किसी ऑब्जेक्ट का संदर्भ है। SomeClass एक मान प्रकार है।
एंट

मैंने पहले से ही प्रारंभिक प्रश्न पर @ रॉबर्ट से पूछा है, लेकिन मैं इसे यहाँ भी करूँगा: * और / और C ++ के बीच का अंतर केवल एक निम्न स्तर की तकनीकी चीज़ है, है न? क्या वे उच्च स्तर पर हैं, शब्दार्थ वे समान हैं।
गुस्तावो कार्डसो

3
@ गुस्तावो कार्डसो: अंतर शब्दार्थ है; कम तकनीकी स्तर पर वे आम तौर पर समान होते हैं। एक संकेतक एक ऑब्जेक्ट को इंगित करता है, या NULL (एक परिभाषित खराब मूल्य) है। जब तक const, अन्य वस्तुओं को इंगित करने के लिए इसका मूल्य नहीं बदला जा सकता है। एक संदर्भ एक वस्तु के लिए दूसरा नाम है, NULL नहीं हो सकता है, और इसे बचाया नहीं जा सकता है। यह आमतौर पर पॉइंटर्स के सरल उपयोग द्वारा कार्यान्वित किया जाता है, लेकिन यह एक कार्यान्वयन विवरण है।
डेविड थॉर्नले

+1 के लिए "बहुरूपता को संदर्भ द्वारा किया जाना चाहिए।" यह एक अविश्वसनीय रूप से महत्वपूर्ण विवरण है जिसे अधिकांश अन्य उत्तरों ने नजरअंदाज कर दिया है।
डोभाल

4

C # ऑब्जेक्ट्स के संदर्भ में दिया जा रहा आपका प्रारंभिक कथन सही नहीं है। C # में, ऑब्जेक्ट संदर्भ प्रकार हैं, लेकिन डिफ़ॉल्ट रूप से वे मूल्य प्रकारों की तरह ही मूल्य द्वारा पारित किए जाते हैं। संदर्भ प्रकार के मामले में, पास-दर-मूल्य विधि पैरामीटर के रूप में कॉपी किया जाने वाला "मान" संदर्भ ही है, इसलिए विधि के दायरे के बाहर एक विधि के अंदर गुणों में परिवर्तन दिखाई देगा।

हालाँकि, यदि आप किसी विधि के अंदर पैरामीटर चर को फिर से असाइन करना चाहते हैं, तो आप देखेंगे कि यह परिवर्तन विधि क्षेत्र के बाहर परिलक्षित नहीं है। इसके विपरीत, यदि आप वास्तव में refकीवर्ड का उपयोग करके संदर्भ द्वारा एक पैरामीटर पास करते हैं , तो यह व्यवहार अपेक्षित रूप से काम करता है।


3

शीघ्र जवाब

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

अतिरिक्त विस्तारित उबाऊ टिप्पणी

Altougth, उन भाषाओं में ऑब्जेक्ट रेफरेंस (जावा, डेल्फी, C #, VB.NET, Vala, Scala, PHP) का उपयोग किया जाता है, सच्चाई यह है कि ऑब्जेक्ट रेफ़रेंस ऑब्जेक्ट्स में भेस के संकेत होते हैं। शून्य मान, मेमोरी एलोकेशन, किसी ऑब्जेक्ट के संपूर्ण डेटा को कॉपी किए बिना संदर्भ की कॉपी, ये सभी ऑब्जेक्ट पॉइंटर्स हैं, न कि प्लेन ऑब्जेक्ट्स !!!

ऑब्जेक्ट पास्कल (डेल्फी में नहीं), anc C ++ (जावा नहीं, सी # नहीं), एक ऑब्जेक्ट को एक स्थिर आवंटित चर के रूप में घोषित किया जा सकता है, और एक डायनेमिक आवंटित चर के साथ, एक पॉइंटर ("ऑब्जेक्ट रेफरेंस" के बिना) चीनी वाक्य रचना ")। प्रत्येक केस कुछ सिंटैक्स का उपयोग करता है, और जावा "और दोस्तों" के रूप में भ्रमित होने का कोई तरीका नहीं है। उन भाषाओं में, एक वस्तु को मूल्य या संदर्भ के रूप में पारित किया जा सकता है।

प्रोग्रामर जानता है कि एक पॉइंटर सिंटैक्स की आवश्यकता कब है, और कब आवश्यक नहीं है, लेकिन जावा और एक जैसे भाषाओं में, यह भ्रामक है।

जावा के अस्तित्व में आने या मुख्यधारा बनने से पहले, कई प्रोग्रामर बिना किसी संकेत के, बिना किसी मूल्य के या संदर्भ के गुजरने वाले C ++ में OO सीखते हैं। जब सीखने के लिए व्यावसायिक ऐप से स्विच किया जाता है। तब, वे आमतौर पर ऑब्जेक्ट पॉइंटर्स का उपयोग करते हैं। क्यूटी पुस्तकालय इसका अच्छा उदाहरण है।

जब मैंने जावा सीखा, तो मैंने सब कुछ का पालन करने की कोशिश की एक वस्तु अवधारणा है, लेकिन कोडिंग में भ्रमित हो गया। आखिरकार, मैंने कहा "ठीक है, यह एक गतिशील रूप से आवंटित ऑब्जेक्ट के सिंटैक्स के साथ एक पॉइंटर के साथ आवंटित की गई वस्तुएं हैं", और फिर से कोड करने के लिए परेशानी नहीं हुई।


3

जावा और C # आप से निम्न-स्तरीय मेमोरी पर नियंत्रण रखते हैं। "हीप" जहाँ आपके द्वारा बनाई गई वस्तुएं अपना जीवन स्वयं जीती हैं; उदाहरण के लिए, कचरा संग्रहकर्ता जब चाहे तब वस्तुओं को फिर से दिखाता है।

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

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


2

मैं कुछ कारणों के बारे में सोच सकता हूं:

  • आदिम प्रकार की नकल करना तुच्छ है, यह आमतौर पर एक मशीन अनुदेश में अनुवाद करता है।

  • ऑब्जेक्ट को कॉपी करना तुच्छ नहीं है, ऑब्जेक्ट में ऐसे सदस्य हो सकते हैं जो स्वयं ऑब्जेक्ट हैं। सीपीयू समय और मेमोरी में वस्तुओं को कॉपी करना महंगा है। संदर्भ के आधार पर किसी वस्तु को कॉपी करने के कई तरीके हैं।

  • संदर्भ द्वारा वस्तुओं को पास करना सस्ता है और यह तब भी उपयोगी हो जाता है जब आप ऑब्जेक्ट के कई क्लाइंट के बीच ऑब्जेक्ट की जानकारी साझा / अपडेट करना चाहते हैं।

  • जटिल डेटा संरचनाओं (विशेष रूप से जो पुनरावर्ती हैं) को संकेत की आवश्यकता होती है। संदर्भ द्वारा वस्तुओं को पास करना संकेत देने वाले मार्ग का एक सुरक्षित तरीका है।


1

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


क्या यह केवल एक उथली प्रति है और अन्य वस्तुओं के वास्तविक मूल्यों और बिंदुओं को रख सकता है?
गुस्तावो कार्डसो

#Gustavo Cardoso, तो आप इस एक के माध्यम से अन्य वस्तुओं को संशोधित कर सकते हैं, क्या आप एक वस्तु से अपेक्षा करेंगे जो संदर्भ के रूप में पारित नहीं हुई है?
डेविड

0

क्योंकि जावा को एक बेहतर C ++ के रूप में डिज़ाइन किया गया था, और C # को एक बेहतर जावा के रूप में डिज़ाइन किया गया था, और इन भाषाओं के डेवलपर्स मूल रूप से टूटे हुए C ++ ऑब्जेक्ट मॉडल से थक गए थे, जिसमें ऑब्जेक्ट मूल्य प्रकार हैं।

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

यहाँ एक तुच्छ C ++ प्रोग्राम है जो समस्या को प्रदर्शित करता है:

#include <iostream> 
class Parent 
{ 
public: 
   int a;
   int b;
   int c;
   Parent(int ia, int ib, int ic) { 
      a = ia; b = ib; c = ic;
   };
   virtual void doSomething(void) { 
      std::cout << "Parent doSomething" << std::endl;
   }
};

class Child : public Parent {
public:
   int d;
   int e;
   Child(int id, int ie) : Parent(1,2,3) { 
      d = id; e = ie;
   };
   virtual void doSomething(void) {
      std::cout << "Child doSomething : D = " << d << std::endl;
   }
};

void foo(Parent a) {
   a.doSomething();
}

int main(void)
{
   Child c(4, 5);
   foo(c);
   return 0;
}

इस कार्यक्रम का आउटपुट ऐसा नहीं है जो किसी भी ओएन भाषा में समकक्ष कार्यक्रम के लिए होगा, क्योंकि आप बेस ऑब्जेक्ट की अपेक्षा किसी फ़ंक्शन के मान से व्युत्पन्न वस्तु को पारित नहीं कर सकते हैं, इसलिए संकलक एक छिपी प्रतिलिपि निर्माता बनाता है और गुजरता है चाइल्ड ऑब्जेक्ट के पेरेंट पार्ट की एक कॉपी, चाइल्ड ऑब्जेक्ट को पास करने के बजाय जैसे आपने इसे करने के लिए कहा था। इस तरह से छिपे हुए अर्थमेटिक गोच इस प्रकार हैं कि मूल्य से गुजरने वाली वस्तुओं को C ++ में टाला जाना चाहिए और लगभग हर दूसरी OO भाषा में यह संभव नहीं है।


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

OO वास्तव में पॉइंटर्स के बिना सही काम नहीं करता है
Gustavo Cardoso

-1.000000000000
पी

5
यह याद रखना महत्वपूर्ण है कि जावा पास-बाय-वैल्यू है (यह वैल्यू द्वारा ऑब्जेक्ट रेफरेंस पास करता है , जबकि प्राइमेटीज को विशुद्ध रूप से वैल्यू द्वारा पास किया जाता है)।
निकोल

3
@ पावेल शेव्ड - "दो एक से बेहतर है!" या, दूसरे शब्दों में, अपने आप को फांसी देने के लिए अधिक रस्सी।
निकोल

0

क्योंकि अन्यथा बहुरूपता नहीं होता।

OO प्रोग्रामिंग में, आप एक Derivedसे एक बड़ा वर्ग बना सकते हैं Base, और उसके बाद किसी Baseसे अपेक्षा कर सकते हैं । बहुत तुच्छ एह?

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

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

तो मनमानी लंबाई की वस्तुओं को पास करने के लिए, सबसे सरल बात यह है कि इस ऑब्जेक्ट के लिए एक पॉइंटर / संदर्भ पास किया जाए।

यह OO प्रोग्रामिंग की एक तकनीकी सीमा है।

लेकिन बड़े प्रकार के लिए, आप आमतौर पर नकल से बचने के लिए किसी भी तरह से संदर्भ पारित करना पसंद करते हैं, यह आमतौर पर एक बड़ा झटका नहीं माना जाता है :)

हालांकि, जावा या C # में एक महत्वपूर्ण परिणाम है, जब किसी ऑब्जेक्ट को किसी विधि से पास किया जाता है, तो आपको यह पता नहीं होता है कि आपकी वस्तु को विधि द्वारा संशोधित किया जाएगा या नहीं। यह डीबगिंग / समानांतर बनाता है जो कठिन है, और यह समस्या है कार्यात्मक भाषाएं और ट्रांसपेरेंशियल रेफ़रेंसी को संबोधित करने की कोशिश कर रहे हैं -> नकल करना इतना बुरा नहीं है (जब यह समझ में आता है)।


-1

जवाब नाम में है (लगभग वैसे भी)। एक संदर्भ (एक पते की तरह) बस कुछ और को संदर्भित करता है, एक मूल्य किसी और चीज की नकल है। मुझे यकीन है कि किसी ने संभवतः निम्नलिखित प्रभाव के लिए कुछ का उल्लेख किया है, लेकिन ऐसी परिस्थितियां होंगी जिनमें एक और दूसरा उपयुक्त नहीं है (मेमोरी सुरक्षा बनाम मेमोरी दक्षता)। यह स्मृति, स्मृति, मेमोरी ...... मेमोरी के प्रबंधन के बारे में है! : डी


-2

ठीक है इसलिए मैं यह नहीं कह रहा हूं कि वस्तुएं संदर्भ प्रकार क्यों हैं या संदर्भ द्वारा पारित की गई हैं, लेकिन मैं आपको एक उदाहरण दे सकता हूं कि यह लंबे समय में एक बहुत अच्छा विचार क्यों है।

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

तो इसका मतलब यह है कि आपके बच्चे के वर्ग में कुल आकार का डेटा मूल वर्ग और व्युत्पन्न वर्ग में सामान का एक संयोजन है।

ईजी: #include

class Top 
{   
    int arrTop[20] = {1,2,3,4,5,6,7,8,9,9,8,7,6,5,4,3,2,1};
};  

class Middle : Top 
{   
    int arrMiddle[20] = {1,2,3,4,5,6,7,8,9,9,8,7,6,5,4,3,2,1};
};  

class Bottom : Middle
{   
    int arrBottom[20] = {1,2,3,4,5,6,7,8,9,9,8,7,6,5,4,3,2,1};
};  

int main()
{   
    using namespace std;

    int arr[20];
    cout << "Size of array of 20 ints: " << sizeof(arr) << endl;

    Top top;
    Middle middle;
    Bottom bottom;

    cout << "Size of Top Class: " << sizeof(top) << endl;
    cout << "Size of middle Class: " << sizeof(middle) << endl;
    cout << "Size of bottom Class: " << sizeof(bottom) << endl;

}   

जो आपको दिखाएगा:

Size of array of 20 ints: 80
Size of Top Class: 80
Size of middle Class: 160
Size of bottom Class: 240

इसका मतलब यह है कि यदि आपके पास कई वर्गों की एक बड़ी पदानुक्रम है, तो ऑब्जेक्ट का कुल आकार, जैसा कि यहां घोषित किया गया है, उन सभी वर्गों का संयोजन होगा। जाहिर है, ये वस्तुएं बहुत सारे मामलों में काफी बड़ी होंगी।

मेरा मानना ​​है कि समाधान, ढेर पर बनाना और पॉइंटर्स का उपयोग करना है। इसका मतलब यह है कि कई माता-पिता के साथ कक्षाओं की वस्तुओं का आकार एक अर्थ में, प्रबंधनीय होगा।

यही कारण है कि ऐसा करने के लिए संदर्भों का उपयोग करना अधिक बेहतर तरीका होगा।


1
यह 13 से पहले किए गए 13 से अधिक जवाबों में बताए गए कुछ बिंदुओं पर पर्याप्त रूप से कुछ नहीं देता है और समझा जाता है
gnat
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.