2011-09-24 15 views
36

वस्तुओं को बनाने के बारे में एक छोटा सा सवाल।विरासत में कन्स्ट्रक्टर/विनाशकों को कॉल करने का आदेश

struct A{ 
    A(){cout << "A() C-tor" << endl;} 
    ~A(){cout << "~A() D-tor" << endl;} 
}; 

struct B : public A{ 
    B(){cout << "B() C-tor" << endl;} 
    ~B(){cout << "~B() D-tor" << endl;} 

    A a; 
}; 

और मुख्य में मैं B का एक उदाहरण बनाने के लिए::

int main(){ 
    B b; 
} 

ध्यान दें कि BA से निकला है और यह भी प्रकार A के एक क्षेत्र है मैं इन दो वर्गों है कहो।

मैं नियमों को समझने की कोशिश कर रहा हूं। मुझे पता है कि किसी ऑब्जेक्ट का निर्माण करते समय पहले अपने मूल कन्स्ट्रक्टर को कॉल करते हैं, और इसके विपरीत जब विनाश होता है।

इस मामले में फ़ील्ड (A a;) के बारे में क्या? जब B बनाया गया है, तो यह A के निर्माता कहां से कॉल करेगा? मैंने प्रारंभिक सूची को परिभाषित नहीं किया है, क्या कोई डिफ़ॉल्ट सूची है? और यदि कोई डिफ़ॉल्ट सूची नहीं है? और विनाश के बारे में एक ही सवाल है।

+3

आपका उदाहरण अधिक व्याख्यात्मक हो सकता है यदि विनाशक के लिए आपका संदेश कन्स्ट्रक्टर के लिए आपके संदेश से अलग है। साथ ही, उन 'std :: sort' क्या कर रहे हैं? – Tom

+0

इसके अलावा, प्रयोग करते समय, 'बी बी' के निर्माण और विनाश की तुलना करें, 'बी * बी = नया बी(); बी हटाएं; 'और' ए * ए = नया बी(); हटाएं; '(तुलना करें कि जब आप अपने विनाशक के लिए' आभासी 'कीवर्ड का उपयोग करते हैं, यानी' वर्चुअल ~ ए() {cout << "ए डी-टोर" << endl;} ') – Tom

+0

@ टॉम, आप हैं सही। संकलक त्रुटियों को हटा रहा है। – iammilind

उत्तर

67
  • निर्माण हमेशा आधार class के साथ शुरू होता है। यदि कई आधार class es हैं तो निर्माण बाएं सबसे अधिक आधार से शुरू होता है। (साइड नोट: यदि virtual विरासत है तो इसे उच्च वरीयता दी जाती है)।
  • फिर सदस्य फ़ील्ड का निर्माण किया जाता है। वे क्रम में वे
  • अंत में घोषित किया गया है में प्रारंभ कर रहे हैं class ही निर्माण किया है
  • नाशक के आदेश बिल्कुल विपरीत

प्रारंभकर्ता सूची का लिहाज किए बिना है, कॉल आदेश तरह होगा इस:

  1. बेस class A के निर्माता
  2. class B के क्षेत्रनामित 10 (प्रकार class A का) निर्माण किया जाएगा
  3. व्युत्पन्न class B के निर्माता
+2

'आखिरी कक्षा में ही बनाया गया है' - क्या आप यहां कन्स्ट्रक्टर बॉडी के बारे में बात कर रहे हैं? – Wolf

+1

@ भेड़िया: मुझे हां लगता है। – Ludwik

+0

@Wolf। यह व्युत्पन्न वर्ग – MSD561

7

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

+1

+1 संक्षिप्त है, लेकिन अच्छा है। शायद कुछ टाइपोग्राफिक चीनी अधिक पाठकों को आकर्षित करेगा। – Wolf

20

मान लिया जाये कि वहाँ आभासी/एकाधिक वंशानुक्रम (है कि चीजें काफ़ी पेचीदा हो) तो नियम सरल कर रहे हैं नहीं है:,

  1. वस्तु स्मृति
  2. आधार वर्ग के निर्माता क्रियान्वित कर रहे हैं आवंटित किया जाता है के साथ समाप्त सबसे व्युत्पन्न
  3. सदस्य प्रारंभ निष्पादित किया जाता है
  4. वस्तु
  5. निर्माता कोड
  6. निष्पादित किया जाता है अपने वर्ग के एक सच्चे उदाहरण बन जाता है

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

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

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

