2012-04-21 29 views
8

अगर मैं पहले से ही उत्तर दिया गया था और उत्तर नहीं मिला तो मैं पहले से माफ़ी मांगता हूं।स्मार्ट पॉइंटर्स और डायनामिक_कास्ट

नोट: यह आईएस एक होमवर्क असाइनमेंट है, इसलिए यदि आपको असहज जवाब मिल रहा है, तो मैं पूरी तरह से समझता हूं।

मैं निम्नलिखित है:

ptr.h:

template<typename T> 
class Ptr { 
    T* address; 
    size_t* counter; 
    Ptr(T* address) : address(address), counter(new size_t(1)) { } 
    Ptr(const Ptr& other) : address(other.address), counter(other.counter) 
    { 
     ++(*counter); 
    } 
    virtual ~Ptr() { 
     if (0 == --(*counter)) { delete address; delete counter; } 
    } 
    Ptr& operator=(const Ptr& right) { 
     if (address != right.address) { 
      if (0 == --(*counter)) { delete address; delete counter; } 
      address = right.address; 
      counter = right.counter; 
      ++(*counter); 
     } 
     return *this; 
    } 
    T& operator*() const { TRACE(address); return *address; } 
    T* operator->() const { TRACE(address); return address; } 
    T* raw()  const { TRACE(addr); return addr; } 
}; 

main.cc:

#include <iostream> 
#include "ptr.h" 

using std::cout; 
using std::endl; 


class Base { 
public: 
    Base() { std::cout << "Base()" << std::endl; } 
    virtual ~Base() { std::cout << "~Base()" << std::endl; } 
    virtual std::string str() { return "In Base::str()"; } 
}; 

class Derived: public Base { 
public: 
    Derived() { std::cout << "Derived()" << std::endl; } 
    ~Derived() { std::cout << "~Derived()" << std::endl; } 
    std::string str() { return "In Derived::str()"; } 
}; 



int main() { 
Ptr<Base> base(new Base()); 
Ptr<Derived> derived(new Derived()); 

Ptr<Base> pbase(0); 
Ptr<Derived> pderived(0); 

    // upcasting can be done like this, but is it the best way? 
    pbase = *((Ptr<Base>*)(&derived)); 
    cout << pbase->str() << endl; // outputs: "In Derived::str()" 

    /* 
    * downcasting should be done using dynamic_casts 
    * but how can I downcast here? 
    * what do I know so far: 
    * 1. just because Derived is a subclass of Base does not mean Ptr<Derived> is a 
    * subclass of Ptr<Base> so there is no hierarchy between the two so I cannot 
    * really use dynamic_casts here 
    * 2. The dynamic_cast I do use is sort of useless no? since pbase is a Ptr<Base> 
    */ 
    pderived = *((Ptr<Derived>*)(dynamic_cast<Ptr<Base>*>(&pbase))); 
    cout << pderived->str() << endl; 


return 0; 
} 

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

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

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

मैं तुम लोगों कह रहा हूँ क्योंकि: 1. मैं एक मुद्दा यह है कि मैं ऑनलाइन और मदद पूछ 2. से पहले पिछले कुछ समय से इस पर काम कर रहा हूँ मैं आपको बताना चाहता क्या चाहते हैं बनाना चाहते मैं पहले से ही कोशिश की है।

मैं वास्तव में यहां कुछ सलाह का उपयोग कर सकता हूं। बस कैसे प्राप्त करें:

pderived = <SOMETHINGSOMETHING>pbase<SOMETHINGSOMETHING> 

धन्यवाद!

+3

चिंता मत करो अगर यह होमवर्क के रूप में छोड़ दिया है। बस सुनिश्चित करें कि आप होमवर्क टैग डाल दें।लोग सिर्फ उन उत्तरों के लिए जाएंगे जो आपको जवाब देने के बजाए सही दिशा में ले जाते हैं। – chris

+0

यदि आप अधिक विस्तृत स्पष्टीकरण चाहते हैं तो यह एक अच्छा पठन है: http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions – chris

+0

लिंक के लिए धन्यवाद :) मैं नहीं था होमवर्क टैग – mlnyc

उत्तर

6

आम तौर पर स्मार्ट पॉइंटर क्लास गतिशील कास्ट रैपर का पर्दाफाश करेगा जो अंतर्निहित स्मार्ट पॉइंटर ऑब्जेक्ट से ठीक से संबंधित है। उदाहरण के लिए, सी ++ 0x में dynamic_pointer_cast फ़ंक्शन है। ध्यान दें कि आपका *((Ptr<Derived>*)(dynamic_cast<Ptr<Base>*>(&pbase))); ब्रेक कर सकता है और विशेष रूप से यदि आपके पास एकाधिक विरासत है, क्योंकि यह सुपर पॉस की आवश्यकता होने पर उप-वर्ग के भीतर दाएं ऑफसेट पर address पर आंतरिक सूचक को समायोजित नहीं करेगा।

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

किसी भी मामले में, एक बार जब आप विनाशक के लिए यह संकेत देते हैं, तो इन स्मार्ट पॉइंटर्स को डालने का समय आने पर, आप केवल बाहरी पॉइंटर कास्ट कर सकते हैं; विनाश के समय के आसपास घूमने के लिए अकेले इस आंतरिक संदर्भ-गिनती संरचना को छोड़कर।

वास्तव में सभी कोड में इस मोड़, ज़ाहिर है, पाठक के लिए एक व्यायाम :)

+0

"और एक विलोपन दिनचर्या के लिए एक सूचक" - या सीधे एक डिलीटर फ़ंक्शन ऑब्जेक्ट से अवगत नहीं है। – Xeo

+0

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

+1

वास्तव में यह है कि मैं क्या जानता हूं सभी कार्यान्वयन। [एसटीएल के पास गोइंगनेट 2012 में 'shared_ptr' कैसे काम करता है] पर एक अच्छी बात थी] (http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/STL11- मैजिक- रहस्य)। – Xeo