2011-01-10 15 views
8

निम्न कोड में downcasting, जबकि case 1 में obj के निर्माण हम किसी भी कैसे derived वर्ग भी बनाएगी लेकिन यह सदस्य कार्यों सिर्फ obj के लिए दुर्गम हैं। तो नीचे - कास्टिंग (यानी, 2 मामले में), obj का उपयोग स्रोत के रूप में करते हुए, हम किसी भी प्रकार का निर्माण derived बनाते हैं। obj को पॉलिमॉर्फिक की आवश्यकता क्यों होगी?सी ++ dynamic_cast - बहुरूपी आवश्यकता और

यदि मैंने आपको उपर्युक्त विवरण के साथ भ्रमित किया है, तो क्यों उग्र obj को पॉलिमॉर्फिक होने की आवश्यकता नहीं है, लेकिन dynamic_cast का उपयोग करते समय डाउनकास्ट होने की आवश्यकता है?

class base 
{ 
    public: 
    base() 
    { 
     cout<< " \n base constructor \n"; 
    } 
}; 

class derived:public base 
{ 
    public: 
    derived() 
    { 
     cout <<" \n derived constructor \n"; 
    } 
}; 

base *obj = dynamic_cast<base*> (new derived) ; // case 1: explicitly upcasting 
derived *OBJ = dynamic_cast<derived*> (obj) ; // case 2: error 

धन्यवाद।

उत्तर

6

[expr.dynamic.cast] से 5.2.7/1:

अभिव्यक्ति dynamic_cast<T>(v) का परिणाम अभिव्यक्ति वी परिवर्तित टाइप करने के लिए टी

[का परिणाम है .. ।]

तो टी और वी "CV1 बी को सूचक" ऐसी है कि बी डी का एक आधार वर्ग है "CV2 डी करने के लिए सूचक" टाइप किया है, परिणाम एक सूचक है डी वस्तु की अनूठी बी उप वस्तु को वी द्वारा की ओर इशारा किया।

[...]

अन्यथा, वी करने के लिए एक सूचक या एक बहुरूपी प्रकार का एक lvalue होगा।

मानक भी निम्न उदाहरण जो दिखाता है कि बहुरूपी प्रकार की आवश्यकता के लिए आधार रूपांतरण के लिए ली गई खड़े नहीं करता है प्रदान करता है: जब आप खिन्न, आप संकलक कह रहे हैं: इस तरह से इसके बारे में

struct B {}; 
struct D : B {}; 
void foo(D* dp) 
{ 
    B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp; 
} 
0

Think कि आप एक बहुलक वर्ग सूचक को इंगित करना चाहते हैं। लेकिन जब आप गतिशील_कास्ट का उपयोग करके उथल-पुथल कर रहे हैं, तो यह कहता है, "जब आप मुझसे व्युत्पन्न होते हैं तो आप मुझे पहले ही मिल चुके हैं, आप मुझे गतिशील_कास्ट का स्पष्ट रूप से उपयोग क्यों करना चाहते हैं?" और इसलिए संकलक एक त्रुटि देता है। यही है, संकलक देखता है कि व्युत्पन्न वर्ग में, उनका प्रकार बेस का उप-भाग है और इसलिए यह जानता है कि प्रोग्रामर को स्पष्ट रूप से इसे पॉइंटर डालने की आवश्यकता नहीं है (और संभवतः विनाश बनाते हैं)।

मुझे उम्मीद है कि स्पष्टीकरण मदद करता है।

+0

कुछ स्पष्ट नहीं है अगर मैं स्पष्ट रूप से अपवाद करता हूं, जो मानक दस्तावेज़ों में स्पष्ट रूप से कहता है। – Mahesh

15

डायनामिक_कास्ट ऑब्जेक्ट को काम करने के लिए ऑब्जेक्ट को पॉलिमॉर्फिक होने की आवश्यकता है। इसका कारण यह है कि dynamic_cast को उस प्रकार की जानकारी संग्रहीत करने की आवश्यकता है जो कास्ट करने के लिए उपयोग की जाएगी, और यह कक्षा के लिए vtable के साथ जानकारी संग्रहीत करके करता है। एक vtable होने के लिए आपको कम से कम एक विधि वर्चुअल बनाने की आवश्यकता है।

बेस क्लास विनाशक को आभासी के रूप में ध्वजांकित करना सबसे आसान तरीका है।