+0

'बिंदु 2 पर सबसे अमूर्त से शुरू': क्या यह सच है? – Wolf

+0

@ भेड़िया: हाँ, यह गारंटी है। यदि आपके पास 'बी' से प्राप्त कक्षा' डी' है तो 'डी' को तुरंत चालू करने पर' बी 'के निर्माता को निष्पादित किया जाता है (सबसे सार) और फिर कन्स्ट्रक्टर 'डी' निष्पादित किया जाता है। असल में वस्तु सभी आधारों के निर्माण के बाद वास्तविक 'डी' (आभासी तरीकों के संबंध में) बन जाती है और अन्य सभी सदस्यों को पूरा कर लिया गया है (यह एक के निर्माण के दौरान' डी' के आभासी तरीकों को कॉल करने के बारे में एक मुश्किल बिंदु है) सदस्यों या आधार उप-वस्तु के निर्माण के दौरान)। – 6502

+0

यह आधार से निर्माण आदेश नहीं है जिसे मैंने पूछा था, यह 'अमूर्त' शब्द है जो मुझे लगता है कि भ्रामक है। जैसा कि मैंने सीखा, एक अमूर्त वर्ग कम से कम शुद्ध आभासी विधि के साथ एक वर्ग है। कृपया [इस उदाहरण] पर एक नज़र डालें (http://coliru.stacked-crooked.com/a/2f5e712f8421d303) – Wolf

0

आउटपुट है:

A() C-tor 
A() C-tor 
B() C-tor 
~B() D-tor 
~A() D-tor 
~A() D-tor 
3

आधार वर्ग निर्माता हमेशा first.so निष्पादित करता है जब आप एक बयान B b;A के निर्माता पहले कहा जाता है और उसके बाद B वर्ग लिखने constructor.therefore से उत्पादन इस प्रकार कंस्ट्रक्टर्स एक क्रम में हो जाएगा:

A() C-tor 
A() C-tor 
B() C-tor 
1
#include<iostream> 

class A 
{ 
    public: 
    A(int n=2): m_i(n) 
    { 
    // std::cout<<"Base Constructed with m_i "<<m_i<<std::endl; 
    } 
    ~A() 
    { 
    // std::cout<<"Base Destructed with m_i"<<m_i<<std::endl; 
    std::cout<<m_i; 
    } 

    protected: 
    int m_i; 
}; 

class B: public A 
{ 
    public: 
    B(int n): m_a1(m_i + 1), m_a2(n) 
    { 
    //std::cout<<"Derived Constructed with m_i "<<m_i<<std::endl; 
    } 

    ~B() 
    { 
    // std::cout<<"Derived Destructed with m_i"<<m_i<<std::endl; 
    std::cout<<m_i;//2 
    --m_i; 
    } 

    private: 
    A m_a1;//3 
    A m_a2;//5 
}; 

int main() 
{ 
    { B b(5);} 
    std::cout <<std::endl; 
    return 0; 
} 

इस मामले में जवाब 2531. कैसे constructo है आर यहाँ कहा जाता है:

  1. बी :: ए (int n = 2) निर्माता
  2. कहा जाता है
  3. बी :: बी (5) निर्माता
  4. बी कहा जाता हैm_A1 :: एक (3) कहा जाता है
  5. B.m_A2 :: एक (5)

एक ही तरह से नाशक कहा जाता है कहा जाता है:

  1. बी :: ~ बी() कहा जाता है। i.e m_i = 2, ए
  2. बीएम_ए 2 :: ~ ए() में एमआईआई से 1 में कमी आई है। m_i = 5
  3. बीएम_ए 1 :: ~ ए() कहा जाता है। m_i = 3 4 बी :: ~ एक() कहा जाता है।, m_i = 1

इस उदाहरण में, m_A1 & m_A2 के निर्माण के प्रारंभ सूची क्रम लेकिन उनकी घोषणा के आदेश के आदेश के अप्रासंगिक है।

संबंधित मुद्दे