C ++ और Java दोनों "संदर्भ" की धारणा का उपयोग क्यों करते हैं लेकिन एक ही अर्थ में नहीं?


26

C ++ में एक फ़ंक्शन के लिए एक संदर्भ तर्क फ़ंक्शन को संदर्भ को कुछ और करने के लिए संदर्भित करने की अनुमति देता है:

int replacement = 23;

void changeNumberReference(int& reference) {
    reference = replacement;
}

int main() {
    int i = 1;
    std::cout << "i=" << i << "\n"; // i = 1;
    changeNumberReference(i);
    std::cout << "i=" << i << "\n"; // i = 23;
}

यदि हम संदर्भ को बदलने का प्रयास करते हैं, तो फलस्वरूप, फ़ंक्शन के लिए एक निरंतर संदर्भ तर्क एक संकलन समय त्रुटि को फेंक देगा:

void changeNumberReference(const int& reference) {
    reference = replacement; // compile-time error: assignment of read-only reference 'reference'
}

अब, जावा के साथ, डॉक्स कहते हैं कि गैर-आदिम प्रकारों के कार्य तर्क संदर्भ हैं। आधिकारिक डॉक्स से उदाहरण:

public void moveCircle(Circle circle, int deltaX, int deltaY) {
    // code to move origin of circle to x+deltaX, y+deltaY
    circle.setX(circle.getX() + deltaX);
    circle.setY(circle.getY() + deltaY);

    // code to assign a new reference to circle
    circle = new Circle(0, 0);
}

फिर सर्कल को x = y = 0. के साथ एक नई सर्कल ऑब्जेक्ट का एक संदर्भ सौंपा गया है। इस पुनर्मूल्यांकन में कोई स्थायित्व नहीं है, हालांकि, संदर्भ मूल्य द्वारा पारित किया गया था और बदल नहीं सकता है।

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

यह C ++ पॉइंटर्स के व्यवहार में अधिक समान है। आप इसे पॉइंटेड ऑब्जेक्ट वैल्यू को बदलने के लिए उपयोग कर सकते हैं, लेकिन आप किसी फ़ंक्शन में पॉइंटर के मान को बदल नहीं सकते हैं। इसके अलावा, C ++ पॉइंटर्स के साथ (लेकिन C ++ संदर्भों के साथ नहीं), जावा में आप इस तरह के तर्क के लिए "null" मान के रूप में पास कर सकते हैं।

तो मेरा सवाल है: जावा "संदर्भ" की धारणा का उपयोग क्यों करता है? क्या यह समझा जाए कि वे C ++ संदर्भों से मिलते-जुलते नहीं हैं? या क्या वे वास्तव में सी ++ संदर्भ से मिलते जुलते हैं और मुझे कुछ याद आ रहा है?


10
ध्यान दें कि आपके पहले C ++ उदाहरण में, आप "कुछ और करने के लिए बिंदु" संदर्भ नहीं बना रहे हैं। इसके बजाय, आप चर के मान को संदर्भ बिंदुओं में बदल रहे हैं। यह वैचारिक रूप से उस वस्तु की स्थिति को बदलने के समान है जिसे जावा संदर्भ के साथ संदर्भित किया जाता है,
Xion

@Xion yep, अब जब मैंने आपकी टिप्पणी पढ़ ली है तो मैं देख रहा हूं कि आपका क्या मतलब है और आप जो कहते हैं उसके 98% से सहमत हैं :) जावा में समस्या यह है कि आपको वैचारिक रूप से वस्तु की किसी भी और सभी स्थिति तक पहुंच होनी चाहिए। सी + + प्राप्त करें जो आपको संदर्भ को कुछ अन्य संदर्भ के मूल्य को निर्धारित करने देता है।
शिवन ड्रैगन

जवाबों:


48

क्यूं कर? क्योंकि, हालांकि, संपूर्ण शब्दावली आम तौर पर पूरे पेशे के लिए अच्छी होती है, भाषा डिजाइनर हमेशा अन्य भाषा डिजाइनरों के भाषा उपयोग का सम्मान नहीं करते हैं, खासकर अगर उन अन्य भाषाओं को प्रतियोगियों के रूप में माना जाता है।

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

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

