पहले हमें मूल्य और संदर्भ से गुजरने का मतलब है।
जावा और एसएमएल जैसी भाषाओं के लिए, मूल्य से पास सीधा है (और संदर्भ से कोई पास नहीं है), जैसा कि एक चर मूल्य की नकल है, जैसा कि सभी चर सिर्फ स्केलर हैं और बिलिन कॉपी अर्थ हैं: वे या तो क्या हैं जो अंकगणित की गणना करते हैं C ++, या "संदर्भ" (विभिन्न नाम और वाक्यविन्यास के साथ संकेत) में टाइप करें।
C में हमारे पास स्केलर और उपयोगकर्ता परिभाषित प्रकार हैं:
- स्केलरों का एक संख्यात्मक या सार मान होता है (संकेत संख्या नहीं हैं, उनका एक सार मान है) जो कॉपी किया गया है।
- अलग-अलग प्रकारों में उनके सभी संभवतः प्रारंभिक सदस्यों की प्रतिलिपि बनाई गई है:
- उत्पाद प्रकारों (सरणियों और संरचनाओं) के लिए: पुनरावर्ती रूप से, सरणियों की संरचना और तत्वों के सभी सदस्यों की प्रतिलिपि बनाई जाती है (सी फ़ंक्शन सिंटैक्स सीधे मान द्वारा सरणियों को पारित करना संभव नहीं बनाता है, केवल एक संरचना के सदस्यों को गिरफ्तार करता है, लेकिन यह एक विवरण है )।
- सम प्रकार (यूनियनों) के लिए: "सक्रिय सदस्य" का मूल्य संरक्षित है; स्पष्ट रूप से, सदस्य प्रति द्वारा सदस्य क्रम में नहीं है क्योंकि सभी सदस्यों को प्रारंभ नहीं किया जा सकता है।
सी ++ में उपयोगकर्ता परिभाषित प्रकारों में उपयोगकर्ता परिभाषित कॉपी अर्थ हो सकते हैं, जो अपने संसाधनों के स्वामित्व और "गहरी कॉपी" संचालन के साथ वस्तुओं के साथ "ऑब्जेक्ट ओरिएंटेड" वास्तव में प्रोग्रामिंग को सक्षम करते हैं। ऐसे मामले में, एक कॉपी ऑपरेशन वास्तव में एक फ़ंक्शन के लिए एक कॉल है जो लगभग मनमाना संचालन कर सकता है।
C ++ के रूप में संकलित C संरचनाओं के लिए, "कॉपी करना" को अभी भी उपयोगकर्ता परिभाषित कॉपी ऑपरेशन (या तो कंस्ट्रक्टर या असाइनमेंट ऑपरेटर) के रूप में परिभाषित किया गया है, जो संकलक द्वारा उत्पन्न होते हैं। इसका अर्थ है कि C / C ++ के सामान्य सबसेट प्रोग्राम का शब्दार्थ C और C ++ में भिन्न है: C में एक संपूर्ण समुच्चय प्रकार की प्रतिलिपि बनाई गई है, C ++ में प्रत्येक सदस्य को कॉपी करने के लिए एक अंतर्निहित उत्पन्न प्रतिलिपि फ़ंक्शन को कहा जाता है; अंतिम परिणाम यह है कि किसी भी मामले में प्रत्येक सदस्य की नकल की जाती है।
(एक अपवाद है, मुझे लगता है, जब एक संघ के अंदर एक संरचना की नकल की जाती है।)
तो एक वर्ग प्रकार के लिए, एक नया उदाहरण बनाने का एकमात्र तरीका (बाहरी प्रतियां) एक कंस्ट्रक्टर (यहां तक कि तुच्छ संकलित उत्पन्न कंस्ट्रक्टर वाले लोगों के लिए) के माध्यम से है।
आप एक परिचालक के माध्यम से असमान संचालक का पता नहीं लगा सकते हैं, &
लेकिन इसका मतलब यह नहीं है कि कोई रव्यू ऑब्जेक्ट नहीं है; और एक वस्तु, परिभाषा से, एक पता है ; और उस पते को एक सिंटैक्स निर्माण द्वारा भी दर्शाया गया है: वर्ग प्रकार की एक वस्तु केवल एक निर्माता द्वारा बनाई जा सकती है, और इसमें एक this
संकेतक है; लेकिन तुच्छ प्रकारों के लिए, कोई उपयोगकर्ता लिखित रचनाकार नहीं है, इसलिए this
प्रतिलिपि बनाए जाने और नाम दिए जाने तक कोई जगह नहीं है ।
अदिश प्रकार के लिए, किसी वस्तु का मूल्य वस्तु का लकीर है, वस्तु में संग्रहीत शुद्ध गणितीय मूल्य।
एक वर्ग प्रकार के लिए, ऑब्जेक्ट के मूल्य की एकमात्र धारणा ऑब्जेक्ट की एक और कॉपी है, जिसे केवल एक कॉपी कंस्ट्रक्टर द्वारा बनाया जा सकता है, एक वास्तविक फ़ंक्शन (हालांकि तुच्छ प्रकार के लिए जो फ़ंक्शन इतना विशेष रूप से तुच्छ है, ये कभी-कभी हो सकते हैं। कंस्ट्रक्टर को कॉल किए बिना बनाया गया)। इसका मतलब है कि वस्तु का मूल्य एक निष्पादन द्वारा वैश्विक कार्यक्रम राज्य के परिवर्तन का परिणाम है । यह गणितीय रूप से एक्सेस नहीं करता है।
तो मूल्य से गुजरना वास्तव में कोई बात नहीं है: यह कॉपी कंस्ट्रक्टर कॉल से गुजरता है , जो कम सुंदर है। प्रतिलिपि निर्माता से अपेक्षा की जाती है कि वह वस्तु के प्रकार के उचित शब्दार्थ के अनुसार अपने आंतरिक आवेगों (जो कि अमूर्त उपयोगकर्ता गुण हैं, आंतरिक C ++ गुण नहीं) का उचित अर्थ के अनुसार एक समझदार "कॉपी" ऑपरेशन करेगा।
किसी कक्षा वस्तु के मान से गुजरने का अर्थ है:
- एक और उदाहरण बनाएँ
- उसके बाद उस फंक्शन पर कॉल फंक्शन एक्ट करें।
ध्यान दें कि समस्या का इस बात से कोई लेना-देना नहीं है कि प्रतिलिपि स्वयं किसी पते वाली वस्तु है: सभी फ़ंक्शन पैरामीटर ऑब्जेक्ट हैं और एक पता (भाषा शब्दार्थ स्तर पर) है।
मुद्दा यह है कि:
- प्रतिलिपि मूल वस्तु के शुद्ध गणितीय मूल्य (सच्चा शुद्ध अंतराल) के साथ एक नई वस्तु है , जैसा कि स्केलर के साथ;
- या कॉपी मूल वस्तु का मूल्य है , जैसे कक्षाओं के साथ।
एक तुच्छ वर्ग प्रकार के मामले में, आप अभी भी मूल की सदस्य प्रति के सदस्य को परिभाषित कर सकते हैं, इसलिए आपको प्रतिलिपि संचालन (कॉपी कंस्ट्रक्टर और असाइनमेंट) की तुच्छता के कारण मूल के शुद्ध अंतराल को परिभाषित करना होगा। मनमाने ढंग से विशेष उपयोगकर्ता कार्यों के साथ ऐसा नहीं है: मूल का एक मूल्य एक निर्मित प्रति होना है।
क्लास ऑब्जेक्ट्स को कॉलर द्वारा निर्मित किया जाना चाहिए; एक निर्माणकर्ता के पास औपचारिक रूप से एक this
संकेतक होता है, लेकिन औपचारिकता यहां प्रासंगिक नहीं है: सभी वस्तुओं का औपचारिक रूप से एक पता होता है, लेकिन केवल वे जो वास्तव में अपना पता गैर विशुद्ध रूप से स्थानीय तरीकों *&i = 1;
से उपयोग करते हैं (इसके विपरीत विशुद्ध रूप से स्थानीय उपयोग का पता है) को अच्छी तरह से परिभाषित करने की आवश्यकता है पता।
किसी ऑब्जेक्ट को पते से बिल्कुल पास होना चाहिए, अगर उसे इन दोनों अलग-अलग संकलित कार्यों में एक पता होना चाहिए:
void callee(int &i) {
something(&i);
}
void caller() {
int i;
callee(i);
something(&i);
}
यहां तक कि अगर something(address)
कोई शुद्ध कार्य या मैक्रो या जो भी (जैसे printf("%p",arg)
) है जो पते को संग्रहीत नहीं कर सकता है या किसी अन्य इकाई से संवाद नहीं कर सकता है, तो हमें पते से गुजरने की आवश्यकता है क्योंकि पता एक अनूठी वस्तु के लिए अच्छी तरह से परिभाषित किया जाना चाहिए int
जो एक अद्वितीय है पहचान।
हम यह नहीं जानते हैं कि कोई बाहरी कार्य इसके लिए दिए गए पतों की अवधि में "शुद्ध" होगा।
यहाँ संभावित या तो एक गैर तुच्छ निर्माता या नाशक में पता की एक वास्तविक उपयोग के लिए फोन करने वाले पक्ष पर शायद सुरक्षित, साधारण मार्ग ले रहे हैं और वस्तु फोन करने वाले इसके पते को एक पहचान देने के लिए और पारित, के रूप में के लिए कारण है यह बनाता है सुनिश्चित करें कि निर्माण में और विध्वंसक के बाद कंस्ट्रक्टर में इसके पते का कोई भी गैर तुच्छ उपयोग सुसंगत है : this
वस्तु के अस्तित्व पर समान होना चाहिए।
किसी अन्य फ़ंक्शन की तरह एक गैर तुच्छ कंस्ट्रक्टर या डिस्ट्रक्टर, this
पॉइंटर को इस तरह से उपयोग कर सकता है कि इसके मूल्य पर निरंतरता की आवश्यकता होती है, भले ही गैर-तुच्छ सामान के साथ कुछ वस्तु न हो:
struct file_handler { // don't use that class!
file_handler () { this->fileno = -1; }
file_handler (int f) { this->fileno = f; }
file_handler (const file_handler& rhs) {
if (this->fileno != -1)
this->fileno = dup(rhs.fileno);
else
this->fileno = -1;
}
~file_handler () {
if (this->fileno != -1)
close(this->fileno);
}
file_handler &operator= (const file_handler& rhs);
};
ध्यान दें कि उस स्थिति में, एक पॉइंटर (स्पष्ट सिंटैक्स this->
) के स्पष्ट उपयोग के बावजूद , ऑब्जेक्ट पहचान अप्रासंगिक है: कंपाइलर इसे स्थानांतरित करने और "कॉपी एलीसन" करने के लिए ऑब्जेक्ट को अच्छी तरह से कॉपी कर सकता है। यह this
विशेष सदस्य कार्यों के उपयोग की "शुद्धता" के स्तर पर आधारित है (पता नहीं बचता है)।
लेकिन शुद्धता मानक घोषणा स्तर पर उपलब्ध विशेषता नहीं है (संकलक एक्सटेंशन मौजूद हैं जो गैर इनलाइन फ़ंक्शन घोषणा पर शुद्धता विवरण जोड़ते हैं), इसलिए आप कोड की शुद्धता के आधार पर एक एबीआई को परिभाषित नहीं कर सकते हैं जो उपलब्ध नहीं हो सकता है (कोड हो सकता है या नहीं) इनलाइन नहीं हो सकता है और विश्लेषण के लिए उपलब्ध है)।
पवित्रता को "निश्चित रूप से शुद्ध" या "अशुद्ध या अज्ञात" के रूप में मापा जाता है। सामान्य जमीन, या ऊपरी सीमांतिकी (वास्तव में अधिकतम), या एलसीएम (कम से कम कॉमन मल्टीपल) "अज्ञात" है। तो एबीआई अनजान पर बैठ जाता है।
सारांश:
- कुछ निर्माणों को वस्तु पहचान को परिभाषित करने के लिए संकलक की आवश्यकता होती है।
- ABI को कार्यक्रमों के वर्गों के रूप में परिभाषित किया गया है, न कि ऐसे विशिष्ट मामलों को जिन्हें अनुकूलित किया जा सकता है।
भविष्य के संभावित कार्य:
क्या शुद्धता एनोटेशन सामान्यीकृत और मानकीकृत होने के लिए पर्याप्त उपयोगी है?