यदि मैं इसे स्पष्ट रूप से नहीं करता तो C ++ वर्ग के सदस्यों को कैसे आरंभ किया जाता है?


158

मान लीजिए मैं निजी सदस्य ही साथ एक वर्ग है ptr, name, pname, rname, crnameऔर age। यदि मैं उन्हें स्वयं प्रारंभ नहीं करता तो क्या होगा? यहाँ एक उदाहरण है:

class Example {
    private:
        int *ptr;
        string name;
        string *pname;
        string &rname;
        const string &crname;
        int age;

    public:
        Example() {}
};

और फिर मैं:

int main() {
    Example ex;
}

पूर्व में सदस्यों को कैसे आरंभ किया जाता है? संकेत के साथ क्या होता है? क्या करें stringऔर intडिफ़ॉल्ट निर्माणकर्ताओं के साथ 0-intialized करें string()और int()? संदर्भ सदस्य के बारे में क्या? इसके अलावा कास्ट संदर्भों के बारे में क्या?

मुझे और क्या जानना चाहिए?

क्या कोई ऐसे ट्यूटोरियल को जानता है जो इन मामलों को कवर करता है? शायद कुछ किताबों में? मेरे पास बहुत सी ++ पुस्तकों के लिए विश्वविद्यालय के पुस्तकालय में पहुंच है।

मैं इसे सीखना चाहता हूं ताकि मैं बेहतर (बग फ्री) प्रोग्राम लिख सकूं। किसी भी प्रतिक्रिया में मदद मिलेगी!


3
पुस्तक सिफारिशों के लिए, stackoverflow.com/questions/388242/…
माइक सेमोर

माइक, ओउ, मेरा मतलब है कि किसी किताब से अध्याय जो इसे समझाता है। पूरी किताब नहीं! :)
बॉडासिडो

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

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

2
@TylerMcHenry सी ++ पर कौन सी किताबें "अच्छा" मानते हैं? मैंने C ++ पर कई किताबें पढ़ी हैं, लेकिन उनमें से किसी ने भी इसे पूरी तरह से नहीं समझाया है। जैसा कि मेरी पिछली टिप्पणी में उल्लेख किया गया है, स्कॉट मेयर्स ने प्रभावी C ++ में पूर्ण नियमों को प्रदान करने के लिए स्पष्ट रूप से गिरावट दर्ज की है । मैंने मेयर्स की प्रभावी मॉडर्न C ++ , डेहर्स्ट्स C ++ कॉमन नॉलेज और स्ट्रॉस्ट्रुप की A Tour of C ++ भी पढ़ी है । मेरी स्मृति में, उनमें से किसी ने भी पूरा नियम नहीं समझाया। जाहिर है मैं मानक पढ़ सकता था, लेकिन मैं शायद ही इस बात पर विचार करूंगा कि एक "अच्छी किताब"! : D और मुझे उम्मीद है कि Stroustrup शायद इसे C ++ प्रोग्रामिंग लैंग्वेज में समझाएगा ।
काइल स्ट्रैंड

जवाबों:


206

स्पष्ट आरंभीकरण के एवज में, वर्गों में सदस्यों का आरंभीकरण कार्यों में स्थानीय चरों के आरंभीकरण के लिए समान रूप से काम करता है।

के लिए वस्तुओं , उनके डिफ़ॉल्ट निर्माता कहा जाता है। उदाहरण के लिए, std::stringडिफ़ॉल्ट रूप से, डिफ़ॉल्ट निर्माता इसे एक रिक्त स्ट्रिंग पर सेट करता है। यदि ऑब्जेक्ट की क्लास में डिफॉल्ट कंस्ट्रक्टर नहीं है, तो स्पष्ट रूप से इसे इनिशियलाइज़ न करने पर यह एक कंपाइल एरर होगा।

के लिए आदिम प्रकार (संकेत, ints, आदि), वे कर रहे हैं नहीं प्रारंभ - वे होते हैं जो कुछ भी मनमाने ढंग से कबाड़ पहले कि स्मृति स्थान पर हुआ।

के लिए संदर्भ (जैसे std::string&), यह है अवैध उन्हें प्रारंभ करने में नहीं है, और अपने संकलक शिकायत और इस तरह के कोड को संकलित करने के लिए मना कर दिया जाएगा। संदर्भों को हमेशा आरंभीकृत किया जाना चाहिए।