इसका परिणाम यह है कि दोनों भाषाएं एक ही अस्पष्ट शब्द का उपयोग दो अलग-अलग चीजों के लिए करती हैं, जिनमें से दोनों को अधिक विशिष्ट नाम से लाभ हो सकता है, लेकिन दोनों में से किसी के जल्द ही प्रतिस्थापित होने की संभावना नहीं है। प्राकृतिक भाषा, कभी-कभी निराशाजनक भी हो सकती है!


7
धन्यवाद, C ++ संदर्भों को "एलियासेस" (समान मूल्य / उदाहरण के लिए) और जावा संदर्भों के रूप में "नैस्टियर लो-लेवल ऑपरेशंस के बिना पॉइंटर्स (कास्टिंग, जोड़ना ...) के रूप में सोच" वास्तव में मेरे लिए चीजों को स्पष्ट करता है।
शिवन ड्रैगन

14
जावा में संकेत नहीं हैं, और इस पर गर्व है, इसलिए शब्द के रूप में "पॉइंटर" का उपयोग करना कोई विकल्प नहीं था। क्या NullPointerExceptionया इस तथ्य के बारे में कि जेएलएस शब्द "पॉइंटर" का उपयोग करता है?
टोबियास ब्रांड

7
@TobiasBrandt: NullPointerExceptionएक पॉइंटर नहीं है, लेकिन यह एक ऐसा अपवाद है जो यह दर्शाता है कि, निचले स्तर पर, एक NULL पॉइंटर को पारित / निष्क्रिय कर दिया गया था। का उपयोग करते हुए Pointerएक अपवाद के हिस्से के रूप में कुछ भी करता है, तो, बुरा छवि वे have.The JLS में जोड़ता है , संकेत का उल्लेख क्योंकि जावा के वीएम मुख्य रूप से एक भाषा में लिखा गया था कि उन्हें का उपयोग करता है। आप
इंटर्ल्स

3
@TobiasBrandt: जावा सभी जगह पॉइंटर्स का उपयोग करता है; ढेर वस्तुओं को किसी ऐसी चीज के माध्यम से संदर्भित किया जाता है जो सभी व्यावहारिक उद्देश्यों के लिए एक सूचक है। यह सिर्फ इतना है कि जावा प्रोग्रामर को पॉइंटर प्रकार के किसी भी ऑपरेशन को उजागर नहीं करता है।
जॉन बोडे

2
मैं जावा / .NET संदर्भों के लिए "ऑब्जेक्ट आईडी" शब्द पसंद करता हूं। बिट स्तर पर, ऐसी चीजों को आमतौर पर एक पॉइंटर के समान कुछ के रूप में लागू किया जा सकता है, लेकिन कुछ भी नहीं होना चाहिए। यह महत्वपूर्ण है कि एक वस्तु आईडी में किसी वस्तु को पहचानने के लिए किसी भी प्रकार की जानकारी हो, जिसमें फ्रेमवर्क / वीएम की जरूरत हो।
सुपरकैट

9

एक संदर्भ एक ऐसी चीज़ है जो दूसरी चीज़ को संदर्भित करता है। विभिन्न भाषाओं ने "संदर्भ" शब्द को अधिक विशिष्ट अर्थ दिया है, आमतौर पर "सभी बुरे पहलुओं के बिना एक सूचक की तरह कुछ"। C ++ एक विशिष्ट अर्थ बताता है, जैसा कि जावा या पर्ल करता है।

C ++ में, संदर्भ उपनाम की तरह अधिक होते हैं (जो एक पॉइंटर के माध्यम से लागू किया जा सकता है)। यह संदर्भ या तर्क से पास होने की अनुमति देता है

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


6

यह काफी हद तक वापस अल्गोल 68 तक चला जाता है, और आंशिक रूप से सी के रूप में सीर्स को परिभाषित करता है।

