c++ - गलत कास्ट-क्या यह कास्ट या उपयोग है जो अपरिभाषित व्यवहार है




casting language-lawyer (2)

यदि मैं आधार से व्युत्पन्न प्रकार तक कास्ट करता हूं, लेकिन बेस प्रकार व्युत्पन्न प्रकार का उदाहरण नहीं है, लेकिन केवल परिणाम का उपयोग करें यदि यह है, तो क्या मुझे अपरिभाषित व्यवहार मिलता है?

यह समझने में मुश्किल है कि मैं क्या पूछ रहा हूं? इस उदाहरण पर एक नज़र डालें:

struct Animal { int GetType(){...} };
struct Dog : Animal { bool HasLoudBark(){...}};
struct Cat : Animal { bool HasEvilStare(){...} };

Animal * a = ...;
Dog* d = static_cast<Dog*>(a);

if(a->GetType() == DogType && d->HasLoudBark())
    ....

इस मामले a एक Dog हो सकता है या नहीं। हम हमेशा a Dog * d लिए static_cast करते हैं Dog * d लेकिन हम कभी भी d उपयोग नहीं करते हैं जब तक कि हमें इसका Dog

यह मानते हुए कि a Dog नहीं है, क्या कलाकारों के बिंदु पर यह अपरिभाषित व्यवहार है? या इसे तब तक परिभाषित किया जाता है जब तक हम वास्तव में d उपयोग नहीं करते हैं जब तक कि यह वास्तव में एक Dog ?

मानक के प्रासंगिक भागों के संदर्भ की सराहना की जाती है।

(हां मुझे पता है कि मैं डायनेमिक_कास्ट, और आरटीटीआई का उपयोग कर सकता हूं, और शायद यह महान कोड नहीं है, लेकिन मुझे इस बात में अधिक दिलचस्पी है कि क्या यह मान्य है)


कलाकारों के पास अपरिभाषित व्यवहार होता है। C ++ 17 (n4659) को उद्धृत करते हुए [expr.static.cast] 8.2.10 / 11:

" Cv1 B लिए सूचक" का एक प्रकार, जहां B एक वर्ग प्रकार है, को " cv2 D सूचक" के प्रकार में बदला जा सकता है, जहाँ D एक वर्ग व्युत्पन्न है (Clause 13) B , यदि cv2 है तो cv1 की तुलना में समान cv- योग्यता, या उससे अधिक cv- योग्यता। ... यदि " B लिए पॉइंटर टाइप टू cv1 B " का संकेत है जो कि वास्तव में टाइप D ऑब्जेक्ट का सब -जेक्ट है , तो परिणामस्वरूप पॉइंटर टाइप D के एन्क्लोजिंग ऑब्जेक्ट की ओर इशारा करता है। अन्यथा, व्यवहार अपरिभाषित है।


यह अपरिभाषित व्यवहार है , लेकिन (मज़ाकिया पर्याप्त) यदि आप static_cast बजाय reinterpret_cast उपयोग किया होता, तो आप उस दानव को निकाल देते।

[expr.reinterpret.cast]/7

ऑब्जेक्ट पॉइंटर को एक अलग प्रकार के ऑब्जेक्ट पॉइंटर में स्पष्ट रूप से परिवर्तित किया जा सकता है। जब ऑब्जेक्ट पॉइंटर टाइप का प्रचलित v ऑब्जेक्ट पॉइंटर टाइप "पॉइंटर टू cv T " में परिवर्तित हो जाता है, तो परिणाम static_cast<cv T*>(static_cast<cv void*>(v))

जैसा कि उपयोगकर्ता Angew द्वारा उल्लेख किया गया है, इसके लिए "एक विशेष आंतरिक प्रतिनिधित्व की आवश्यकता होती है जो सुनिश्चित करता है कि static_cast<void*>(d) == static_cast<void*>(a) जब a == d "।

यह [class.mem]/22 से 26 द्वारा व्यक्त किया गया है:

[class.mem]/26

यदि मानक-लेआउट वर्ग ऑब्जेक्ट में कोई भी गैर-स्थिर डेटा सदस्य है, तो इसका पता उसके पहले गैर-स्थिर डेटा सदस्य के पते के समान है यदि वह सदस्य बिट-फ़ील्ड नहीं है। इसका पता भी इसके प्रत्येक बेस क्लास सबजेक्ट के पते के समान है।

इसलिए यदि Animal का GetType() Animal और Dog के सामान्य प्रारंभिक अनुक्रम से एक गैर-स्थैतिक डेटा सदस्य का मान लौटाता है, तो व्यवहार को परिभाषित किया गया है।

उन आवश्यकताओं को पूरा किया जाता है जब सरल विरासत और डिफ़ॉल्ट-संरेखित वस्तुओं के साथ काम करते हैं।





undefined-behavior