इसलिए, आपके विशिष्ट मामले में, यदि वे स्पष्ट रूप से आरंभिक नहीं हैं:

    int *ptr;  // Contains junk
    string name;  // Empty string
    string *pname;  // Contains junk
    string &rname;  // Compile error
    const string &crname;  // Compile error
    int age;  // Contains junk

4
+1। यह ध्यान देने योग्य है कि, सख्त मानक परिभाषा द्वारा, विभिन्न प्रकार की अन्य चीजों (किसी भी क्षेत्र का भंडारण) के साथ आदिम प्रकार के उदाहरणों को सभी माना जाता है
stinky472

7
"यदि ऑब्जेक्ट की क्लास में डिफॉल्ट कंस्ट्रक्टर नहीं है, तो यह एक कंपाइल एरर होगा यदि आप इसे स्पष्ट रूप से इनिशियलाइज़ नहीं करते हैं" तो यह गलत है ! यदि किसी क्लास में डिफॉल्ट कंस्ट्रक्टर नहीं है, तो उसे डिफॉल्ट डिफॉल्ट कंस्ट्रक्टर दिया जाता है जो खाली है।
जादूगर

19
@ मुझे लगता है कि उनका शाब्दिक अर्थ है 'यदि वस्तु में डिफ़ॉल्ट निर्माता नहीं है' जैसा कि कोई भी उत्पन्न नहीं है, तो ऐसा तब होगा जब वर्ग स्पष्ट रूप से डिफ़ॉल्ट के अलावा किसी भी निर्माता को परिभाषित करता है (कोई डिफ़ॉल्ट ctor उत्पन्न नहीं होगा)। यदि हमें बहुत अधिक पांडित्य है, तो हम शायद मदद से अधिक भ्रमित करेंगे और टायलर इससे पहले अपनी प्रतिक्रिया में इस बारे में एक अच्छी बात करता है।
13:27 पर बदबूदार 472

8
@ wiz-loz मैं कहूंगा कि fooएक कंस्ट्रक्टर है, यह सिर्फ निहित है। लेकिन यह वास्तव में शब्दार्थ का एक तर्क है।
टायलर मैकहेनरी

4
मैं "डिफॉल्ट कंस्ट्रक्टर" की व्याख्या एक कंस्ट्रक्टर के रूप में करता हूं जिसे बिना तर्क के कहा जा सकता है। यह या तो आप स्वयं को परिभाषित करेंगे या संकलक द्वारा उत्पन्न किया जाएगा। तो इसका अभाव, का अर्थ है न तो स्वयं द्वारा परिभाषित और न ही उत्पन्न। या कि मैं इसे कैसे देखता हूं।
5

28

सबसे पहले, मैं समझाता हूं कि मेम-इनिशियलाइज़र-सूची क्या है। एक मेम-प्रारंभकर्ता-सूची की एक अल्पविराम द्वारा पृथक सूची है मेम-प्रारंभकर्ता रों है, जहां प्रत्येक मेम-प्रारंभकर्ता एक सदस्य नाम होता है (, एक के बाद अभिव्यक्ति की सूची , एक के बाद )अभिव्यक्ति-सूची कैसे सदस्य का निर्माण किया जाता है। उदाहरण के लिए, में

static const char s_str[] = "bodacydo";
class Example
{
private:
    int *ptr;
    string name;
    string *pname;
    string &rname;
    const string &crname;
    int age;

public:
    Example()
        : name(s_str, s_str + 8), rname(name), crname(name), age(-4)
    {
    }
};

उपयोगकर्ता- प्रदायक की मेम-इनिशियल-लिस्ट , नो-आर्ग्युमेंट्स कंस्ट्रक्टर है name(s_str, s_str + 8), rname(name), crname(name), age(-4)। इस मेमरी-इनिशियलाइज़र-लिस्ट का अर्थ है कि nameसदस्य को कंस्ट्रक्टर द्वारा इनिशियलाइज़ किया गया है std::stringजो दो इनपुट पुनरावृत्तियों को लेता है , rnameसदस्य को एक संदर्भ के साथ आरंभीकृत किया जाता है name, crnameसदस्य को एक कॉन्सर्ट-रेफ़रेंस के साथ आरंभीकृत किया जाता है name, और ageसदस्य को इनिशियलाइज़ किया जाता है -4

