2010-11-28 37 views
13

मुझे सदस्य रूपांतरण में सूचक के लिए प्रासंगिक सी ++ 03 मानक ड्राफ्ट में निम्नलिखित अनुच्छेद मिले।सदस्य रूपांतरण के लिए सूचक

4,11/2 सदस्य रूपांतरण करने के लिए सूचक

प्रकार के "प्रकार सीवी टी, के बी के सदस्य के लिए सूचक" एक rvalue जहां बी एक वर्ग प्रकार है, प्रकार का एक rvalue में बदला जा सकता "डी प्रकार के सीवी टी के सदस्य के लिए सूचक," जहां बी बी का एक व्युत्पन्न वर्ग (खंड 10) है। यदि बी एक अप्राप्य (धारा 11) है, अस्पष्ट (10.2) या वर्चुअल (10.1) बेस क्लास डी, ए कार्यक्रम जो इस रूपांतरण की जरुरत है वह खराब है। रूपांतरण का परिणाम रूपांतरण के पहले सदस्य के रूप में एक ही सदस्य को संदर्भित करता है, लेकिन यह बेस क्लास सदस्य को संदर्भित करता है जैसे कि यह व्युत्पन्न कक्षा का सदस्य था। परिणाम बी के उदाहरण में बी को संदर्भित करता है। परिणामस्वरूप "डी प्रकार के सीवी टी के सदस्य के लिए सूचक" टाइप किया गया है, इसे डी ऑब्जेक्ट से संदर्भित किया जा सकता है। परिणाम एक ही है, जैसे कि बी के सदस्य के लिए सूचक अशक्त सदस्य सूचक मूल्य गंतव्य type.52 की अशक्त सदस्य सूचक मूल्य में बदल जाती है डी बी उप वस्तु)

साथ dereferenced गया 5.2.9/9 static_cast

"के प्रकार CV1 टी डी के सदस्य के लिए सूचक" प्रकार का एक rvalue, जहां "के प्रकार CV2 टी बी के सदस्य के लिए सूचक" प्रकार का एक rvalue में बदला जा सकता बी डी का एक बेस क्लास (क्लॉज 10) है, यदि "टाइप ऑफ टी के सदस्य से सूचक" से वैध मानक रूपांतरण "टाइप टी के सदस्य के सूचक के लिए सूचक" मौजूद है (4.11), और सीवी 2 एक ही सीवी है -qualification सीवी 1.63 की तुलना में, या अधिक सीवी-योग्यता) शून्य सदस्य सूचक मूल्य (4.11) गंतव्य प्रकार के शून्य सदस्य सूचक मान में परिवर्तित हो जाता है। यदि कक्षा बी में मूल सदस्य होता है, या मूल सदस्य वाले वर्ग का मूल या व्युत्पन्न वर्ग होता है, तो मूल सदस्य को सदस्य अंक के परिणामस्वरूप सूचक। अन्यथा, कास्ट का परिणाम अपरिभाषित है। [नोट: हालांकि कक्षा बी को में मूल सदस्य, ऑब्जेक्ट का डायनामिक प्रकार नहीं है जिस पर सदस्य को पॉइंटर को संदर्भित किया गया है, मूल सदस्य होना चाहिए; 5.5 देखें। ]

तो मेरा प्रश्न यहां है। 5.2.9/9 के अनुसार, यदि 4.11/2 में वर्णित वैध रूपांतरण मौजूद है, तो डी के सदस्य को एक सूचक को बी के सदस्य को परिवर्तित किया जा सकता है। क्या इसका मतलब यह है कि यदि डी का सदस्य 'एम' है जिसे बी से विरासत में नहीं मिला है, तो सदस्य 'एम' के सूचक को बी के सदस्य को सूचक के प्रकार में नहीं डाला जा सकता है?

class Base { }; 
class Derived : public Base 
{ 
    int a; 
}; 
typedef int Base::* BaseMemPtr; 
BaseMemPtr pa = static_cast<BaseMemPtr>(&Derived::a); // invalid, as per 5.2.9/9 ? 

5.2.9/9 के नोट में यह भी कहा गया है कि हालांकि वर्ग बी मूल सदस्य, वस्तु, जिस पर किसी सदस्य के लिए सूचक मूल सदस्य शामिल होना चाहिए dereferenced है के गतिशील प्रकार के होते हैं की जरूरत नहीं है ।

