c++ - सी++ में निजी स्थिर सदस्यों को कैसे प्रारंभ करें?




सी++ प्रोग्राम्स (11)

PrivateStatic.cpp फ़ाइल में भी काम कर रहा है:

#include <iostream>

using namespace std;

class A
{
private:
  static int v;
};

int A::v = 10; // possible initializing

int main()
{
A a;
//cout << A::v << endl; // no access because of private scope
return 0;
}

// g++ privateStatic.cpp -o privateStatic && ./privateStatic

C ++ में एक निजी, स्थिर डेटा सदस्य प्रारंभ करने का सबसे अच्छा तरीका क्या है? मैंने इसे अपने हेडर फ़ाइल में करने की कोशिश की, लेकिन यह मुझे अजीब लिंकर त्रुटियां देता है:

class foo
{
    private:
        static int i;
};

int foo::i = 0;

मुझे लगता है कि ऐसा इसलिए है क्योंकि मैं कक्षा के बाहर से एक निजी सदस्य को शुरू नहीं कर सकता। तो ऐसा करने का सबसे अच्छा तरीका क्या है?


आपके द्वारा सामना की जाने वाली लिंकर समस्या शायद इस कारण है:

  • हेडर फ़ाइल में कक्षा और स्थिर सदस्य परिभाषा दोनों प्रदान करना,
  • इस हेडर को दो या दो से अधिक स्रोत फ़ाइलों में शामिल करना।

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

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

class Foo
{
    // int& getObjectInstance() const {
    static int& getObjectInstance() {
        static int object;
        return object;
    }

    void func() {
        int &object = getValueInstance();
        object += 5;
    }
};

एक चर के लिए :

foo.h:

class foo
{
private:
    static int i;
};

foo.cpp:

int foo::i = 0;

ऐसा इसलिए है क्योंकि आपके प्रोग्राम में केवल foo::i का एक उदाहरण हो सकता है। यह एक शीर्ष फ़ाइल में extern int i के बराबर है और int i एक स्रोत फ़ाइल में int i

निरंतर के लिए आप सीधे कक्षा घोषणा में मूल्य डाल सकते हैं:

class foo
{
private:
    static int i;
    const static int a = 42;
};

कक्षा घोषणा हेडर फ़ाइल में होनी चाहिए (या स्रोत फ़ाइल में साझा नहीं होने पर)।
फ़ाइल: foo.h

class foo
{
    private:
        static int i;
};

लेकिन प्रारंभिक स्रोत फ़ाइल में होना चाहिए।
फ़ाइल: foo.cpp

int foo::i = 0;

यदि प्रारंभिक हेडर फ़ाइल में है तो प्रत्येक फ़ाइल जिसमें हेडर फ़ाइल शामिल है, में स्थिर सदस्य की परिभाषा होगी। इस प्रकार लिंक चरण के दौरान आपको लिंकर त्रुटियां मिलेंगी क्योंकि चर को प्रारंभ करने के लिए कोड एकाधिक स्रोत फ़ाइलों में परिभाषित किया जाएगा।

नोट: मैट कर्टिस: बताता है कि सी ++ उपर्युक्त के सरलीकरण की अनुमति देता है यदि स्थैतिक सदस्य चर स्थिरांक प्रकार (जैसे int , bool , char ) का है। फिर आप शीर्षलेख फ़ाइल में कक्षा घोषणा के अंदर सीधे सदस्य चर घोषित कर सकते हैं और प्रारंभ कर सकते हैं:

class foo
{
    private:
        static int const i = 42;
};

जब मैं पहली बार इसका सामना करना पड़ा तो मैं बस थोड़ा अजीब बात करना चाहता था।

मुझे एक टेम्पलेट वर्ग में एक निजी स्थैतिक डेटा सदस्य शुरू करने की आवश्यकता थी।

.h या .hpp में, यह टेम्पलेट क्लास के स्थिर डेटा सदस्य को प्रारंभ करने के लिए ऐसा कुछ दिखता है:

template<typename T>
Type ClassName<T>::dataMemberName = initialValue;

माइक्रोसॉफ्ट कंपाइलर [1] के साथ, स्थैतिक चर जो अंतर- __declspec(selectany) , को हेडर फ़ाइल में भी परिभाषित किया जा सकता है, लेकिन क्लास घोषणा के बाहर, Microsoft विशिष्ट __declspec(selectany) का उपयोग करके।