प्रत्येक कंस्ट्रक्टर की अपनी मेम-इनिशियल-लिस्ट होती है , और सदस्यों को केवल एक निर्धारित क्रम में शुरू किया जा सकता है (मूल रूप से वह क्रम जिसमें सदस्यों को वर्ग में घोषित किया जाता है)। इस प्रकार, के सदस्यों Exampleकर सकते हैं केवल क्रम में प्रारंभ: ptr, name, pname, rname, crname, और age

जब आप किसी सदस्य का मेम-इनिशियलाइज़र निर्दिष्ट नहीं करते हैं , तो C ++ मानक कहता है:

यदि इकाई एक नॉनस्टैटिक डेटा सदस्य है ... वर्ग प्रकार की ..., तो इकाई डिफ़ॉल्ट-आरंभिक (8.5) है। ... अन्यथा, इकाई आरंभिक नहीं है।

यहाँ, क्योंकि nameक्लास प्रकार का एक नॉनस्टैटिक डेटा सदस्य है, यह डिफ़ॉल्ट-इनिशियलाइज़्ड है यदि कोई इनिशियलाइज़र मेम-इनिशियलाइज़र-सूचीname में निर्दिष्ट नहीं किया गया था । अन्य सभी सदस्यों के पास वर्ग का प्रकार नहीं है, इसलिए वे आरंभिक नहीं हैं।Example

जब मानक कहता है कि वे आरंभिक नहीं हैं, तो इसका मतलब है कि उनका कोई भी मूल्य हो सकता है । इस प्रकार, क्योंकि उपरोक्त कोड ने प्रारंभ नहीं किया था pname, यह कुछ भी हो सकता है।

ध्यान दें कि आपको अभी भी अन्य नियमों का पालन करना है, जैसे कि नियम जो संदर्भों को हमेशा आरंभीकृत किया जाना चाहिए। संदर्भों को प्रारंभ नहीं करना एक संकलक त्रुटि है।


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

12

आप उस बिंदु पर डेटा सदस्यों को इनिशियलाइज़ कर सकते हैं जिसे आप उन्हें घोषित करते हैं:

class another_example{
public:
    another_example();
    ~another_example();
private:
    int m_iInteger=10;
    double m_dDouble=10.765;
};

मैं इस फॉर्म का बहुत विशेष रूप से उपयोग करता हूं, हालांकि मैंने पढ़ा है कि कुछ लोग इसे 'खराब रूप' मानते हैं, शायद इसलिए क्योंकि यह केवल हाल ही में पेश किया गया था - मुझे लगता है कि सी ++ 11 में। मेरे लिए यह अधिक तार्किक है।

नए नियमों के लिए एक और उपयोगी पहलू यह है कि डेटा-सदस्यों को कैसे प्रारंभ किया जाए जो स्वयं कक्षाएं हैं। उदाहरण के लिए मान लीजिए कि CDynamicStringयह एक ऐसा वर्ग है जो स्ट्रिंग हैंडलिंग को इनकैप्सुलेट करता है। इसमें एक कंस्ट्रक्टर है जो आपको इसके प्रारंभिक मूल्य को निर्दिष्ट करने की अनुमति देता है CDynamicString(wchat_t* pstrInitialString)। आप इस वर्ग को किसी अन्य वर्ग के अंदर डेटा सदस्य के रूप में अच्छी तरह से उपयोग कर सकते हैं - ऐसा वर्ग कहें जो विंडोज़ रजिस्ट्री मान को अलग करता है जो इस स्थिति में एक डाक पते को संग्रहीत करता है। रजिस्ट्री कुंजी का नाम 'हार्ड कोड' के लिए, जिसमें लिखा गया है कि आप ब्रेसिज़ का उपयोग करते हैं:

class Registry_Entry{
public:
    Registry_Entry();
    ~Registry_Entry();
    Commit();//Writes data to registry.
    Retrieve();//Reads data from registry;
private:
    CDynamicString m_cKeyName{L"Postal Address"};
    CDynamicString m_cAddress;
};

