डाउनकास्टिंग शेयर्ड_एप्ट्र <बेस> से शेयर्ड_प्ट्र <Derived>?


102

अपडेट: इस उदाहरण में शेयर्ड_पार्ट, बूस्ट में से एक की तरह है, लेकिन यह साझा_पोलिमोर्फिक_डाउन (या डायनामिक_पॉइंट_कास्ट या स्टेटिक_पॉइंट_कास्ट के लिए समर्थन नहीं करता है)!

मैं संदर्भ संख्या गंवाए बिना एक साझा पॉइंटर को एक व्युत्पन्न वर्ग में आरम्भ करने की कोशिश कर रहा हूँ:

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;  

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

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

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


शेयर्ड_प्ट्र <बेस> के बजाय आपको एक साझा_प्रति <Derived> की आवश्यकता क्यों है?
बिल

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

जवाबों:


109

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

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

प्रलेखन: https://en.cppreference.com/w/cpp/memory/sared_ptr/pointer/_cast

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

-Update: यदि प्रकार बहुरूपी नहीं है, तो std::static_pointer_castइसका उपयोग किया जा सकता है।


4
मुझे पहली पंक्ति से समझ नहीं आया कि वह उपयोग नहीं कर रहा है std::shared_ptr। लेकिन पहले उत्तर की टिप्पणियों से मुझे लगा कि वह बूस्ट का उपयोग नहीं कर रहा है, इसलिए वह प्रयोग कर रहा है std::shared_ptr
मसूद खारी

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

47

मुझे लगता है कि आप उपयोग कर रहे हैं 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जाएगी।

देखें (मृत लिंक) :

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


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

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

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

4

अगर किसी को बढ़ावा के साथ यहाँ मिलता है :: साझा_प्रति ...

इस तरह से आप व्युत्पन्न बूस्ट शेयर्ड_प्ट्र को डाउनकास्ट कर सकते हैं। आधार से व्युत्पन्न व्युत्पन्न मानते हुए।

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;

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

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