language agnostic - मूल्य बनाम संदर्भ बनाम गुजरने के बीच क्या अंतर है?




language-agnostic pass-by-reference (12)

2 शर्तों को समझने से पहले, आपको निम्नलिखित समझना होगा। प्रत्येक वस्तु में 2 चीजें होती हैं जो इसे विशिष्ट बना सकती हैं।

  • इसका मूल्य
  • इसका पता

तो अगर आप Employee.name = John कहते हैं

पता है कि name बारे में 2 चीजें हैं। इसका मूल्य जो John और स्मृति में इसका स्थान भी है जो कुछ हेक्साडेसिमल संख्या है: 0x7fd5d258dd00

भाषा के आर्किटेक्चर या आपके ऑब्जेक्ट के प्रकार (वर्ग, संरचना इत्यादि) के आधार पर, आप या तो John या 0x7fd5d258dd00 स्थानांतरित 0x7fd5d258dd00

पासिंग John को मूल्य से गुजरने के रूप में माना जाता है। 0x7fd5d258dd00 पास करने के संदर्भ में गुजरने के रूप में माना जाता है। कोई भी जो इस स्मृति स्थान को इंगित कर रहा है उसे John के मूल्य तक पहुंच होगी।

इस पर अधिक जानकारी के लिए, मैं आपको एक सूचक को संदर्भित करने के बारे में पढ़ने की सलाह देता हूं और कक्षा में संरचना का चयन क्यों करता हूं

के बीच क्या अंतर है

  1. संदर्भ द्वारा पारित एक पैरामीटर
  2. मूल्य से पारित पैरामीटर?

क्या आप मुझे कुछ उदाहरण दे सकते हैं, कृपया?


इसे प्राप्त करने का सबसे आसान तरीका Excel फ़ाइल पर है। आइए उदाहरण के लिए कहें कि आपके पास कोशिकाओं ए 1 और बी 1 में दो संख्याएं, 5 और 2 हैं, और आप अपने योग को तीसरे सेल में ढूंढना चाहते हैं, आइए ए 2 कहें। आप इसे दो तरीकों से कर सकते हैं।

  • या तो इस सेल में टाइपिंग = 5 + 2 टाइप करके सेल ए 2 पर अपने मानों को पारित करके। इस मामले में, यदि कक्ष ए 1 या बी 1 के मान बदलते हैं, तो ए 2 में योग समान रहता है।

  • या कोशिकाओं ए 1 और बी 1 के सेल संदर्भों को टाइपिंग = ए 1 + बी 1 द्वारा "संदर्भ" पारित करके। इस मामले में, यदि कक्ष ए 1 या बी 1 के मान बदलते हैं, तो ए 2 में योग भी बदल जाता है।


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

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

यहाँ लिंक लिंक सी # चर्चा और उदाहरण देखें


जब संदर्भ द्वारा पैरामीटर पारित किया जाता है , तो कॉलर और कैली पैरामीटर के लिए समान चर का उपयोग करते हैं । यदि कैली पैरामीटर वैरिएबल को संशोधित करता है, तो प्रभाव कॉलर के चर के लिए दृश्यमान होता है।

जब मान द्वारा मानदंड पारित किया जाता है , तो कॉलर और कैली के समान मूल्य वाले दो स्वतंत्र चर होते हैं। यदि कैली पैरामीटर वैरिएबल को संशोधित करता है, तो कॉलर को प्रभाव दिखाई नहीं देता है।

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

अधिक स्पष्टीकरण के लिए, नीचे दिए गए अन्य उत्तरों को देखें।

नोट : लंबे समय तक, यह उत्तर कहता था:

मान लें कि मैं आपके साथ एक वेब पेज साझा करना चाहता हूं। अगर मैं आपको यूआरएल बताता हूं, तो मैं संदर्भ से गुज़र रहा हूं। आप उसी यूआरएल को देखने के लिए उस यूआरएल का उपयोग कर सकते हैं जिसे मैं देख सकता हूं। यदि वह पृष्ठ बदल गया है, तो हम दोनों परिवर्तन देखेंगे। यदि आप यूआरएल हटाते हैं, तो आप जो भी कर रहे हैं वह उस पृष्ठ के संदर्भ को नष्ट कर रहा है - आप वास्तविक पृष्ठ को स्वयं नहीं हटा रहे हैं।

