2011-03-28 15 views
5

क्या बेस प्रकार से व्युत्पन्न प्रकार से एसटीएल कंटेनर डालना ठीक है? उदाहरण के लिए, मेरे पास दो वैक्टर हैं। पहला बेस बेस क्लास के प्रकार में है, दूसरा एक व्युत्पन्न वर्ग के प्रकार में है।क्या बेस प्रकार के साथ एसटीएल कंटेनर को व्युत्पन्न प्रकार में डालना ठीक है?

class Base 
{ 
// Code 
}; 

class Derive : public Base 
{ 
// Code 
}; 

प्रयोग

vector<Base*>* vec_base = new vector<Base*>; 

    // Add some Derive type data to vec_base 

    vector<Derive*>* vec_derive = (vector<Derive*>*)(vec_base); 

    // Using elements as Derive pointers. Works fine. 

यह ठीक है? (यह ठीक काम करता है, लेकिन मैं इसके बारे में कुछ टिप्पणियां प्राप्त करना चाहता था)। आपका बहुत बहुत धन्यवाद।

संपादित करें: उत्तरों के अनुसार अद्यतन।

कहें, अगर मैं उस वेक्टर का ध्यान से उपयोग करता हूं, और एकाधिक विरासत के साथ उपयोग नहीं करता और व्युत्पन्न प्रकार के अलावा अन्य वस्तुओं को सम्मिलित नहीं करता, तो क्या यह ठीक है? (मुझे लगता है, यह नहीं है)

और उत्तर के लिए आपको बहुत बहुत धन्यवाद।

+0

पुन: अपडेट करें - std :: transform जैसे कुछ का उपयोग किए बिना आप कुछ भी नहीं कर सकते हैं, यह reinterpret_cast के अलावा किसी भी कलाकार का उपयोग करेगा, जो आप – Flexo

+0

@awoodland के लिए नहीं देख रहे हैं, फिर भी reinterpret_cast खराब है बहुलक प्रकार? मेरा मतलब है, भले ही मैं 100% सुनिश्चित करता हूं कि वेक्टर reinterpret_cast के "मुझे सही प्रकार पता है" इस मामले के लिए अनिर्धारित है? – Morpheus

+1

reinterpret_cast std :: vector पर निश्चित रूप से खराब है, समस्या यह है कि std :: vector और std :: vector के लिए मेमोरी लेआउट यह मानने के लिए कोई (पोर्टेबल, मानकीकृत) कारण नहीं है कि यह काम करेगा। – Flexo

उत्तर

8

यह निश्चित रूप से ठीक नहीं है, और सी-शैली के उदाहरणों में से एक मास्किंग त्रुटियों का कारण बनता है। "यह मेरे लिए काम करता है" इस उदाहरण में अच्छी तरह से परिभाषित व्यवहार का संकेत नहीं है।

मैं सुझाव देंगे क्या आप वाकई ऐसा करना चाहते हैं:

#include <vector> 
#include <algorithm> 
#include <iterator> 

using namespace std; 

class Base 
{ 
// Code 
virtual ~Base(); 
}; 

class Derrive : public Base 
{ 
// Code 
}; 

Derrive *convert(Base * in) { 
    // assert here? 
    return dynamic_cast<Derrive*>(in); 
} 

int main() { 
    vector<Base*>* vec_base = new vector<Base*>; 

    // Add some Derrive type data to vec_base 

    vector<Derrive*>* vec_derrive = new vector<Derrive*>; 

    transform(vec_base->begin(), vec_base->end(), back_insert_iterator<vector<Derrive*> >(*vec_derrive), convert); 
} 
+0

यह करने का यह अच्छा तरीका है। बहुत बहुत धन्यवाद – Morpheus

+2

यह एक शर्म की बात है गतिशील_कास्ट एक फ़ंक्शन नहीं है क्योंकि तब आपको संभावित रूप से कनवर्ट फ़ंक्शन को गतिशील_कास्ट को लपेटने की आवश्यकता नहीं होगी। – Flexo

+0

