2010-04-07 11 views
5

यह प्रश्न बहुत मूर्खतापूर्ण हो सकता है, हालांकि, मुझे कहीं और ठोस जवाब नहीं मिला है।ऑपरेटर हटाते समय कक्षा के विनाशक को एकाधिक विरासत में उपयोग किया जाता है

विरासत में उपयोग किए जाने वाले देर से बाध्यकारी कार्यों और वर्चुअल कीवर्ड के बारे में कम जानकारी के साथ।

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

अब मेरी सवाल यह है:

1) जब आधार के नाशक, आभासी नहीं है क्यों बुला ली गई dtor नहीं की समस्या हो ही जब का उपयोग कर के मामले में ऑपरेटर "हटाएँ", क्यों मामले में नहीं दी नीचे:


derived drvd; 
base *bPtr; 
bPtr = &drvd; //DTOR called in proper order when goes out of scope. 

2) When "delete" operator is used, who is reponsible to call the destructor of the class? The operator delete will have an implementation to call the DTOR ? or complier writes some extra stuff ? If the operator has the implementation then how does it looks like , [I need sample code how this would have been implemented].

3) If virtual keyword is used in this example, how does operator delete now know which DTOR to call?

Fundamentaly i want to know who calls the dtor of the class when delete is used.

<h1> Sample Code </h1> 

class base 
{ 
    public: 
    base(){ 
     cout<<"Base CTOR called"<<endl; 
    } 

    virtual ~base(){ 
     cout<<"Base DTOR called"<<endl; 
    } 
}; 

class derived:public base 
{ 
    public: 
     derived(){ 
      cout<<"Derived CTOR called"<<endl; 
     } 

    ~derived(){ 
      cout<<"Derived DTOR called"<<endl; 
    } 
}; 

I'm not sure if this is a duplicate, I couldn't find in search.

int main() { base *bPtr = new derived();

delete bPtr;// only when you explicitly try to delete an object return 0; 

}

+1

छोटे बिंदु, लेकिन आपका प्रश्न एकाधिक विरासत कहता है। यह एकाधिक विरासत का एक उदाहरण नहीं है, यह सिर्फ सादा पुरानी विरासत है। – Rich

उत्तर

1

संकलक सही क्रम में विनाशकर्ता कॉल करने के लिए, चाहे वह एक ढेर वस्तु या सदस्य चर दायरे से बाहर जा रहा है, या एक ढेर वस्तु हटाया जा रहा हो सभी आवश्यक कोड उत्पन्न करता है।

+0

@ मार्सेलो: अगर सब कुछ संकलन समय पर होता है, तो इस कार्यान्वयन को देर से बाध्यकारी क्यों कहा जाता है? और संकलन के समय संकलक को कैसे पता चलता है जिसे डीटीओआर कॉल करना है? मेरी अज्ञानता के लिए माफ़ी, आपके प्रयास की सराहना करते हैं। – dicaprio

+0

@dicaprio संकलन समय पर संकलक वर्चुअल फ़ंक्शन तंत्र का उपयोग करके विनाश को संभालने के लिए कोड को उत्सर्जित करता है। कोड रन टाइम पर निष्पादित किया जाता है। –

+0

@Neil: आपके उत्तर के लिए बहुत बहुत धन्यवाद, क्या इसका मतलब यह है कि कंपाइलर वर्चुअल तंत्र का उपयोग करने के लिए अतिरिक्त सामान लिखता है और ऑपरेटर को उचित डीटीओआर को कॉल करने के लिए रनटाइम पर पता का उपयोग करने के लिए हटा दिया जाता है? – dicaprio

1
  1. आप जब यह हो जाता है क्षेत्र से बाहर यह नाशक कहता है, आभासी या नहीं, व्युत्पन्न प्रकार का दृष्टांत।
  2. कंपाइलर कोड उत्पन्न करेगा जो विनाशकों को कॉल करता है। यह संकलन समय पर नहीं होता है। कोड जनरेशन करता है, लेकिन रनटाइम पर dtor का पता क्या होता है, इसे देखें। उस मामले के बारे में सोचें जहां आपके पास 1 व्युत्पन्न प्रकार है और आप बेस पॉइंटर का उपयोग करके हटाते हैं।
  3. एक बेस क्लास विनाशक को पॉलिमॉर्फिक डिलीट करने के लिए वर्चुअल होने की आवश्यकता होती है जो व्युत्पन्न प्रकार के डीटीओ को कॉल करती है।

यदि आप नए अधिभार को हटाने और हटाने का अधिक प्रयास करना चाहते हैं।

+0

@epronk: धन्यवाद, मैं 1 से आपसे सहमत हूं, लेकिन 2 और 3 अभी भी स्पष्ट नहीं हैं। यह फिर से कई प्रश्न उठाए जो मैंने नीचे मार्सेलो के जवाब में जोड़ा। – dicaprio

+0

आधार * बीपीआरआर वस्तु के जीवनकाल को किसी भी तरह से विस्तारित नहीं करता है और ड्रॉव करने से पहले गुंजाइश से बाहर हो जाएगा। (सितारे बाईं तरफ जाते हैं) –

+0

अच्छा बिंदु !! नया सुझाव या ऑपरेटर को हटाने के लिए आपका सुझाव, हालांकि, मेरी समझ यह है कि हम कक्षा के कॉलर को कॉल करने के लिए कुछ भी लागू नहीं करते हैं, है ना? – dicaprio

