2009-08-31 15 views
67

अद्यतन: इस उदाहरण में shared_ptr बूस्ट में से एक जैसा है, लेकिन यह shared_polymorphic_downcast (या उस समस्या के लिए dynamic_pointer_cast या static_pointer_cast का समर्थन नहीं करता है) का समर्थन नहीं करता है! ,डाउनकास्टिंग share_ptr <Base> साझा_ptr <Derived> पर?

struct Base { }; 
struct Derived : public Base { }; 
shared_ptr<Base> base(new Base()); 
shared_ptr<Derived> derived; 

// error: invalid conversion from 'Base* const' to 'Derived*' 
derived = base; 

अब तक तो अच्छा:

मैं संदर्भ गिनती खोने के बिना एक व्युत्पन्न वर्ग के लिए एक साझा सूचक को प्रारंभ करने की कोशिश कर रहा हूँ। मैंने उम्मीद नहीं की थी कि सी ++ बेस * को व्युत्पन्न * में परिवर्तित कर देगा। हालांकि, मैं कोड द्वारा व्यक्त की गई कार्यक्षमता चाहता हूं (यानी बेस पॉइंटर को कम करते समय संदर्भ गणना को बनाए रखना)। मेरी पहली सोचा ताकि जगह ले सकता है व्युत्पन्न करने के लिए एक अंतर्निहित रूपांतरण बेस में एक डाली ऑपरेटर उपलब्ध कराने के लिए किया गया था (pedants के लिए: मैं की जाँच करेगा कि नीचे डाली मान्य है, चिंता मत करो):

struct Base { 
    operator Derived*(); 
} 
// ... 
Base::operator Derived*() { 
    return down_cast<Derived*>(this); 
} 

ठीक है, यह मदद नहीं की। ऐसा लगता है कि संकलक ने मेरे टाइपकास्ट ऑपरेटर को पूरी तरह नजरअंदाज कर दिया। कोई विचार है कि मैं share_ptr असाइनमेंट कैसे काम कर सकता हूं? अतिरिक्त बिंदुओं के लिए: किस प्रकार का प्रकार Base* const है? const Base* मैं समझता हूं, लेकिन Base* const? const इस मामले में क्या संदर्भित करता है?

+0

साझा_ptr के बजाय आपको साझा_ptr क्यों चाहिए? – Bill

+2

क्योंकि मैं व्युत्पन्न में कार्यक्षमता तक पहुंच बनाना चाहता हूं जो कि बेस में नहीं है, ऑब्जेक्ट को क्लोन करने के बिना (मुझे एक ऑब्जेक्ट चाहिए, दो साझा पॉइंटर्स द्वारा संदर्भित)। वैसे, कास्ट ऑपरेटर क्यों काम नहीं करते? –

उत्तर

45

मुझे लगता है कि आप boost::shared_ptr का उपयोग कर रहे हैं ... मुझे लगता है कि आप dynamic_pointer_cast या shared_polymorphic_downcast चाहते हैं।

हालांकि, इन्हें पॉलीमोर्फिक प्रकारों की आवश्यकता होती है।

किस तरह का प्रकार Base* const है? const Base* मैं समझता हूं, लेकिन Base* const? const इस मामले में क्या संदर्भित करता है?

  • const Base * एक निरंतर Base करने के लिए एक परिवर्तनशील सूचक है।
  • Base const * निरंतर Base पर एक परिवर्तनीय सूचक है।
  • Base * const एक परिवर्तनीय Base के लिए एक स्थिर सूचक है।
  • Base const * const स्थिर Base पर स्थिर सूचक है।

यहाँ एक न्यूनतम उदाहरण है:

struct Base { virtual ~Base() { } }; // dynamic casts require polymorphic types 
struct Derived : public Base { }; 

boost::shared_ptr<Base> base(new Base()); 
boost::shared_ptr<Derived> derived; 
derived = boost::static_pointer_cast<Derived>(base); 
derived = boost::dynamic_pointer_cast<Derived>(base); 
derived = boost::shared_polymorphic_downcast<Derived>(base); 

मुझे यकीन है कि अगर यह जानबूझकर है कि आपके उदाहरण आधार प्रकार का एक उदाहरण बनाता है और यह डाले था नहीं कर रहा हूँ, लेकिन यह अच्छी तरह से अंतर झलक दिखाती है।

