2010-06-15 15 views
5

मैं कक्षा को अपने 'इस' सूचक को अपने इंटरफेस में से किसी एक के सूचक में बदलने में सक्षम होने से रोकने की कोशिश कर रहा हूं। मैं इसे एक मध्य प्रॉक्सी कक्षा के माध्यम से निजी विरासत का उपयोग करके करता हूं। समस्या यह है कि मुझे निजी विरासत पदानुक्रम में विरासत वर्ग के तहत सभी वर्गों के लिए सभी सार्वजनिक स्थैतिक सदस्यों और आधार वर्ग के प्रकारों को पहुंच योग्य बनाता है।सी ++ निजी विरासत और स्थिर सदस्य/प्रकार

class Base 
{ 
public: 
    enum Enum 
    { 
     value 
    }; 
}; 

class Middle : private Base 
{ 
}; 

class Child : public Middle 
{ 
public: 
    void Method() 
    { 
     Base::Enum e = Base::value; // doesn't compile BAD!  
     Base* base = this; // doesn't compile GOOD! 
    } 
}; 

मैंने इसे वीएस -2008 (आवश्यक संस्करण) और वीएस -2010 दोनों में करने की कोशिश की है, न तो काम।

क्या कोई कामकाज के बारे में सोच सकता है? या रूपांतरण को रोकने के लिए एक अलग दृष्टिकोण?

मैं भी व्यवहार के curios हूँ, यह सिर्फ कंपाइलर कार्यान्वयन का एक दुष्प्रभाव है, या यह डिजाइन द्वारा है? अगर डिजाइन द्वारा, तो क्यों? मैंने हमेशा निजी विरासत के बारे में सोचा कि इसका मतलब है कि कोई भी बेस से मध्य विरासत को नहीं जानता है। हालांकि, प्रदर्शित व्यवहार का अर्थ है कि निजी विरासत का मतलब उससे कहीं अधिक है, असल में बच्चे को श्रेणी पदानुक्रम में किसी भी नामस्थान की तुलना में बेस तक कम पहुंच नहीं है!

+0

+1: वास्तव में एक बहुत ही रोचक सवाल है। –

उत्तर

6

आप पूरी तरह से यह योग्यता से Base::Enum उपयोग करने में सक्षम होना चाहिए:

नोट:

class Child : public Middle 
{ 
public: 
    void Method() 
    { 
     ::Base::Enum e = ::Base::value; 
    } 
}; 

यह व्यवहार भाषा (सी ++ 03 §11.2/3) द्वारा निर्दिष्ट है: एक निजी बेस क्लास का सदस्य विरासत सदस्य नाम के रूप में पहुंच योग्य नहीं हो सकता है, लेकिन सीधे पहुंच योग्य है।

इसके बाद एक विस्तारित उदाहरण है जो आपके उदाहरण कोड के प्रभावी ढंग से समान है।

हालांकि, ऐसा लगता है कि न तो विजुअल सी ++ 2008 और न ही विजुअल सी ++ 2010 सही ढंग से लागू करता है, इसलिए आप ::Base::Enum टाइप कर सकते हैं, फिर भी आप ::Base::value तक नहीं पहुंच सकते हैं। (असल में, विज़ुअल सी ++ में यह बहुत गलत पाया गया है, क्योंकि यह गलत तरीके से आपको पूरी तरह से योग्य Base::Enum का उपयोग करने की अनुमति देता है)।

"आसपास" करने के लिए बात नहीं, आप Middle वर्ग के लिए घोषणाओं का उपयोग कर जोड़ सकते हैं:

class Middle : private Base 
{ 
protected: 

    using Base::Enum; 
    using Base::value; 
}; 

यह आपको अपने Child कक्षा में Base::Enum या Base::value का उपयोग नहीं होगा, लेकिन यह करने के लिए आप की अनुमति देगा Enum और value या Middle::Enum और Middle::value का उपयोग करें।

+1

मैंने विजुअल सी ++ बग से संबंधित माइक्रोसॉफ्ट कनेक्ट पर एक बग रिपोर्ट जमा की: https://connect.microsoft.com/VisualStudio/feedback/details/567693/ –

+0