अल्गोल 68 ने एक अवधारणा को परिभाषित किया जिसे संदर्भ कहा जाता है। यह पास्कल में एक संकेतक के रूप में (एक उदाहरण के लिए) बहुत अधिक था। यह एक सेल था जिसमें NIL या कुछ निर्दिष्ट प्रकार के कुछ अन्य सेल का पता था। आप एक संदर्भ के लिए असाइन कर सकते हैं, इसलिए एक संदर्भ एक समय में एक सेल को संदर्भित कर सकता है, और पुन: असाइन किए जाने के बाद एक अलग सेल। हालांकि, यह C या C ++ पॉइंटर अंकगणित के अनुरूप कुछ भी समर्थन नहीं करता था ।

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

उदाहरण के लिए, एक घोषणा की तरह INT j := 7;वास्तव में संकलक द्वारा एक घोषणा की तरह व्यवहार किया गया था REF INT j = NEW LOC INT := 7। इसलिए, जो आपने अल्गोल 68 में घोषित किया था, वह सामान्य रूप से एक संदर्भ था, जिसे तब कुछ संदर्भित करने के लिए आरंभीकृत किया गया था, जो कि ढेर पर आवंटित किया गया था, और जो कि (निर्दिष्ट रूप से) कुछ निर्दिष्ट मान शामिल करने के लिए प्रारंभिक था। जावा के विपरीत, हालांकि, उन्होंने कम से कम आपको इसके लिए सिन सिंटैक्स बनाए रखने की कोशिश की, बजाय इसके कि लगातार चीज़ों को रखने foo bar = new foo();या "हमारे संकेत बिंदु नहीं हैं।"

पास्कल और इसके अधिकांश वंशज (प्रत्यक्ष और ... आध्यात्मिक दोनों) ने अल्गोल 68 संदर्भ अवधारणा का नाम बदलकर "पॉइंटर" कर दिया, लेकिन अवधारणा को अनिवार्य रूप से वही रखा: एक सूचक एक चर था जिसे या तो रखा गया था nil, या आपके द्वारा आवंटित किसी चीज का पता। ढेर पर (यानी, कम से कम जैसा कि मूल रूप से जेन्सेन और विर्थ द्वारा परिभाषित किया गया था, कोई "एड्रेस-ऑफ" ऑपरेटर नहीं था, इसलिए एक पॉइंटर के लिए सामान्य रूप से परिभाषित चर को संदर्भित करने का कोई तरीका नहीं था)। "पॉइंटर्स" होने के बावजूद, किसी भी पॉइंटर अंकगणित का समर्थन नहीं किया गया था।

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

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

हालांकि यह कुछ अलग तरीके से निकला, सी ++ लगभग एक ही समस्या से घिरा हुआ था: शब्द "पॉइंटर" पहले से ही जाना और समझा गया था, इसलिए उन्हें इस अलग चीज के लिए एक अलग शब्द की आवश्यकता थी जो वे जोड़ रहे थे जो किसी और चीज के लिए भेजा गया था, लेकिन अन्यथा काफी था जो लोग "पॉइंटर" का मतलब समझते थे, उससे थोड़ा अलग है। इसलिए, भले ही यह Algol 68 संदर्भ से अलग है, फिर भी उन्होंने "संदर्भ" शब्द का फिर से उपयोग किया।


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

0

'संदर्भ प्रकार' की धारणा एक सामान्य है, यह एक पॉइंटर और एक संदर्भ (सी ++ के संदर्भ में) दोनों को व्यक्त कर सकता है, जैसा कि 'मूल्य प्रकार' के विपरीत है। जावा के संदर्भ वास्तव में ->एक *डेरेफ़रिंग के सिंटैक्टिक ओवरहेड के बिना संकेत हैं । यदि आप C ++ में JVM के कार्यान्वयन को देखते हैं, तो वे वास्तव में नंगे पॉइंटर्स हैं। इसके अलावा, C # में जावा के समान संदर्भों की धारणा है, लेकिन इसमें फ़ंक्शन मापदंडों पर पॉइंटर्स और 'रेफरी' क्वालिफायर भी हैं, जो संदर्भ द्वारा मूल्य-प्रकार पास करने और &सी ++ की तरह कॉपी करने से बचने की अनुमति देते हैं ।


यह उत्तर पहले के उत्तर से भिन्न / बेहतर कैसे है?
जन्नत
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.