मुझे पैराग्राफ के शब्द से भ्रमित हो जाता है। क्या कोड वैध है?

मैं इस साइट की खोज, और वहाँ एक समान प्रश्न, c++ inheritance and member function pointers, जिसका जवाब केवल मामला है कि आधार वर्ग के किसी सदस्य के लिए सूचक से रूपांतरण व्युत्पन्न वर्ग के सदस्य सूचक को कवर किया है।

+0

आप सदस्य फ़ंक्शन वैरिएबल को पॉइंटर को डेटा सदस्य मान में पॉइंटर असाइन कर रहे हैं। अन्यथा, हाँ, "कास्ट का परिणाम अपरिभाषित है।" – Potatoswatter

+0

धन्यवाद, मैंने इसे ठीक किया। – ashen

उत्तर

10

आपके द्वारा लिखे गए कोड पूरी तरह से मान्य हैं। इसके साथ कुछ भी गलत नहीं है (इस तथ्य से अलग कि Derived::a निजी है)। यह अच्छी तरह से गठित है और व्यवहार परिभाषित किया गया है (अब तक)। जैसा कि मानक के उद्धृत हिस्से में कहा गया है, स्पष्ट static_cast का उपयोग करके सदस्य पॉइंटर्स को अपनाने के लिए यह पूरी तरह कानूनी है, जो आप कर रहे हैं। 5.2.9/9 कभी नहीं कहता है कि अंकित सदस्य को बेस क्लास में उपस्थित होना है।

इसके अलावा, के रूप में आप सही ढंग से मानक से उद्धृत, वस्तु में वास्तविक सदस्य की उपस्थिति बाद में आवश्यक है सूचक की भिन्नता के पल में, प्रारंभ के समय नहीं। यह, ज़ाहिर है, सदस्य-पहुंच ऑपरेटर (->* या .*) के बाईं ओर उपयोग की गई वस्तु के गतिशील प्रकार पर निर्भर करता है। प्रकार केवल रन-टाइम पर जाना जाता है और इस प्रकार कंपाइलर द्वारा जांच नहीं की जा सकती है।

इस आवश्यकता 5.2.9/9 में एक मात्र नोट के रूप में शामिल किया गया है, लेकिन यह 5,5/4

4 में एक और अधिक औपचारिक रूप में दोहराया गया वस्तु के गतिशील प्रकार शामिल नहीं है तो सदस्य जो सूचक इंगित करता है, व्यवहार अपरिभाषित है।

तो, अच्छी तरह से गठित उदाहरण के लिए, अपने उदाहरण के संदर्भ में कोड की निम्न लाइनों रहे

Base b; 
b.*pa; // 1 

Derived d; 
d.*pa; // 2 

Base *pb = &d; 
pb->*pa; // 3 

हालांकि, पहली भिन्नता अपरिभाषित व्यवहार (के बाद से वस्तु b सदस्य शामिल नहीं है का उत्पादन), जबकि दूसरा और तीसरा दोनों पूरी तरह से कानूनी हैं।

+0

उत्कृष्ट जवाब। लेकिन मैं इस बात का जिक्र नहीं कर सकता कि 'आकार बी बी * पी' परिभाषित व्यवहार देता है, एक अपरिवर्तनीय सदस्य "dereferencing" के बावजूद। (क्योंकि सी ++ में कुछ भी सरल नहीं है ... :-P) –

+1

@j_random_hacker: ठीक है, हाँ। मेरे मामले में अपरिभाषित व्यवहार का अवसर अभिव्यक्ति के * मूल्यांकन * के दौरान सूचक अव्यवस्था की प्रक्रिया से जुड़ा हुआ है, जबकि 'आकार' के मामले में तर्क का मूल्यांकन कभी नहीं किया जाता है। – AnT

+0

वीसी सी 4407 चेतावनी को उत्सर्जित करता है जब मैं व्युत्पन्न वर्ग के दूसरे सदस्य प्रकार के सदस्य को फ़ंक्शन करने के लिए पॉइंटर को स्थिर करता हूं, इसलिए मानक और आपके उत्तर के अनुसार, यह मानक अनुरूप नहीं है, है ना? – ashen

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