static_pointer_cast "बस इसे करें"। इसके परिणामस्वरूप अपरिभाषित व्यवहार (Derived*Base द्वारा आवंटित स्मृति के लिए आवंटित स्मृति पर इंगित करेगा) और संभावित रूप से क्रैश या इससे भी बदतर हो जाएगा। base पर संदर्भ गणना बढ़ाई जाएगी।

dynamic_pointer_cast परिणामस्वरूप एक शून्य सूचक होगा। base पर संदर्भ संख्या अपरिवर्तित होगी।

shared_polymorphic_downcast एक स्थिर कास्ट के समान परिणाम होगा, लेकिन सफल होने के लिए प्रतीत होता है और अपरिभाषित व्यवहार की ओर अग्रसर होता है। base पर संदर्भ गणना बढ़ाई जाएगी।

(dead link) देखें:

कभी कभी यह एक छोटे से static_cast या dynamic_cast उपयोग करने के लिए तय करना मुश्किल है, और आप चाहते हैं कि आप दोनों दुनिया का एक छोटा सा हो सकता था। यह अच्छी तरह से ज्ञात है कि गतिशील_कास्ट में रनटाइम ओवरहेड होता है, लेकिन यह सुरक्षित है, जबकि static_cast में कोई ओवरहेड नहीं है, लेकिन यह चुपचाप विफल हो सकता है। यह कितना अच्छा होगा यदि आप डिबग बिल्ड में shared_dynamic_cast का उपयोग कर सकते हैं, और shared_static_cast रिलीज बिल्ड में बना सकते हैं। खैर, ऐसी चीज पहले से ही उपलब्ध है और इसे shared_polymorphic_downcast कहा जाता है।

+0

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

+3

अन्य 'shared_ptr' रचनाकारों को लागू करने के लिए छोटा ('static_cast_tag' और' dynamic_cast_tag' लेना), आप इतना कुछ नहीं कर सकते हैं। 'Shared_ptr' के बाहर आप जो कुछ भी करते हैं वह रीफॉउंट प्रबंधित करने में सक्षम नहीं होगा। - एक "सही" ओओ डिज़ाइन में आप हमेशा बेस प्रकार का उपयोग कर सकते हैं, और कभी भी यह जानने की आवश्यकता नहीं है कि न ही व्युत्पन्न प्रकार क्या है, क्योंकि इसकी सभी कार्यक्षमता बेस-क्लास इंटरफेस के माध्यम से सामने आती है। शायद आपको फिर से सोचने की जरूरत है कि आपको पहले स्थान पर क्यों डालना चाहिए। –

+1

@ टिम सिल्वेस्टर: लेकिन, सी ++ एक "सही" ओओ भाषा नहीं है! :-) डाउन-कास्ट्स में एक गैर-परिपूर्ण ओओ भाषा –

55

आप dynamic_pointer_cast का उपयोग कर सकते हैं। यह std::shared_ptr द्वारा समर्थित है।

std::shared_ptr<Base> base (new Derived()); 
std::shared_ptr<Derived> derived = 
       std::dynamic_pointer_cast<Derived> (base); 

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

-अद्यतन: यदि प्रकार polymorphic नहीं है, std::static_pointer_cast का उपयोग किया जा सकता है।

+3

में उनकी जगह है, मुझे पहली पंक्ति से नहीं पता था कि वह 'std :: shared_ptr' का उपयोग नहीं कर रहा है। लेकिन पहले जवाब की टिप्पणियों से मैंने अनुमान लगाया कि वह बूस्ट का उपयोग नहीं कर रहा है, इसलिए वह 'std :: shared_ptr' का उपयोग कर रहा है। –

+0

ठीक है। माफ़ कीजिये। उन्हें बेहतर स्पष्टीकरण देना चाहिए कि वह एक कस्टम कार्यान्वयन का उपयोग कर रहा है। –

3

किसी बढ़ावा :: shared_ptr के साथ यहाँ हो जाता है ...

इस तरह आप व्युत्पन्न बूस्ट shared_ptr को खिन्न कर सकते हैं। बेस से व्युत्पन्न विरासत मानते हैं।

boost::shared_ptr<Base> bS; 
bS.reset(new Derived()); 

boost::shared_ptr<Derived> dS = boost::dynamic_pointer_cast<Derived,Base>(bS); 
std::cout << "DerivedSPtr is: " << std::boolalpha << (dS.get() != 0) << std::endl; 

सुनिश्चित करें कि 'आधार' वर्ग/struct कम से कम एक आभासी समारोह है। एक आभासी विनाशक भी काम करता है।

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