आपके विस्तृत उत्तर के लिए धन्यवाद। एक बग के कारण यह परेशान है। दुर्भाग्य से मध्य वर्ग में उपयोग करना मेरे असली दुनिया के मामले में एक विकल्प नहीं है, क्योंकि मध्य एक टेम्पलेटेड क्लास है जो बेस क्लास को टाइप तर्क के रूप में लेता है। मेरा एकमात्र विकल्प इंटरफ़ेस के बाहर enum को स्थानांतरित करना है। – WearyMonkey

+0

मैं ध्यान दूंगा कि मैंने जो मानक उद्धृत किया है, उससे "नोट" वास्तव में कुछ भी निर्दिष्ट नहीं करता है, यह सिर्फ इस व्यवहार को समझाता है। मेरा अनुमान है कि इस व्यवहार का वास्तविक विनिर्देश विभिन्न खंडों के माध्यम से फैला हुआ है जो बताते हैं कि नाम संकल्प कैसे होता है। –

1

मेरे पास केवल एक प्रश्न है: आप निजी विरासत क्यों देते हैं?

विरासत, मेरी राय में, काफी एक टूटी हुई अवधारणा है, क्योंकि यह एक जिम्मेदारी सिद्धांत का उल्लंघन करता है:

  • आप इंटरफ़ेस
  • आप कार्यान्वयन

दुर्भाग्य से विरासत की आवश्यकता है वारिस वारिस ऑब्जेक्ट ओरिएंटेड कोड में बहुरूपता के लिए, इसलिए आप इस मामले में इससे दूर शर्मिंदा नहीं हो सकते हैं।

लेकिन यहां आप स्पष्ट रूप से बहुरूपता का उपयोग नहीं करना चाहते हैं, इसलिए मुझे लगता है कि विरासत का उपयोग क्यों करना है, क्योंकि यह इसका एकमात्र दिलचस्प उपयोग है (आईएमओ)।

इसके बजाय, सी ++ में, आप का उपयोग कर सकते हैं:

  • संरचना, कोड पुन: उपयोग के लिए
  • नि: शुल्क कार्य (अपने स्वयं के नाम स्थान में परिभाषित)
  • using, typedef आदि ... से वस्तुओं लाने के लिए कक्षा के बाहर

आपका उदाहरण यहाँ विवश लगता है, लेकिन मैं भी struct में मेरी enums लपेट एक से नाम स्थान प्रदूषण को रोकने के लिए हजार प्रतीकों (और क्योंकि struct टेम्पलेट पैरामीटर के रूप में उपयोग किया जा सकता है wheres नामस्थान नहीं कर सकते हैं)।

struct MyEnum 
{ 
    enum type 
    { 
    value 
    }; 
}; 

class Child 
{ 
public: 
    typedef MyEnum::type Enum; 

    Child(Enum e = MyEnum::value); 

private: 
}; 

मैं नाम योग्यता के साथ कुछ भी गलत नहीं देखते हैं, बजाय मुझे लगता है यह यह आसान बनाता है, क्योंकि आप जानते हैं कि कौन enum के बारे में हम बात कर रहे हैं, फिर से पढ़ने के लिए ...

वास्तव में, private विरासत सबसे अच्छा बचा है (और आमतौर पर संरचना द्वारा प्रतिस्थापित)। एकमात्र वैध मामला (आईएमओ) खाली बेस अनुकूलन के लिए है ... और स्पष्ट रूप से यह अक्सर आपको इसकी आवश्यकता नहीं होती है (ऑप्टिमाइज़ेशन के साथ सामान्य रूप से)।

+0

निजी विरासत के लिए अन्य उपयोग यह है कि यदि आपको कक्षा के संरक्षित सदस्यों तक पहुंच की आवश्यकता है। यह एक आदर्श स्थिति नहीं है, लेकिन यह दुर्लभ मौकों पर आता है। मैं निश्चित रूप से सहमत हूं कि यह सबसे अच्छा बचा है। –

+0

मैं आमतौर पर इस बिंदु पर decouple करना पसंद करता हूं: मैं एक मध्यम वर्ग बनाता हूं जो सार्वजनिक रूप से विरासत में आता है और संरचना का उपयोग करता है। –

+0

मैं निश्चित रूप से सहमत हूं कि जहां संभव हो वहां संरचना विरासत के लिए बेहतर है। हालांकि, मेरी असली दुनिया की समस्या में बेस क्लास एक पुराने बड़े कोड बेस में कोर क्लास है, उचित रिफैक्टर नौकरी करने का मतलब अधिकांश कोड को फिर से लिखना होगा। – WearyMonkey

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