2012-12-18 28 views
6

मैं इस धारणा का था कि सी ++ static const अभिन्न प्रकार पर पर भले ही नामस्थान स्कोप पर घोषित किया गया हो या कक्षा/संरचना/संघ के भीतर घोषित किया गया हो।सी ++ स्थिर कॉन्स अभिन्न प्रकारों पर कौन से विशेष नियम लागू होते हैं?

अब मैं सोच रहा हूं कि मुझे गैर-अनुपालन कंपाइलर्स द्वारा खराब चीजें सिखाई गई हैं।

static const int A = 1; 

struct s 
{ 
    static const int A = 1; 
}; 
दायरे में स्पष्ट अंतर से

अलावा, A और s::A क्या अंतर है?

  • ... जब उनका उपयोग उनके शाब्दिक मूल्य के साथ बदल दिया जाएगा?
  • ... जब मैं इसका पता ले सकता हूं?
  • ... जब मुझे उन्हें अलग से परिभाषित करने की आवश्यकता है?

मैं उत्सुक विशेष रूप से सी ++ के बारे में 03.

+0

आपको क्यों लगता है कि कोई अंतर है? विशेष उपचार यह है कि उन्हें निरंतर अभिव्यक्ति माना जा सकता है। "शाब्दिक मूल्य के साथ प्रतिस्थापन" के संदर्भ में मत सोचो। – Pubby

+1

@ पब्बी 'const int और x = s :: ए;' इसके बाद, और कहीं भी 'x' का उपयोग करें। संभावना है कि आपको एक लिंकर त्रुटि मिलेगी। – hvd

उत्तर

6

कीवर्ड static वर्ग गुंजाइश में और नाम स्थान दायरे में एक ही बात का मतलब यह नहीं कर रहा हूँ। वास्तव में, इसका नाम नेमस्पेस स्कोप में उपयोग किया जाता है बहिष्कृत है।

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

नामस्थान स्कोप पर एक चर घोषित करते समय, static का अर्थ है कि नाम बाहरी के बजाय आंतरिक संबंध है; या static के बिना, घोषणा एक परिभाषा है (इसलिए प्रोग्राम में कोई अन्य परिभाषा नहीं होनी चाहिए)। सी ++ 03 में, यह उपयोग बहिष्कृत किया गया था; इसके बजाय अनाम नामस्थान का उपयोग करें। नोट भी कि यदि चर स्वयं const (शीर्ष स्तर का स्थिरांक) है, तो में डिफ़ॉल्ट रूप से आंतरिक संबंध होता है, इसलिए static में प्रभाव नहीं है। कैसे करते हैं (आप बाहरी लिंकेज के साथ एक const चर जरूरत है, यह एक वर्ग के सदस्य यह एक परिभाषा बनाने के लिए एक प्रारंभकर्ता का उपयोग कर, बल्कि सिर्फ एक घोषणा से बनाने के लिए, या परिभाषित यह स्पष्ट रूप से extern,।)

+0

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

+0

@ जॉन 5342 मैंने सोचा कि मैंने उन पंक्तियों के साथ कुछ सुना होगा। मुझे थोड़ा सा इच्छा-धोना लगता है: बहिष्कृत करें, फिर अव्यवस्थित करें। अगली चीज़ जो हम जानते हैं, वे 'निर्यात' और 'std :: auto_ptr' को पुनर्स्थापित कर देंगे। –

+0

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

0

A और s::A अलग हैं?

सबसे बड़ा अंतर यह है कि A की घोषणा भी एक परिभाषा है, जबकि s::A की है कि नहीं है। मुझे यकीन नहीं है कि "विशेष नियम" से आपका क्या मतलब है, लेकिन प्रत्येक मामले में static का एक अलग अर्थ है।

नामस्थान स्कोप पर, यह आंतरिक लिंक देता है ताकि ऑब्जेक्ट वर्तमान अनुवाद इकाई के बाहर दिखाई न दे। ध्यान दें कि static यहां अनावश्यक है, क्योंकि नामस्थान स्कोप पर निरंतर चर के डिफ़ॉल्ट रूप से आंतरिक संबंध हैं।

कक्षा के दायरे में, इसका मतलब है कि कक्षा के किसी भी तत्कालता से स्वतंत्र एक वस्तु है।

जब उनका उपयोग उनके शाब्दिक मूल्य के साथ बदल दिया जाएगा?

के बाद से दोनों घोषणा में एक initialiser साथ अभिन्न स्थिरांक हैं, दोनों लगातार भाव में इस्तेमाल किया जा सकता है, और संकलक संकलन समय स्थिरांक साथ उनके मूल्यों को बदलने के लिए सक्षम है।

शायद एक और उचित सवाल यह है कि एक परिभाषा कब आवश्यक है?

सी ++ 11 में, यह आवश्यक है यदि परिवर्तक odr-used - मोटे तौर पर बोल रहा है, यदि आप ऐसा कुछ करते हैं जिसके लिए इसके मूल्य के बजाय चर के पते की आवश्यकता होती है।

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

जब मैं इसका पता ले सकता हूं?

उस चर को सी ++ 03 और सी ++ 11 में परिभाषा की आवश्यकता होती है। परिभाषा चर के लिए भंडारण आवंटित करती है, ताकि उसके पास पता हो।

जब मुझे उन्हें अलग से परिभाषित करने की आवश्यकता है?

नेमस्पेस स्कोप पर एक परिवर्तनीय घोषणा भी एक परिभाषा है, जब तक कि आप इसे extern घोषित न करें; तो आपके पहले चर को एक अलग परिभाषा की आवश्यकता नहीं है।

कक्षा के दायरे में एक परिवर्तनीय घोषणा परिभाषा नहीं है; इसलिए आपके दूसरे चर को C++ 03 में एक अलग परिभाषा की आवश्यकता होती है, और सी ++ 11 में यदि यह odr-used है।