class A
{
    static B b;
}

__declspec(selectany) A::b;

ध्यान दें कि मैं यह नहीं कह रहा कि यह अच्छा है, मैं बस इतना कहता हूं कि यह किया जा सकता है।

[1] इन दिनों, एमएससी समर्थन __declspec(selectany) से कम कंपाइलर - कम से कम जीसीसी और __declspec(selectany) । शायद और भी।


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

#include <stdio.h>

class Foo
{
   public:

     int   GetMyStaticValue () const {  return MyStatic();  }
     int & GetMyStaticVar ()         {  return MyStatic();  }
     static bool isMyStatic (int & num) {  return & num == & MyStatic(); }

   private:

      static int & MyStatic ()
      {
         static int mStatic = 7;
         return mStatic;
      }
};

int main (int, char **)
{
   Foo obj;

   printf ("mystatic value %d\n", obj.GetMyStaticValue());
   obj.GetMyStaticVar () = 3;
   printf ("mystatic value %d\n", obj.GetMyStaticValue());

   int valMyS = obj.GetMyStaticVar ();
   int & iPtr1 = obj.GetMyStaticVar ();
   int & iPtr2 = valMyS;

   printf ("is my static %d %d\n", Foo::isMyStatic(iPtr1), Foo::isMyStatic(iPtr2));
}

यह आउटपुट

mystatic value 7
mystatic value 3
is my static 1 0

यदि आप कुछ यौगिक प्रकार (fe स्ट्रिंग) को प्रारंभ करना चाहते हैं तो आप ऐसा कुछ कर सकते हैं:

class SomeClass {
  static std::list<string> _list;

  public:
    static const std::list<string>& getList() {
      struct Initializer {
         Initializer() {
           // Here you may want to put mutex
           _list.push_back("FIRST");
           _list.push_back("SECOND");
           ....
         }
      }
      static Initializer ListInitializationGuard;
      return _list;
    }
};

जैसा कि ListInitializationGuard SomeClass::getList() विधि के अंदर एक स्थिर चर है, इसे केवल एक बार बनाया जाएगा, जिसका अर्थ है कि निर्माता को एक बार बुलाया जाता है। यह आपको आवश्यक मूल्य के लिए initialize _list चर initialize _list करेगा। getList को getList करने के बाद कोई भी कॉल पहले ही प्रारंभिक _list ऑब्जेक्ट को वापस कर देगा।

निश्चित रूप से आपको getList() विधि को कॉल करके हमेशा _list ऑब्जेक्ट तक पहुंच प्राप्त _list


सी ++ 17 के बाद से, स्थिर सदस्यों को इनलाइन कीवर्ड के साथ शीर्षलेख में परिभाषित किया जा सकता है।

http://en.cppreference.com/w/cpp/language/static

"एक स्थैतिक डेटा सदस्य को इनलाइन घोषित किया जा सकता है। एक इनलाइन स्थैतिक डेटा सदस्य को कक्षा परिभाषा में परिभाषित किया जा सकता है और एक डिफ़ॉल्ट सदस्य प्रारंभकर्ता निर्दिष्ट कर सकता है। इसे कक्षा के बाहर की परिभाषा की आवश्यकता नहीं है:"

struct X
{
    inline static int n = 1;
};

set_default() विधि के बारे में क्या?

class foo
{
    public:
        static void set_default(int);
    private:
        static int i;
};

void foo::set_default(int x) {
    i = x;
}

हमें केवल set_default(int x) विधि का उपयोग करना होगा और हमारे static चर प्रारंभ किए जाएंगे।

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


int foo::i = 0; 

चर को प्रारंभ करने के लिए सही वाक्यविन्यास है, लेकिन इसे शीर्षलेख के बजाय स्रोत फ़ाइल (.cpp) में जाना चाहिए।

क्योंकि यह एक स्थिर चर है क्योंकि संकलक को इसकी केवल एक प्रति बनाने की आवश्यकता है। आपके पास एक पंक्ति "int foo: i" है जहां आपके कोड में कंपाइलर को यह कहने के लिए कहां रखा जाए अन्यथा आपको एक लिंक त्रुटि मिलती है। यदि वह हेडर में है तो आपको प्रत्येक फ़ाइल में एक प्रति प्राप्त होगी जिसमें हेडर शामिल है, इसलिए लिंकर से परिभाषित प्रतीक त्रुटियों को गुणा करें।





static-members