यदि मैं पृष्ठ को प्रिंट करता हूं और आपको प्रिंटआउट देता हूं, तो मैं मूल्य से गुजर रहा हूं। आपका पृष्ठ मूल की डिस्कनेक्ट की गई प्रति है। आपको कोई भी आगामी परिवर्तन नहीं दिखाई देगा, और आपके द्वारा किए गए कोई भी परिवर्तन (जैसे आपके प्रिंटआउट पर स्क्रिबलिंग) मूल पृष्ठ पर दिखाई नहीं देंगे। यदि आप प्रिंटआउट को नष्ट करते हैं, तो आपने वास्तव में ऑब्जेक्ट की अपनी प्रति नष्ट कर दी है - लेकिन मूल वेब पेज बरकरार है।

यह एक साधारण सादृश्य है जिसे समझना आसान है, जिसने इस पोस्ट को सैकड़ों अपवॉट प्राप्त किए। हालांकि, समानता त्रुटिपूर्ण है: कॉल-बाय-रेफरेंस और कॉल-बाय-वैल्यू यूआरएल की तरह नहीं हैं। (सी # जैसी भाषा में एक संदर्भ प्रकार यूआरएल की तरह है; विवरण के लिए .NET में संदर्भ प्रकारों के बारे में जॉन स्कीट के महान लेखन को देखें। लेकिन संदर्भ प्रकार संदर्भ के अनुसार समान नहीं हैं।)

चूंकि यह समानता वास्तव में सही नहीं है, इसलिए इसे इस उत्तर से हटा दिया गया है। नीचे दी गई टिप्पणियां भी देखें जहां इस पर चर्चा हुई थी।


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

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


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


मूल्य से गुजरें - फ़ंक्शन चर की प्रतिलिपि बनाता है और एक प्रतिलिपि के साथ काम करता है (इसलिए यह मूल चर में कुछ भी नहीं बदलता है)

संदर्भ द्वारा पास करें - फ़ंक्शन मूल चर का उपयोग करता है, यदि आप अन्य फ़ंक्शन में चर बदलते हैं, तो यह मूल चर में भी बदल जाता है।

उदाहरण (कॉपी और उपयोग / इसे स्वयं आज़माएं और देखें):

#include <iostream>

using namespace std;

void funct1(int a){ //pass-by-value
    a = 6; //now "a" is 6 only in funct1, but not in main or anywhere else
}
void funct2(int &a){ //pass-by-reference
    a = 7; //now "a" is 7 both in funct2, main and everywhere else it'll be used
}

int main()
{
    int a = 5;

    funct1(a);
    cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 5
    funct2(a);
    cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 7

    return 0;
}

इसे सरल रखें, peeps। पाठ की दीवारें एक बुरी आदत हो सकती हैं।


यदि आप किसी फ़ंक्शन में इसे पास करने के बाद मूल चर के मान को नहीं बदलना चाहते हैं, तो फ़ंक्शन को " मान द्वारा पास करें " पैरामीटर के साथ बनाया जाना चाहिए।

फिर फ़ंक्शन केवल मूल्य ही होगा, लेकिन पारित चर के पते पर नहीं होगा। चर के पते के बिना, फ़ंक्शन के अंदर कोड फ़ंक्शन के बाहर से देखे गए वैरिएबल वैल्यू को नहीं बदल सकता है।

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


यहां एक उदाहरण दिया गया है जो मूल्य के आधार पर अंतर दर्शाता है - सूचक मूल्य - संदर्भ :

void swap_by_value(int a, int b){
    int temp;

    temp = a;
    a = b;
    b = temp;
}   
void swap_by_pointer(int *a, int *b){
    int temp;

    temp = *a;
    *a = *b;
    *b = temp;
}    
void swap_by_reference(int &a, int &b){
    int temp;

    temp = a;
    a = b;
    b = temp;
}

int main(void){
    int arg1 = 1, arg2 = 2;

    swap_by_value(arg1, arg2);
    cout << arg1 << " " << arg2 << endl;    //prints 1 2

    swap_by_pointer(&arg1, &arg2);
    cout << arg1 << " " << arg2 << endl;    //prints 2 1

    arg1 = 1;                               //reset values
    arg2 = 2;
    swap_by_reference(arg1, arg2);
    cout << arg1 << " " << arg2 << endl;    //prints 2 1
}

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

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

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

पीएस: आप मौजूदा धागे में डायलन बीट्टी के जवाब को भी देख सकते हैं जो इसे सादे शब्दों में बताता है।


यहां कई उत्तरों (और विशेष रूप से सबसे अधिक उत्साहित उत्तर) वास्तव में गलत हैं, क्योंकि वे गलत तरीके से "संदर्भ द्वारा कॉल" का अर्थ समझते हैं। यहां मामलों को सीधे सेट करने का मेरा प्रयास यहां दिया गया है।

टी एल; डॉ

सरल शब्दों में:

  • मूल्य से कॉल का मतलब है कि आप मान तर्कों के रूप में मान पास करते हैं
  • संदर्भ द्वारा कॉल का अर्थ है कि आप फ़ंक्शन तर्क के रूप में चर को पास करते हैं

रूपक शब्दों में:

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

"मूल्य द्वारा कॉल" और "संदर्भ द्वारा कॉल" का क्या अर्थ नहीं है

ध्यान दें कि इन दोनों अवधारणाएं संदर्भ प्रकारों की अवधारणा से पूरी तरह से स्वतंत्र और ऑर्थोगोनल हैं (जो जावा में सभी प्रकार हैं जो Object उपप्रकार हैं, और सी # सभी class प्रकारों में), या सी में पॉइंटर प्रकार की अवधारणा (जो हैं अर्थात् जावा के "संदर्भ प्रकार" के बराबर, बस विभिन्न वाक्यविन्यास के साथ)।

संदर्भ प्रकार की धारणा एक यूआरएल से मेल खाती है: यह दोनों ही जानकारी का एक टुकड़ा है, और यह एक संदर्भ है (एक सूचक , यदि आप करेंगे) अन्य जानकारी के लिए। आप विभिन्न स्थानों पर एक यूआरएल की कई प्रतियां प्राप्त कर सकते हैं, और वे नहीं बदलते कि वे किस वेबसाइट से लिंक करते हैं; यदि वेबसाइट अपडेट की जाती है तो प्रत्येक यूआरएल प्रतिलिपि अभी भी अपडेट की गई जानकारी का नेतृत्व करेगी। इसके विपरीत, किसी भी स्थान पर यूआरएल को बदलने से यूआरएल की किसी अन्य लिखित प्रति को प्रभावित नहीं होगा।

ध्यान दें कि सी ++ में "संदर्भ" (जैसे int& ) की धारणा है जो जावा और सी # के "संदर्भ प्रकार" जैसी नहीं है , लेकिन "संदर्भ द्वारा कॉल करें" की तरह है। जावा और सी # के "संदर्भ प्रकार", और पाइथन में सभी प्रकार, सी और सी ++ कॉल "पॉइंटर प्रकार" (जैसे int* ) की तरह हैं।

ठीक है, यहां लंबा और अधिक औपचारिक स्पष्टीकरण है।

शब्दावली

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

शुरू करने के लिए, फ़ंक्शन घोषणा की कुछ सी-जैसी भाषा में एक उदाहरण दिया गया है:

void foo(int param) {  // line 1
  param += 1;
}

और यहां इस फ़ंक्शन को कॉल करने का एक उदाहरण दिया गया है:

void bar() {
  int arg = 1;  // line 2
  foo(arg);     // line 3
}

इस उदाहरण का उपयोग करके, मैं शब्दावली के कुछ महत्वपूर्ण बिट्स को परिभाषित करना चाहता हूं:

  • foo लाइन 1 पर घोषित एक फ़ंक्शन है (जावा सभी फ़ंक्शंस विधियों को बनाने पर जोर देता है, लेकिन अवधारणा सामान्यता के नुकसान के बिना समान है; सी और सी ++ घोषणा और परिभाषा के बीच एक अंतर बनाती है जिसे मैं यहां नहीं जाऊंगा)
  • param foo को औपचारिक पैरामीटर है, जिसे लाइन 1 पर भी घोषित किया गया है
  • arg एक चर है , विशेष रूप से फ़ंक्शन bar का एक स्थानीय चर , जिसे घोषित किया गया है और लाइन 2 पर प्रारंभ किया गया है
  • तर्क लाइन 3 पर foo विशिष्ट आमंत्रण के लिए भी एक तर्क है

यहां अंतर करने के लिए अवधारणाओं के दो बहुत ही महत्वपूर्ण सेट हैं। पहला वैरिएबल बनाम वैरिएबल है :

  • एक मूल्य भाषा में अभिव्यक्ति का मूल्यांकन करने का परिणाम है । उदाहरण के लिए, ऊपर दिए गए bar फ़ंक्शन में, लाइन int arg = 1; अभिव्यक्ति arg में मान 1
  • एक चर वैल्यू के लिए एक कंटेनर है । एक चर परिवर्तनीय हो सकता है (यह अधिकांश सी-जैसी भाषाओं में डिफ़ॉल्ट है), केवल पढ़ने के लिए (उदाहरण के लिए जावा के final या सी # के readonly का उपयोग करके घोषित) या गहराई से अपरिवर्तनीय (उदाहरण के लिए सी ++ के const )।

अंतर करने के लिए अवधारणाओं की अन्य महत्वपूर्ण जोड़ी पैरामीटर बनाम तर्क है :

  • एक पैरामीटर (जिसे औपचारिक पैरामीटर भी कहा जाता है) एक चर होता है जिसे फ़ंक्शन कॉल करते समय कॉलर द्वारा आपूर्ति की जानी चाहिए।
  • एक तर्क एक मान है जो फ़ंक्शन के कॉलर द्वारा उस फ़ंक्शन के विशिष्ट औपचारिक पैरामीटर को पूरा करने के लिए प्रदान किया जाता है

मूल्य से कॉल करें

मूल्य से कॉल में , फ़ंक्शन के औपचारिक पैरामीटर चर होते हैं जिन्हें फ़ंक्शन आमंत्रण के लिए नव निर्मित किया जाता है, और जिन्हें उनके तर्कों के मानों के साथ प्रारंभ किया जाता है।

यह वैसे ही काम करता है कि किसी अन्य प्रकार के चर मूल्यों के साथ आरंभ किए जाते हैं। उदाहरण के लिए:

int arg = 1;
int another_variable = arg;

यहां another_variable और another_variable पूरी तरह से स्वतंत्र चर हैं - उनके मूल्य एक-दूसरे से स्वतंत्र रूप से बदल सकते हैं। हालांकि, उस बिंदु पर जहां एक another_variable घोषित किया गया है, यह उसी मूल्य को पकड़ने के लिए शुरू किया गया है जो arg रखता है - जो 1

चूंकि वे स्वतंत्र चर हैं, another_variable परिवर्तन another_variable को प्रभावित नहीं करते हैं:

int arg = 1;
int another_variable = arg;
another_variable = 2;

assert arg == 1; // true
assert another_variable == 2; // true

यह उपरोक्त हमारे उदाहरण में arg और param बीच संबंध के समान ही है, जिसे मैं समरूपता के लिए यहां दोहरा दूंगा:

void foo(int param) {
  param += 1;
}

void bar() {
  int arg = 1;
  foo(arg);
}

यह ठीक है जैसे हमने कोड को इस तरह लिखा था:

// entering function "bar" here
int arg = 1;
// entering function "foo" here
int param = arg;
param += 1;
// exiting function "foo" here
// exiting function "bar" here

यही है, मूल्य के आधार पर कॉल की परिभाषा विशेषता यह है कि कैली (इस मामले में foo ) मानों को तर्क के रूप में प्राप्त करता है, लेकिन कॉलर के चर (इस मामले में bar ) से उन मानों के लिए अपने स्वयं के अलग-अलग चर होते हैं।

उपरोक्त मेरे रूपक पर वापस जाकर, यदि मैं bar हूं और आप foo , जब मैं आपको कॉल करता हूं, तो मैं आपको कागज़ का एक टुकड़ा उस पर लिखे गए मान के साथ सौंपता हूं। आप पेपर param टुकड़े को बुलाते हैं। यह मान एक वैरिएबल I कॉल arg में, मेरी नोटबुक (मेरे स्थानीय चर) में लिखे गए मान की एक प्रति है।

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

संदर्भ द्वारा कॉल करें

संदर्भ द्वारा कॉल में , फ़ंक्शन के औपचारिक पैरामीटर केवल वही चर के लिए नए नाम होते हैं जिन्हें कॉलर तर्क के रूप में आपूर्ति करता है।

ऊपर हमारे उदाहरण पर वापस जाकर, यह बराबर है:

// entering function "bar" here
int arg = 1;
// entering function "foo" here
// aha! I note that "param" is just another name for "arg"
arg /* param */ += 1;
// exiting function "foo" here
// exiting function "bar" here

चूंकि param लिए सिर्फ एक और नाम है - यानी, वे एक ही चर हैं , param परिवर्तन param में परिलक्षित होते हैं। यह मौलिक तरीका है जिसमें संदर्भ द्वारा कॉल मूल्य से कॉल से भिन्न होता है।

बहुत कम भाषा संदर्भ द्वारा कॉल का समर्थन करती हैं, लेकिन सी ++ इसे इस तरह से कर सकती है:

void foo(int& param) {
  param += 1;
}

void bar() {
  int arg = 1;
  foo(arg);
}

इस मामले में, param पास तर्क के समान मूल्य नहीं है, यह वास्तव में arg (केवल एक अलग नाम से) और इसलिए bar देख सकता है कि arg गया है।

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

अनुपूरक: वस्तु साझाकरण द्वारा कॉल करें

यदि आपके पास मूल्य से कॉल किया गया है , लेकिन वास्तविक मान संदर्भ प्रकार या सूचक प्रकार है , तो "मान" स्वयं बहुत रोचक नहीं है (उदाहरण के लिए सी में यह केवल प्लेटफॉर्म-विशिष्ट आकार का पूर्णांक है) - क्या है रोचक यह है कि वह मूल्य क्या इंगित करता है

यदि वह संदर्भ प्रकार (यानी, पॉइंटर) बिंदु को उत्परिवर्तनीय है तो एक दिलचस्प प्रभाव संभव है: आप बिंदु-मूल्य को संशोधित कर सकते हैं, और कॉलर बिंदु-मूल्य में परिवर्तन देख सकता है, भले ही कॉलर निरीक्षण नहीं कर सकता सूचक में ही बदल जाता है।

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

बारबरा लिस्कोव, जब उन्होंने सीएलयू प्रोग्रामिंग भाषा का आविष्कार किया (जिसमें इन अर्थशास्त्र थे), एहसास हुआ कि मौजूदा शब्द "मूल्य से कॉल करें" और "संदर्भ द्वारा कॉल" इस नई भाषा के अर्थशास्त्र का वर्णन करने के लिए विशेष रूप से उपयोगी नहीं थे। इसलिए उसने एक नया शब्द आविष्कार किया: ऑब्जेक्ट शेयरिंग द्वारा कॉल करें

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


संक्षेप में, मूल्य से गुजरना यह है कि संदर्भ में यह कहां है और पास किया गया है, जहां यह है।

यदि आपका मूल्य VAR1 = "हैप्पी गाय!" है, तो आपको केवल "हैप्पी गाय" दिखाई देगा। यदि VAR1 "हैप्पी गैल" में बदल जाता है, तो आप उसे नहीं जान पाएंगे। यदि यह संदर्भ द्वारा पारित किया गया है, और VAR1 परिवर्तन, आप करेंगे।


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

संदर्भ के अनुसार: जब तर्क संदर्भ द्वारा पारित किए जाते हैं, तो इसका अर्थ यह है कि वास्तविक चर के लिए संदर्भ या पॉइंटर विधि को पारित किया जा रहा है, न कि वास्तविक चर डेटा।

आगे के उदाहरणों के लिए इस article को article





pass-by-value