2013-02-19 17 views
9

क्या किसी ऑब्जेक्ट को उप-वर्ग में डाउनकास्ट करना संभव है, कोई अतिरिक्त चर या वर्चुअल विधि परिभाषित नहीं करता है?क्या किसी ऑब्जेक्ट को उप-वर्ग में डाउनकास्ट करना संभव है जो सी ++ में अतिरिक्त चर या vtable परिभाषित नहीं करता है?

अगर मैं इन कक्षाओं में है,

class A { public: A(); }; 
class B : public A { public: void method1() {} B(); }; 

है इस (1) संभव और (2) मानक से सुरक्षित है?

A* a = new A(); 
B* b = (B*)a; 
b->method1(); 
+7

नहीं, एक 'ए' 'बी' नहीं है। –

+0

आपका प्रश्न आप जो पूछ रहे हैं उससे मेल नहीं खाता है। आपका प्रश्न कास्टिंग ऑब्जेक्ट्स के बारे में पूछता है, जबकि आपका कोड पॉइंटर्स कास्टिंग कर रहा है। – Mehrdad

+1

संबंधित: http://stackoverflow.com/questions/11404209/c-memory-layout-of-inheritance – jogojapan

उत्तर

6

सूचक रूपांतरण static_cast के रूप में कार्य करता है। 5.2.9/2 कहते हैं,

हैं [A] के प्रकार वस्तु वास्तव में प्रकार [B] की एक वस्तु की एक subobject है, परिणाम [B] के प्रकार संलग्न वस्तु को दर्शाता है। अन्यथा, कास्ट का परिणाम अव्यवस्थित है।

आपका वस्तु नहीं एक B वस्तु का एक subobject है, इसलिए परिणाम अनिर्धारित रहता है।

भले ही आप reinterpret_cast पर हों, परिणामी सूचक के माध्यम से ऑब्जेक्ट के मूल्य तक पहुंचने से व्यवहार को अपरिभाषित किया गया है क्योंकि यह सख्त एलियासिंग का उल्लंघन करता है। सी ++ 11 मानक में, 3।10/10:

एक कार्यक्रम निम्नलिखित प्रकार व्यवहार unde फाई नेड है में से एक के अलावा अन्य के glvalue के माध्यम से एक वस्तु की संग्रहीत मूल्य तक पहुँचने के लिए प्रयास करता है:

"एक व्युत्पन्न वर्ग उस ऑब्जेक्ट के डायनामिक प्रकार का जो कोई डेटा सदस्य या आभासी सदस्य फ़ंक्शंस नहीं जोड़ता है " निम्न सूची में है।

method1 वास्तव में क्या करता है, इस पर निर्भर करते हुए ऑब्जेक्ट के संग्रहीत मूल्य तक पहुंचने से बचना संभव हो सकता है। लेकिन मुझे यकीन नहीं है कि यह कभी भी संभव है। जब तक कि मानक में कहीं और नहीं कहा जाता है, मैं सुरक्षा के लिए मानता हूं कि गैर-स्थैतिक सदस्य फ़ंक्शन को मूल रूप से "ऑब्जेक्ट के संग्रहीत मूल्य तक पहुंचता है" भले ही फ़ंक्शन वास्तव में किसी भी डेटा सदस्यों का उपयोग न करे।

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

एक बार परिभाषित होने के बाद, नए सदस्य कार्यों सहित नए सदस्यों को सी ++ कक्षाएं बंद कर दी गई हैं। इसलिए new A() के साथ बनाई गई आपकी ऑब्जेक्ट में उसके सभी सदस्य फ़ंक्शंस हैं। बस एक गैर-सदस्यीय फ़ंक्शन लिखें - जब तक कि A में protected सदस्य हैं, तो उनके सदस्य फ़ंक्शन में A पर समान पहुंच होगी। और यदि A में protected सदस्य हैं तो इससे प्राप्त होने का तरीका है, जिसे आप B के उचित उदाहरण बनाने के लिए उपयोग करना चाहिए।

सदस्य समारोह वाक्य रचना मतलब है कि आप के लिए बहुत कुछ है, तो वर्ग के आधार पर A आप लिखने में सक्षम हो सकता है:

B b = *a; // "copy" the object (give B a suitable ctor) 
b.method1(); // act on it 
*a = b;  // copy it back (A needs copy assignment operator) 

मुद्दों जाहिर है देखते हैं यहाँ है कि यह काम करना बंद कर सकता है: के साथ शुरू करने के लिए कि ऑब्जेक्ट कॉपी करने योग्य, थ्रेड-सुरक्षा भी है, और method1b पर कहीं भी पॉइंटर/संदर्भ संग्रहीत करता है जो b नष्ट हो जाता है। सी ++ 11 में प्रतियां शायद दक्षता के लिए आगे बढ़ सकती हैं, लेकिन फिर भी मुझे आशा है कि आप इस बात से सहमत होंगे कि आपको सदस्य फ़ंक्शन सिंटैक्स का उपयोग करने के लिए कूदने के लिए हुप्स के लायक नहीं हैं।

+2

आपके अंतिम कोड के बारे में, 'बी' को 'ए' के चारों ओर एक रैपर बनाने का एक और सुविधाजनक तरीका हो सकता है: ऑब्जेक्ट को' बी' में कॉपी करने के बजाय, 'बी' संदर्भ/सूचक को 'ए' में रखेगा, और इस पर कार्य करें। यह एक काफी आम पैटर्न है। –