ध्यान दें कि दूसरा स्ट्रिंग वर्ग जो वास्तविक डाक पते को रखता है उसके पास एक इनिशियलाइज़र नहीं है, इसलिए इसके डिफ़ॉल्ट निर्माता को निर्माण पर बुलाया जाएगा - शायद स्वचालित रूप से इसे एक रिक्त स्ट्रिंग पर सेट करना।


9

यदि आप उदाहरण देते हैं कि स्टैक पर क्लास को तत्काल किया जाता है, तो असिंचित स्केलर सदस्यों की सामग्री यादृच्छिक और अपरिभाषित होती है।

वैश्विक उदाहरण के लिए, गैर-मानकीकृत स्केलर सदस्यों को शून्य किया जाएगा।

उन सदस्यों के लिए जो स्वयं कक्षाओं के उदाहरण हैं, उनके डिफ़ॉल्ट निर्माता को बुलाया जाएगा, इसलिए आपकी स्ट्रिंग ऑब्जेक्ट को आरंभीकृत किया जाएगा।

  • int *ptr; // uninitialized सूचक (या वैश्विक होने पर शून्य)
  • string name; // कंस्ट्रक्टर कहा जाता है, खाली स्ट्रिंग के साथ आरंभिक
  • string *pname; // uninitialized सूचक (या वैश्विक होने पर शून्य)
  • string &rname; // संकलन त्रुटि यदि आप इसे आरंभ करने में विफल रहते हैं
  • const string &crname; // संकलन त्रुटि यदि आप इसे आरंभ करने में विफल रहते हैं
  • int age; // अदिश मान, असमान और यादृच्छिक (या शून्य यदि वैश्विक)

मैंने प्रयोग किया और ऐसा लगता है कि string nameस्टैक पर क्लास को इनिशियलाइज़ करने के बाद खाली है। क्या आप अपने उत्तर के बारे में निश्चित हैं?
बॉडासिडो

1
स्ट्रिंग में एक कंस्ट्रक्टर होगा जो डिफ़ॉल्ट रूप से एक खाली स्ट्रिंग प्रदान करता है - मैं अपना उत्तर स्पष्ट करूंगा
पॉल डिक्सन

@bodacydo: पॉल सही है, लेकिन अगर आप इस व्यवहार के बारे में परवाह करते हैं, तो यह स्पष्ट होने के लिए कभी भी चोट नहीं पहुंचाता है। इसे शुरुआती सूची में फेंक दें।
स्टीफन

स्पष्ट करने और समझाने के लिए धन्यवाद!
बोदासाइडो

2
यह यादृच्छिक नहीं है! रैंडम उसके लिए बहुत बड़ा शब्द है! यदि अदिश सदस्य यादृच्छिक होंगे, तो हमें किसी अन्य यादृच्छिक संख्या जनरेटर की आवश्यकता नहीं होगी। एक प्रोग्राम की कल्पना करें जो डेटा "लेफ्ट-ओवर" का विश्लेषण करता है - जैसे मेमोरी में फ़ाइलों को हटाना रद्द करें - डेटा यादृच्छिक से दूर है। यह अपरिभाषित भी नहीं है! यह आमतौर पर परिभाषित करना कठिन है, क्योंकि आमतौर पर हम नहीं जानते कि हमारी मशीन क्या करती है। अगर वह "रैंडम डेटा" जिसे आप सिर्फ
अनलेटेड

5

गैर-स्थैतिक गैर-स्थैतिक सदस्यों में यादृच्छिक डेटा शामिल होगा। दरअसल, उनके पास केवल उन स्मृति स्थान का मूल्य होगा जो उन्हें सौंपे गए हैं।

निश्चित रूप से ऑब्जेक्ट पैरामीटर (जैसे string) के लिए ऑब्जेक्ट का निर्माता डिफ़ॉल्ट आरंभीकरण कर सकता है।

आपके उदाहरण में:

int *ptr; // will point to a random memory location
string name; // empty string (due to string's default costructor)
string *pname; // will point to a random memory location
string &rname; // it would't compile
const string &crname; // it would't compile
int age; // random value

2

एक कंस्ट्रक्टर वाले सदस्यों के पास अपने डिफाल्टर कंस्ट्रक्टर को आरंभीकरण के लिए बुलाया जाएगा।

आप अन्य प्रकार की सामग्री पर निर्भर नहीं कर सकते।


0