जब आप vec_derrive का उपयोग करते हैं, तो इसका उपयोग करने से पहले प्रत्येक सदस्य को शून्य के लिए जांचें। यदि कोई गतिशील_casts विफल हो जाता है, तो आपको अपने वेक्टर में शून्य प्रविष्टियां मिलेंगी। – Tim

0

नहीं। यही कारण है कि अच्छी तरह से काम नहीं करेगा।

कहें कि मेरे पास है जो Base से प्राप्त होता है। मैं इसे एसटीएल कंटेनर में रख सकता हूं, लेकिन यह सुरक्षित रूप से Derrive पर नहीं डालेगा।

+0

ठीक है, कहें कि मैं उस वेक्टर का ध्यान से उपयोग करूंगा और वेरिएड 2 प्रकार को वेक्टर में नहीं रखूंगा। अब, क्या यह ठीक है? – Morpheus

+0

अभी भी एक बुरा विचार है। –

+0

@ मॉर्फीस नहीं, यह ठीक नहीं है - वेक्टर प्रकार अभी भी संबंधित नहीं हैं। –

1

यह ठीक नहीं है। विभिन्न T रों साथ टेम्प्लेट प्रकार असंबंधित प्रकार के होते हैं (भले ही वे दोनों std::vector, और एक सी शैली डाली का उपयोग कर कहते हैं कि बस की सुविधा देता है आप अपरिभाषित व्यवहार के साथ भाग मिलता है।

यह, अब के लिए काम अपने आप को अशुभ यह है कि विचार करने के लिए लगता है दुर्घटनाग्रस्त नहीं हुआ।

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

2

आप एक सी-स्टाइल कास्ट कर रहे हैं, जो अनिवार्य रूप से reinterpret_cast कर रहा है, जो संकलक को बताता है "अब x की तरह x का इलाज करें, और बस मुझ पर विश्वास करें कि यह rks "। तो यह निश्चित रूप से संकलित होगा, लेकिन एक बुरा विचार है। यहां कोई प्रकार की सुरक्षा नहीं है, और यह कुछ समय काम कर सकती है, लेकिन दूसरी बार अप्रत्याशित रूप से दुर्घटनाग्रस्त हो जाएगी।

आप के बजाय क्या कर सकते हैं:

for (unsigned int i=0; i < vec_base->length(); i++) 
{ 
    Derrive* d = dynamic_cast<Derrive*> (vec_base[i]); 
    if (d) { 
    // this element is a Derrive instance, so we can treat it like one here 
    } 
    // else, skip it, log an error, throw an exception, whatever, 
    // this element in the vector is not of type Derrive 
} 
+0

हाँ, यह रास्ता होना चाहिए। लेकिन मैं उपयोगकर्ताओं को गतिशील_कास्ट का उपयोग करने नहीं दे सकता, क्योंकि यह महत्वपूर्ण पथ में है। मैंने सोचा, संकलक को डेरिव प्रकार में डालने के लिए मजबूर कर, इसे काम करना चाहिए – Morpheus

0

यह करने के लिए एसटीडी उपयोग कर रहा है सुरक्षित तरीके :: बदलना।

लेकिन, चूंकि std :: सूची के कार्यान्वयन के अंदर, टी = बेस * या टी = व्युत्पन्न * एक ही तरीके से व्यवहार करता है (दोनों का आकार समान होता है), एक सूची में सूची की तुलना में एक ही आंतरिक संरचना होती है।

vector<Derived*> vector2 = *(reinterpret_cast< vector<Derived*>* >(&vector1)); 

नोट:: तो यह निम्नलिखित चाल करना संभव है मेरा जवाब सूचनात्मक है, एसटीडी के साथ चिपके रहते हैं तो कृपया :: दृष्टिकोण को बदलने। मुझे यकीन नहीं है कि अगर एसटीडीसी ++ में जीसीसी के वेक्टर के अलावा अन्य कार्यान्वयन एक ही तरीके से व्यवहार करते हैं, यानी।मुझे यकीन नहीं है कि अगर दावा "सूची < बेस *> और सूची < सूचीबद्ध *> समान आंतरिक संरचना है" अन्य कार्यान्वयन में सच है।

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