यह C ++ में क्विकर / फीचर है। यद्यपि हम संदर्भों के प्रकारों के बारे में नहीं सोचते हैं, वे वास्तव में प्रकार प्रणाली में "बैठते हैं"। हालांकि यह अजीब लगता है (यह देखते हुए कि जब संदर्भ का उपयोग किया जाता है, तो संदर्भ शब्दार्थ स्वचालित रूप से होता है और संदर्भ "रास्ते से बाहर हो जाता है"), कुछ बचाव योग्य कारण हैं कि संदर्भों को एक अलग विशेषता के रूप में सिस्टम में टाइप करने के बजाय एक अलग विशेषता के रूप में क्यों बनाया गया है? प्रकार।
सबसे पहले, आइए विचार करें कि घोषित नाम की प्रत्येक विशेषता प्रकार प्रणाली में नहीं होनी चाहिए। सी भाषा से, हमारे पास "भंडारण वर्ग", और "लिंकेज" है। एक नाम के रूप में पेश किया जा सकता है extern const int ri
, जहां extern
स्थिर भंडारण वर्ग और लिंकेज की उपस्थिति को इंगित करता है। प्रकार बस है const int
।
C ++ स्पष्ट रूप से इस धारणा को स्वीकार करता है कि अभिव्यक्तियों में ऐसी विशेषताएँ हैं जो टाइप सिस्टम के बाहर हैं। भाषा में अब "मूल्य वर्ग" की अवधारणा है जो गैर-प्रकार की विशेषताओं की बढ़ती संख्या को व्यवस्थित करने का एक प्रयास है जो एक अभिव्यक्ति का प्रदर्शन कर सकती है।
फिर भी संदर्भ प्रकार हैं। क्यों?
यह सी ++ ट्यूटोरियल ऐसे ही एक घोषणा में समझाया जा करने के लिए इस्तेमाल const int &ri
की शुरुआत की ri
प्रकार होने के रूप में const int
है, लेकिन संदर्भ अर्थ विज्ञान। वह संदर्भ शब्दार्थ एक प्रकार का नहीं था; यह केवल नाम और भंडारण स्थान के बीच एक असामान्य संबंध का संकेत देने वाला एक प्रकार का गुण था। इसके अलावा, यह तथ्य कि संदर्भ प्रकार नहीं हैं, का उपयोग इस बात को तर्कसंगत बनाने के लिए किया गया था कि आप संदर्भों के आधार पर प्रकारों का निर्माण क्यों नहीं कर सकते हैं, भले ही प्रकार निर्माण वाक्यविन्यास इसकी अनुमति देता हो। उदाहरण के लिए, सरणियों या बिंदुओं के संदर्भ में संभव नहीं होने के लिए: const int &ari[5]
और const int &*pri
।
लेकिन वास्तव में संदर्भ हैं प्रकार के और इतने decltype(ri)
कुछ संदर्भ प्रकार नोड जो अयोग्य है प्राप्त करता है। इस प्रकार के पेड़ के साथ अंतर्निहित प्रकार प्राप्त करने के लिए आपको इस नोड को पिछले हिस्से में उतरना होगा remove_reference
।
जब आप उपयोग करते हैं ri
, तो संदर्भ पारदर्शी रूप से हल हो जाता है, ताकि ri
"जैसा दिखता है और जैसा महसूस होता है i
" और इसे इसके लिए "उपनाम" कहा जा सके। प्रकार प्रणाली में, हालांकि, ri
वास्तव में एक प्रकार है जो " संदर्भ const int
" है।
संदर्भ प्रकार क्यों हैं?
विचार करें कि यदि संदर्भ प्रकार नहीं थे , तो इन कार्यों को एक ही प्रकार माना जाएगा:
void foo(int);
void foo(int &);
यह केवल उन कारणों के लिए नहीं हो सकता है जो बहुत अधिक स्पष्ट हैं। यदि उनके पास एक ही प्रकार होता है, तो इसका मतलब है कि या तो घोषणा या तो परिभाषा के लिए उपयुक्त होगी, और इसलिए प्रत्येक (int)
फ़ंक्शन को एक संदर्भ लेने के लिए संदेह करना होगा।
इसी प्रकार, यदि संदर्भ प्रकार नहीं थे, तो ये दो श्रेणी की घोषणाएं समान होंगी:
class foo {
int m;
};
class foo {
int &m;
};
एक घोषणा इकाई के लिए एक घोषणा का उपयोग करना सही होगा, और दूसरी घोषणा का उपयोग करने के लिए उसी कार्यक्रम में एक और अनुवाद इकाई।
तथ्य यह है कि एक संदर्भ के कार्यान्वयन में अंतर होता है और इसे उस प्रकार से अलग करना असंभव है, क्योंकि C ++ में टाइप को एक इकाई के कार्यान्वयन के साथ करना है: बोलने के लिए बिट्स में इसका "लेआउट"। यदि दो फ़ंक्शन एक ही प्रकार के हैं, तो उन्हें एक ही बाइनरी कॉलिंग सम्मेलनों के साथ लागू किया जा सकता है: एबीआई एक ही है। यदि दो संरचनाओं या वर्गों में एक ही प्रकार है, तो उनका लेआउट समान है और साथ ही सभी सदस्यों तक पहुंच के शब्दार्थ भी हैं। संदर्भों की उपस्थिति प्रकार के इन पहलुओं को बदल देती है, और इसलिए यह उन्हें सीधे प्रकार के सिस्टम में शामिल करने का एक सीधा डिजाइन निर्णय है। (हालांकि, यहां एक प्रतिवाद पर ध्यान दें: एक संरचना / वर्ग का सदस्य हो सकता है static
, जो प्रतिनिधित्व को भी बदलता है; फिर भी वह प्रकार नहीं है।)
इस प्रकार, संदर्भ प्रकार में हैं प्रणाली "द्वितीय श्रेणी के नागरिक" (आईएसओ सी में कार्यों और सरणियों के विपरीत नहीं)। कुछ ऐसी चीजें हैं जो हम संदर्भों के साथ "नहीं" कर सकते हैं, जैसे कि संदर्भकर्ताओं को संदर्भों की घोषणा करना, या उनमें से सरणियाँ। लेकिन इसका मतलब यह नहीं है कि वे टाइप नहीं हैं। वे सिर्फ एक तरह से टाइप नहीं हैं कि यह समझ में आता है।
ये सभी द्वितीय श्रेणी-प्रतिबंध आवश्यक नहीं हैं। यह देखते हुए कि संदर्भों की संरचनाएं हैं, संदर्भों की सरणियाँ हो सकती हैं! उदाहरण के लिए
int x = 0, y = 0;
int &ar[2] = { x, y };
यह सिर्फ C ++ में लागू नहीं है, बस इतना ही। संदर्भ के लिए संकेत बिल्कुल भी समझ में नहीं आते हैं, क्योंकि एक संदर्भ से उठाया गया एक संकेतक सिर्फ संदर्भित वस्तु पर जाता है। संदर्भों की कोई सरणियाँ नहीं होने का संभावित कारण यह है कि सी ++ लोग एरे को सी से विरासत में मिली एक प्रकार की निम्न-स्तरीय विशेषता मानते हैं, जो कई प्रकार से टूटी हुई है जो अपूरणीय है, और वे एरेज़ को स्पर्श नहीं करना चाहते हैं। कुछ भी नया करने का आधार। संदर्भों के सरणियों का अस्तित्व, हालांकि, इस बात का स्पष्ट उदाहरण देगा कि संदर्भों को किस प्रकार का होना चाहिए।
गैर- const
परिवर्तनीय प्रकार: आईएसओ C90 में भी पाया जाता है!
कुछ जवाब इस तथ्य पर इशारा कर रहे हैं कि संदर्भ एक const
क्वालीफायर नहीं लेते हैं । यह बल्कि एक लाल हेरिंग है, क्योंकि घोषणा const int &ri = i
भी एक अयोग्य संदर्भ बनाने का प्रयास नहीं कर रही है const
: यह एक कास्ट-योग्य प्रकार (जो स्वयं नहीं है const
) का संदर्भ है । जैसे const in *ri
किसी चीज को पॉइंटर घोषित करता है const
, लेकिन वह पॉइंटर खुद नहीं है const
।
यह कहा, यह सच है कि संदर्भ const
खुद को क्वालीफायर नहीं ले जा सकते हैं।
फिर भी, यह इतना विचित्र नहीं है। यहां तक कि आईएसओ सी 90 भाषा में, सभी प्रकार नहीं हो सकते हैं const
। अर्थात्, सरणियाँ नहीं हो सकतीं।
सबसे पहले, सिंटैक्स एक कॉन्स्टेंट ऐरे को घोषित करने के लिए मौजूद नहीं है: int a const [42]
गलत है।
हालांकि, उपरोक्त घोषणा क्या करने की कोशिश कर रही है एक मध्यवर्ती के माध्यम से व्यक्त किया जा सकता है typedef
:
typedef int array_t[42];
const array_t a;
लेकिन यह ऐसा नहीं करता जैसा दिखता है। इस घोषणा में, यह नहीं है a
जो हो जाता है const
योग्य है, लेकिन तत्वों! यह कहना है, a[0]
एक है const int
, लेकिन a
सिर्फ "int की सरणी" है। नतीजतन, इसके लिए निदान की आवश्यकता नहीं है:
int *p = a;
यह करता है:
a[0] = 1;
फिर, यह इस विचार को रेखांकित करता है कि संदर्भ कुछ प्रकार से "द्वितीय श्रेणी" में हैं, जैसे कि सरणियाँ।
ध्यान दें कि अनुरूप कैसे अधिक गहराई से पकड़ता है, क्योंकि सरणियों में भी एक "अदृश्य रूपांतरण व्यवहार" होता है, जैसे संदर्भ। प्रोग्रामर के बिना किसी भी स्पष्ट ऑपरेटर का उपयोग करने के लिए, पहचानकर्ता a
स्वचालित रूप से एक int *
सूचक में बदल जाता है , जैसे कि अभिव्यक्ति &a[0]
का उपयोग किया गया था। यह कैसे एक संदर्भ के अनुरूप है ri
, जब हम इसे एक प्राथमिक अभिव्यक्ति के रूप में उपयोग करते हैं, तो जादुई रूप से उस वस्तु i
को दर्शाता है जिसके लिए वह बाध्य है। यह "सरणी से सूचक क्षय" की तरह एक और "क्षय" है।
और जैसे हम "सरणी से पॉइंटर" के क्षय को गलत तरीके से सोचने में भ्रमित नहीं होना चाहिए कि "सरणियां सी और सी ++ में सिर्फ संकेत हैं", वैसे ही हमें यह नहीं सोचना चाहिए कि संदर्भ केवल उपनाम हैं जिनका अपना कोई प्रकार नहीं है।
जब decltype(ri)
संदर्भ के सामान्य रूपांतरण को उसके संदर्भ वस्तु में sizeof a
दबा दिया जाता है, तो यह सरणी-से-पॉइंटर रूपांतरण को दबाने से अलग नहीं होता है , और इसके आकार की गणना करने के लिए सरणी प्रकार पर ही काम करता है ।
boolalpha(cout)
बहुत ही असामान्य है। आपstd::cout << boolalpha
इसके बजाय कर सकते हैं ।