यदि यह स्टैक पर है, तो असंगठित सदस्यों की सामग्री जिनके पास स्वयं का निर्माण नहीं है, यादृच्छिक और अपरिभाषित होंगे। यहां तक ​​कि अगर यह वैश्विक है, तो यह उन पर भरोसा करने के लिए एक बुरा विचार होगा कि उन्हें शून्य किया जाएगा। चाहे वह स्टैक पर हो या नहीं, यदि किसी सदस्य के पास अपना स्वयं का कंस्ट्रक्टर है, तो उसे आरंभ करने के लिए बुलाया जाएगा।

इसलिए, यदि आपके पास स्ट्रिंग * pname है, तो पॉइंटर में रैंडम जंक होगा। लेकिन स्ट्रिंग नाम के लिए, स्ट्रिंग के लिए डिफ़ॉल्ट कंस्ट्रक्टर को बुलाया जाएगा, जो आपको एक खाली स्ट्रिंग देगा। आपके संदर्भ प्रकार चर के लिए, मुझे यकीन नहीं है, लेकिन यह शायद स्मृति के कुछ यादृच्छिक हिस्सा का संदर्भ होगा।


0

यह निर्भर करता है कि कक्षा का निर्माण कैसे किया जाता है

इस प्रश्न का उत्तर देने से C ++ भाषा मानक में एक विशाल स्विच केस स्टेटमेंट समझ में आता है, और जो कि केवल नश्वर लोगों के लिए कठिन हो जाता है।

कितनी मुश्किल बात है इसका एक सरल उदाहरण:

main.cpp

#include <cassert>

int main() {
    struct C { int i; };

    // This syntax is called "default initialization"
    C a;
    // i undefined

    // This syntax is called "value initialization"
    C b{};
    assert(b.i == 0);
}

डिफ़ॉल्ट आरंभीकरण में आप से शुरू होगा: https://en.cppreference.com/w/cpp/language/default_initialization हम "डिफ़ॉल्ट आरंभीकरण के प्रभाव" भाग पर जाते हैं और केस स्टेटमेंट शुरू करते हैं:

  • "यदि T एक गैर-POD है ": नहीं (POD की परिभाषा अपने आप में एक बहुत बड़ा स्विच स्टेटमेंट है)
  • "यदि T एक सरणी प्रकार है": नहीं
  • "अन्यथा, कुछ भी नहीं किया जाता है": इसलिए इसे अपरिभाषित मूल्य के साथ छोड़ दिया जाता है

फिर, यदि कोई व्यक्ति इनिशियलाइज़ करने का निर्णय लेता है तो हम https://en.cppreference.com/w/cpp/language/value_initialization "वैल्यू इनिशियलाइज़ेशन के प्रभाव हैं" पर जाते हैं और केस स्टेटमेंट शुरू करते हैं:

  • "यदि T एक वर्ग प्रकार है जिसमें कोई डिफॉल्ट कंस्ट्रक्टर नहीं है या एक यूजर-प्रोवाइड या डिलीट डिफॉल्ट कंस्ट्रक्टर है": ऐसा नहीं है। अब आप उन शर्तों को देखते हुए 20 मिनट बिताएंगे:
    • हमारे पास एक अंतर्निहित परिभाषित डिफ़ॉल्ट निर्माता है (विशेष रूप से क्योंकि कोई अन्य निर्माता परिभाषित नहीं था)
    • यह उपयोगकर्ता द्वारा प्रदान नहीं किया गया है (स्पष्ट रूप से परिभाषित)
    • इसे हटाया नहीं गया है ( = delete)
  • "यदि T एक डिफ़ॉल्ट कंस्ट्रक्टर के साथ एक वर्ग प्रकार है जो न तो उपयोगकर्ता-प्रदान किया गया है और न ही हटाया गया है": हाँ
    • "ऑब्जेक्ट शून्य-आरंभीकृत है और फिर यह एक गैर-तुच्छ डिफ़ॉल्ट निर्माता है, तो यह डिफ़ॉल्ट-आरंभिक है": कोई भी गैर-तुच्छ निर्माता नहीं है, बस शून्य-प्रारंभिक है। कम से कम "शून्य-आरंभ" की परिभाषा सरल है और वही करता है जो आप उम्मीद करते हैं: https://en.cppreference.com/w/cpp/language/zero_initialization

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.