+0

वास्तव में पॉइंटर रूपांतरण के साथ समस्या होने के लिए संभव नहीं है जब तक कि व्युत्पन्न वर्ग में कोई डेटा सदस्य न हो। –

+0

@EricAronesty: आपको निश्चित रूप से एक उत्तर उद्धरण पोस्ट करना चाहिए जहां मानक गारंटी देता है कि, यदि ऐसा होता है। अगर मेरा जवाब गलत है तो मैं इसे स्वीकार नहीं कर सकता क्योंकि इसे स्वीकार किया गया है, लेकिन मैं आपके सुधार में आपका उल्लेख कर सकता हूं। –

1

आप इस अत्यंत अच्छी तरह से लिखा पोस्ट पढ़ करना चाहिए:

Regular cast vs. static_cast vs. dynamic_cast

आप "static_cast" का उपयोग करते हैं, चेतावनी दी है कि आप "बल" परिवर्तित कर रहे हैं और यह स्वाभाविक असुरक्षित है।

+0

और वह 'dynamic_cast' का उपयोग नहीं कर सकता, क्योंकि कोई वर्चुअल फ़ंक्शन नहीं है। –

3

बी * ख = static_cast < बी *> एक या आप क्या करने की कोशिश की एक असुरक्षित downcasting है, यह एक आधार स्तरीय वस्तु (ए) एक व्युत्पन्न वर्ग (बी) सूचक के पते प्रदान करती है। तो यदि आप उस सूचक के माध्यम से कुछ भी एक्सेस करते हैं, तो यह अपरिभाषित व्यवहार का कारण बन जाएगा।

के एक का एक उदाहरण में से एक संभव वस्तु लेआउट मान लेते हैं:

a ->|vptr| 

जब आप एक मजबूर डाली प्रदर्शन:

b ->|vptr| 

यह निश्चित रूप से असुरक्षित है के बाद से एक एक उदाहरण को इंगित नहीं करता बी के बी या उप-वर्ग। जब आप वर्चुअल विधि को कॉल करते हैं या किसी फ़ील्ड को संशोधित करते हैं (इस मामले में नहीं), तो यह सामान्य रूप से undefined behavior या इस लेआउट में त्रुटि का कारण बन जाएगा।

हालांकि, आपकी विधि 1 गैर-वर्चुअल है, इसलिए वर्चुअल तालिका को देखने की कोई आवश्यकता नहीं है। चूंकि विधि 1 का कार्यान्वयन "इस" पर कुछ भी नहीं कर सकता है, इसलिए जब आप इस hypothetical ऑब्जेक्ट लेआउट में कोड चलाते हैं, तो यह रिपोर्ट की कोई त्रुटि नहीं होगी (जेम्स की टिप्पणी देखें)।

+0

हम्म। आपके उदाहरण लेआउट से, ऐसा लगता है जैसे वे वास्तव में समान थे। यह भी ध्यान रखें कि ओपी द्वारा दिए गए कोड में कोई वर्चुअल फ़ंक्शन शामिल नहीं है। – jogojapan

+0

ऑब्जेक्ट्स में विधियों को संग्रहीत नहीं किया जाता है, सदस्य फ़ंक्शन को आमंत्रित करने के लिए कोई ऑफ़सेट शामिल नहीं होता है (जब तक यह वर्चुअल नहीं होता है, इस स्थिति में फ़ंक्शन वर्चुअल विधि तालिका से पुनर्प्राप्त किया जाता है, जो ऑब्जेक्ट में संग्रहीत नहीं होता है)। –

+0

धन्यवाद, बस ध्यान दिया कि विधि 1 गैर-वर्चुअल है। – StarPinkER

3
  1. हां, यह संभव है।
  2. नहीं, यह मानक के अनुसार सुरक्षित नहीं है; यह निराश है।

यह सी शून्य * कास्टिंग की तरह है, जो सी ++ में करने की सबसे अच्छी बात नहीं है। लेकिन मैंने यह कई बार किया और यह ठीक काम करता है।

+0

डाउनकास्टिंग के लिए बहुत सारे महान उपयोग हैं। "वर्कस्पेस" को परिभाषित करने और फिर व्युत्पन्न "एल्गोरिदम" को परिभाषित करना, जिसमें उस कार्यक्षेत्र पर कोई डेटा सदस्य नहीं है। एल्गोरिदम बेहतर रूप से व्युत्पन्न के रूप में कार्यान्वित किए जाते हैं ... लेकिन एक एल्गोरिदम के पॉइंटर्स को हमेशा आधार पर सुरक्षित रूप से डाला जा सकता है। ऐसे फैक्ट्री की कल्पना करें जो इनका उत्पादन करती है ... बेस को यह पता नहीं होना चाहिए कि vtable क्या है। यह सब करता है और निष्पादित करता है। –

+0

@ErikAronesty, आपका तर्क महत्वपूर्ण है। यह किसी और के साथ अलग है, और मैं देखता हूं कि आपने असली दुनिया के उत्पाद में क्या कहा है। क्या आप कृपया थोड़ा और विस्तार कर सकते हैं? अर्थात। यह असुरक्षित नहीं है। – solotim