उपक्रम (यानी आधार पर व्युत्पन्न) को कास्ट की आवश्यकता नहीं है क्योंकि संकलक यह जांचने में सक्षम है कि कास्ट संकलन समय पर काम करेगा। हालांकि, डाउनकास्टिंग के दौरान भी यह सच नहीं है।

+1

आप इस उदाहरण में 'static_cast' के साथ डाउनकास्ट कर सकते हैं। आप संकलित समय पर जानते हैं कि 'obj' में सही वर्ग है। डायनामिक_कास्ट के लिए उपयोग तब होता है जब आप संकलन समय पर नहीं जानते हैं यदि ऑब्जेक्ट किसी दूसरे से प्राप्त होता है। जैसे जब आप किसी फ़ंक्शन से पॉइंटर प्राप्त करते हैं और यह जांचने की आवश्यकता होती है कि लौटाई गई वस्तु किसी निश्चित वर्ग से संबंधित है या नहीं। (लेकिन आप सही हैं, वे आभासी होना चाहिए।) – RedX

0

Dynamic_cast

  • यह एक व्युत्पन्न सूचक में एक आधार सूचक कास्ट करने के लिए प्रयोग किया जाता है। यदि आधार सूचक किसी ऑब्जेक्ट को इंगित नहीं करता है, तो यह
  • देता है इसका उपयोग संदर्भ संदर्भ में आधार संदर्भ डालने के लिए किया जाता है। यदि संदर्भ व्युत्पन्न के किसी ऑब्जेक्ट पर इंगित नहीं कर रहा है, तो यह std :: bad_cast फेंकता है।
  • इसे चेक किया गया कास्ट static_cast के बराबर माना जा सकता है, जिसमें यह जांचता है कि ऑब्जेक्ट पर इंगित करता है कि वास्तव में व्युत्पन्न प्रकार का है।

आपको डायनेमिक_कास्ट (उदाहरण के साथ) there के बारे में और अधिक पढ़ना होगा।

0
B* b = new D(); 
D* d = dynamic_cast<D*>(b); 

ऊपर के उदाहरण में सबसे compilers की जाँच करके गतिशील कलाकारों को लागू करेगा कि व्युत्पन्न वर्ग डी या नहीं की vtable को ख अंकों की vtable सूचक। यदि हां, तो यह केवल बी के पते को वापसी मूल्य के रूप में देता है अन्यथा यह एक nullptr देता है। यह वही है संभवतः पर्दे के पीछे पर चला जाता है जब एक गतिशील कलाकारों को निष्पादित करता है: -

class car 
{ 
    public: 
    virtual void drive() 
    { 
     std::cout <<"car"<<std::endl; 
    } 
}; 
class toyota: public car 
{ 
    public: 
    virtual void drive() 
    { 
     std::cout <<"toyota"<<std::endl; 
    } 
}; 

class honda: public car 
{ 
    public: 
     virtual void drive() 
    { 
     std::cout <<"honda"<<std::endl; 
    } 
}; 

template <typename Tderived> 
Tderived* dynamicCast(void* pBase) 
{ 
    //compare the vptr of the class pointed by pBase with a temporary Tderived class. 
    //If vptr of pBase and vptr of Tderived() are pointing to the same vtable 
    //then it can be safely deduced that pBase is indeed pointing to an instance of Tderived 
    if (*(int**)pBase == *(int**)&Tderived()) 
    { 
     return (Tderived*)pBase; 
    } 
    else 
    { 
     return nullptr; 
    } 
} 


int main() 
{ 
    car* pCar; 
    honda hondaCar; 
    toyota toyotaCar; 

    pCar = &toyotaCar; 

    honda* pHonda = dynamicCast<honda>(pCar); 
    if (nullptr != pHonda) 
    { 
     pHonda->drive(); 
    } 
    else 
    { 
     toyota* pToyota = dynamicCast<toyota>(pCar); 
     if (nullptr != pToyota) 
     { 
      pToyota->drive(); 
     } 
    } 
} 

अब, अगर वर्ग बहुरूपी नहीं है, वहाँ संकलक कि क्या PCAR होंडा या टोयोटा की ओर इशारा करते है खोजने के लिए कोई रास्ता नहीं है गाड़ी। ध्यान दें कि यह गतिशील_कास्ट को लागू करने के तरीकों में से एक है क्योंकि सी ++ मानक vtables के बारे में कुछ भी नहीं बोलता है।

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