2009-10-28 17 views
47

मैं अपने .cpp फ़ाइल का उपयोग करने के लिए अपने हेडर फ़ाइल में निरंतर char * को परिभाषित करना चाहता हूं।अपनी हेडर फ़ाइल में एक स्थिर कॉन्स char * घोषित कैसे करें?

private: 
    static const char *SOMETHING = "sommething"; 

कौन मेरा पीछा संकलक त्रुटि के साथ लाता है:: तो मैं इस की कोशिश की है

error C2864: 'SomeClass::SOMETHING' : only static const integral data members can be initialized within a class

मैं सी के लिए नया हूँ ++। यहाँ क्या हो रहा है? यह अवैध क्यों है? और आप इसे वैकल्पिक रूप से कैसे कर सकते हैं?

+1

आप "स्थिर स्थिरांक चार * स्थिरांक कुछ" का उपयोग करना चाहिए बजाय जब तक आप वास्तव में:

  • अपने संकलक पर निर्भर करता है, आप भी .cpp फ़ाइल में एक स्पष्ट परिभाषा लिखने के लिए आवश्यकता हो सकती है रनटाइम पर किसी और चीज पर इंगित करने के लिए कुछ पुनः पुन: असाइन करने में सक्षम होना चाहते हैं। – bk1e

  • उत्तर

    57

    आपको एक अनुवाद इकाई में स्थैतिक चर को परिभाषित करने की आवश्यकता है, जब तक कि वे अभिन्न प्रकार न हों।

    अपने हेडर में:

    private: 
        static const char *SOMETHING; 
        static const int MyInt = 8; // would be ok 
    

    .cpp फ़ाइल में:

    const char *YourClass::SOMETHING = "something"; 
    

    सी ++ मानक, 9.4.2/4:

    If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression. In that case, the member can appear in integral constant expressions within its scope. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.

    +0

    तो हेडर फ़ाइल में इसे असाइन करना मेरे लिए असंभव है? मैं इसे अन्य डेटाटाइप के साथ ऐसा करने में सक्षम हूं, जैसे कि ड्वॉर्ड। ऐसा क्यों है? – Mark

    +3

    क्योंकि एक सूचक एक अभिन्न प्रकार नहीं है। इंटीग्रल में केवल अंतर्निहित अंतर्निहित शामिल हैं। –

    +0

    यह मामला क्यों है? इस प्रतिबंध ने सी ++ में इस प्रतिबंध को सीमित क्यों किया है? – Mark

    15

    त्रुटि है कि आप नहीं कर सकते कक्षा के भीतर static const char* शुरू करें। आप केवल पूर्णांक चर प्रारंभ कर सकते हैं।

    // हेडर फाइल

    class Foo { 
        static const char *SOMETHING; 
        // rest of class 
    }; 
    

    // cpp फ़ाइल

    const char *Foo::SOMETHING = "sommething"; 
    

    हैं:

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

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

    +0

    आपको सीपीपी फ़ाइल में एक और "स्थिर" की आवश्यकता नहीं है। – VictorCreator

    1

    कॉन्स्टेंट प्रारंभकर्ता केवल अभिन्न या गणना प्रकारों के लिए सी ++ मानक द्वारा अनुमत है।

    If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. The member shall still be defined in a name- space scope if it is used in the program and the namespace scope definition shall not contain an initializer.

    और 9.4.2/7:

    Static data members are initialized and destroyed exactly like non-local objects (3.6.2, 3.6.3).

    तो तुम cpp फ़ाइल में कहीं लिखना चाहिए:

    const char* SomeClass::SOMETHING = "sommething"; 
    
    3

    यदि आप जानकारी के लिए 9.4.2/4 देखें विजुअल सी ++ का उपयोग करके, आप लिंकर को संकेतों का उपयोग करके गैर-पोर्टेबल रूप से ऐसा कर सकते हैं ...

    // In foo.h... 
    
    class Foo 
    { 
    public: 
        static const char *Bar; 
    }; 
    
    // Still in foo.h; doesn't need to be in a .cpp file... 
    
    __declspec(selectany) 
    const char *Foo::Bar = "Blah"; 
    

    __declspec(selectany) का मतलब है, भले ही Foo::Bar घोषित हो जाएगी कि कई वस्तु फ़ाइलों में, लिंकर केवल एक ही लेने होंगे।

    ध्यान रखें कि यह केवल माइक्रोसॉफ्ट टूलचैन के साथ काम करेगा। पोर्टेबल होने की उम्मीद मत करो।

    3

    एक चाल है जिसका उपयोग आप टेम्पलेट्स के साथ एच फाइल को केवल स्थिरांक प्रदान करने के लिए कर सकते हैं।

    (ध्यान दें, यह एक बदसूरत उदाहरण है, लेकिन कम से कम छ ++ 4.6.1। में में शब्दशः काम करता है)

    (values.hpp फ़ाइल)

    #include <string> 
    
    template<int dummy> 
    class tValues 
    { 
    public: 
        static const char* myValue; 
    }; 
    
    template <int dummy> const char* tValues<dummy>::myValue = "This is a value"; 
    
    typedef tValues<0> Values; 
    
    std::string otherCompUnit(); // test from other compilation unit 
    

    (main.cpp)

    #include <iostream> 
    #include "values.hpp" 
    
    int main() 
    { 
        std::cout << "from main: " << Values::myValue << std::endl; 
        std::cout << "from other: " << otherCompUnit() << std::endl; 
    } 
    

    (other.cpp)

    #include "values.hpp" 
    
    std::string otherCompUnit() { 
        return std::string(Values::myValue); 
    } 
    

    संकलन (उदा। other.cpp & & ./main जी ++ -ओ मुख्य main.cpp) और दो संकलन इकाइयों एक ही निरंतर एक शीर्षक में घोषित संदर्भित देखें:

    from main: This is a value 
    from other: This is a value 
    

    MSVC में, आप के बजाय का उपयोग करने में सक्षम हो सकता __declspec (selectany)

    उदाहरण के लिए:

    __declspec(selectany) const char* data = "My data"; 
    
    +0

    टेम्पलेटेड चाल गलत है। एक स्पष्ट विशेषज्ञता की कई परिभाषाएं प्रदान करना अवैध है। यह काम कर सकता है अगर संकलक इसे पकड़ने में विफल रहता है, लेकिन फिर भी यह ओडीआर का उल्लंघन है। – AnT

    +0

    दरअसल, टेम्पलेट चाल का सही कार्यान्वयन गैर-विशिष्ट घोषणा का उपयोग करेगा। – AnT

    +1

    बस एक और मामला जहां एमएस कंपाइलर सभी मानकों का पालन नहीं करता है? मुझे यह मानना ​​है कि मैंने कभी भी जीसीसी पर कोशिश नहीं की है। – Torlack

    24

    कारण है कि यह केवल अभिन्न प्रकार के साथ अनुमति दी है के बारे में ओ पी के सवाल का जवाब करने के लिए।

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

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

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

    +0

    टेम्पलेट्स को छोड़कर –

    +1

    @ म्यूइंग डक: ओडीआर का पूरा पाठ अपेक्षाकृत व्यापक है। इसमें बहुत से "अपवाद" और "अपवाद" हैं, जो "टेम्पलेट्स" तक दूरस्थ रूप से सीमित नहीं हैं। मेरा जवाब ओडीआर के एक छोटे से प्रासंगिक हिस्से तक सीमित है जो अभिन्न स्थिरांक से संबंधित है। मैं नहीं देखता कि कैसे "टेम्पलेट को छोड़कर" टिप्पणी प्रासंगिक हो सकती है (मुझे यह भी समझ में नहीं आता कि आप उस टिप्पणी से क्या मतलब रखते हैं।) – AnT

    +1

    यह सब सच है, और मैंने +1 दिया क्योंकि यह एक अच्छा जवाब है, लेकिन सभी ओडीआर नियमों के लिए टेम्पलेट वर्ग (मेरे ज्ञान के लिए) अपवाद हैं। मैंने सोचा कि मैं वहां उसमें फेंक दूंगा। –

    0

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

    यह बिल्कुल समझा नहीं जाता है कि उन्हें एक प्रकार में प्रारंभिक के रूप में क्यों अनुमति दी जाती है, लेकिन इसके बारे में अनिवार्य रूप से #define के रूप में सोचें और फिर यह वस्तु के हिस्से के रूप में नहीं बल्कि इस प्रकार के हिस्से के रूप में समझ जाएगा।

    9
    class A{ 
    public: 
        static const char* SOMETHING() { return "something"; } 
    }; 
    

    मैं इसे हर समय करता हूं - खासकर महंगा कॉन्स डिफ़ॉल्ट पैरामीटर के लिए।

    class A{ 
        static 
        const expensive_to_construct& 
        default_expensive_to_construct(){ 
         static const expensive_to_construct xp2c(whatever is needed); 
         return xp2c; 
        } 
    }; 
    
    6
    के साथ सी ++ 11

    आप constexpr कीवर्ड का उपयोग करें और अपने शीर्षक में लिख सकते हैं:

    private: 
        static constexpr const char* SOMETHING = "something"; 
    


    नोट्स:

    • constexpr बनाता SOMETHING एक निरंतर सूचक इसलिए आप

      नहीं लिख सकते
      SOMETHING = "something different"; 
      

      बाद में। ,

      constexpr const char* MyClass::SOMETHING; 
      
    संबंधित मुद्दे