2
  1. यह था तथ्य यह है कि इस मामले में संकलक सब कुछ पता है कि वस्तु विलुप्त होने के लिए के बारे में इस मामले में drvd है और प्रकार derived की है जिसकी वजह से है। drvd दायरे से बाहर चला जाता है जब संकलक आवेषण कोड अपने destructer कॉल करने के लिए

  2. delete संकलक के लिए कोई कीवर्ड है। जब कंपाइलर को हटाया जाता है तो यह स्मृति को डिलीकेट करने के लिए operator delete पर कॉल करने के लिए विनाशक और कोड को कॉल करने के लिए कोड डालता है। कृपया ध्यान रखें कि keyword delete और operater delete अलग हैं।

  3. जब संकलक keyword delete को पॉइंटर के लिए उपयोग किया जाता है तो उसे उचित विनाश के लिए कोड उत्पन्न करने की आवश्यकता होती है। इसके लिए इसे सूचक की प्रकार की जानकारी जाननी चाहिए। पॉइंटर के बारे में संकलक को केवल एक ही चीज सूचक सूचक है, न कि ऑब्जेक्ट का प्रकार जिस पर पॉइंटर इंगित कर रहा है। ऑब्जेक्ट जिस पर पॉइंटर इंगित कर रहा है वह बेस क्लास या व्युत्पन्न क्लास हो सकता है।कुछ मामलों में वस्तु के प्रकार के बहुत स्पष्ट रूप से उदाहरण यह एक

    void deallocate(Base *base) 
    { 
        delete base; 
    } 
    

    तो संकलक के लिए उदाहरण के लिए परिभाषित किया जा सकता

void fun() 
{ 
    Base *base= new Derived(); 
    delete base; 
} 

लेकिन ज्यादातर मामलों में ऐसा नहीं है, पता नहीं है कि किस विनाशक को आधार या व्युत्पन्न कॉल करने के लिए कहा जाता है। यह तरीका है कि यह

  1. यदि बेस क्लास में वर्चुअल फ़ंक्शन (सदस्य फ़ंक्शन या विनाशक) नहीं है। यह बेस क्लास
  2. के विनाशक को कॉल करने के लिए सीधे थ्रू कोड डालने वाला है, यदि बेस क्लास में वर्चुअल फ़ंक्शंस हैं, तो कंपाइलर विनाशक की जानकारी vtable से लेता है।
    1. यदि विनाशक आभासी नहीं है। Vtable में मूल विनाशक का पता होगा और जो कहा जाएगा। यह सही नहीं है क्योंकि उचित विनाशक यहां नहीं बुलाया जा रहा है। यही कारण है कि यह हमेशा के रूप में आभासी
    2. आधार वर्ग के destructer घोषित करने के लिए तो destructer आभासी है vtable destructer और संकलक की correcte पता होगा वहाँ पर
2

+1 उचित कोड दर्ज करेंगे सिफारिश की है अच्छा सवाल बीटीडब्ल्यू।

देखें कि कैसे वर्चुअल तंत्र गैर विनाशकारी विधि के लिए काम करता है और आप पाएंगे कि एक विनाशक अलग-अलग व्यवहार नहीं करता है।

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

किसी व्युत्पन्न क्लास ऑब्जेक्ट पर एक आधारित क्लास पॉइंटर पर गैर वर्चुअल विधि को कॉल करने पर विचार करें, क्या होता है? बेस क्लास कार्यान्वयन कहा जाता है। अब एक वर्चुअल विधि को बेस क्लास पॉइंटर से व्युत्पन्न क्लास ऑब्जेक्ट पर कॉल करने पर विचार करें, क्या होता है? विधि का व्युत्पन्न संस्करण कहा जाता है। कुछ भी नहीं जिसे आप पहले से ही नहीं जानते थे।

अब विनाशक परिदृश्य पर विचार करें। बेस क्लास पॉइंटर पर एक व्युत्पन्न क्लास ऑब्जेक्ट पर कॉल डिलीट करें जिसमें गैर आभासी विनाशक है। बेस क्लास विनाशक को बुलाया जाता है, और यदि बेस क्लास को किसी अन्य वर्ग से लिया गया है, तो यह विनाशक को अगली बार बुलाया जाएगा। चूंकि आभासी तंत्र नाटक में नहीं है, व्युत्पन्न विनाशक को नहीं बुलाया जाएगा क्योंकि विनाश से आप विनाशक से शुरू होता है जिसे आप पदानुक्रम में बुलाते हैं और आधार वर्ग तक इसे नीचे काम करते हैं।

अब वर्चुअल विनाशक मामले पर विचार करें। डिलीट क्लास ऑब्जेक्ट पर आधारित क्लास पॉइंटर पर डिलीट किया जाता है। क्या होता है जब आप बेस क्लास पॉइंटर पर किसी वर्चुअल विधि को कॉल करते हैं? व्युत्पन्न संस्करण कहा जाता है। तो हमारे व्युत्पन्न वर्ग विनाशक कहा जाता है। विनाश के दौरान क्या होता है, वस्तु व्युत्पन्न विनाशक से आधार वर्ग तक नष्ट हो जाती है, लेकिन इस बार हमने आभासी विधि तंत्र के कारण व्युत्पन्न वर्ग स्तर पर विनाश शुरू किया।

गैर-वर्चुअल या आभासी विनाशक के साथ एक स्टैक ऑब्जेक्ट का कारण बेस क्लास से निकलता है जब यह गुंजाइश से बाहर हो जाता है?क्योंकि इस मामले में घोषित वर्ग के विनाशक को बुलाया जाता है और वर्चुअल तंत्र के साथ इसका कोई लेना-देना नहीं है।

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