2011-01-12 8 views
8

यहाँ कोड का एक नमूना है कि मुझे गुस्सा दिलाती है:व्युत्पन्न कक्षा से बेस क्लास में संरक्षित विधि का उपयोग कैसे करें?

class Base { 
    protected: 
    virtual void foo() = 0; 
}; 

class Derived : public Base { 
    private: 
    Base *b; /* Initialized by constructor, not shown here 
       Intended to store a pointer on an instance of any derived class of Base */ 

    protected: 
    virtual void foo() { /* Some implementation */ }; 
    virtual void foo2() { 
     this->b->foo(); /* Compilator sets an error: 'virtual void Base::foo() is protected' */ 
    } 
}; 

कैसे आप संरक्षित overrided कार्य करने के लिए उपयोग करते हैं?

आपकी मदद के लिए धन्यवाद। : ओ)

+7

मुझे नहीं लगता कि आपका कार्यान्वयन काफी सही है। सदस्य चर के रूप में आपके पास बेस का उदाहरण क्यों है? यह-> बी-> foo() शुद्ध वर्चुअल विधि को कॉल करने का प्रयास करेगा। – GWW

+1

इस कार्यक्रम को संकलित नहीं करना चाहिए। आप एक अमूर्त वर्ग को तत्काल नहीं कर सकते .... जब तक 'बी' 'बेस' से व्युत्पन्न किसी अन्य वर्ग के उदाहरण को इंगित नहीं कर रहा है। – 341008

+0

मैंने परिशुद्धता छोड़ी: व्युत्पन्न :: बी विशेषता का उद्देश्य बेस –

उत्तर

8

संरक्षित सदस्यों केवल वर्तमान वस्तु से सुलभ हैं।
इस प्रकार, आप this->foo() कॉल करने के लिए अनुमति दी जाती है, लेकिन आप this->b->foo() कॉल करने के लिए अनुमति नहीं है। यह स्वतंत्र है कि Derivedfoo के लिए कार्यान्वयन प्रदान करता है या नहीं।

इस प्रतिबंध के पीछे कारण यह है कि अन्यथा सुरक्षित पहुंच को रोकने के लिए यह बहुत आसान होगा। आप बस Derived जैसी कक्षा बनाते हैं, और अचानक आपको अन्य वर्गों (जैसे OtherDerived) के हिस्सों तक पहुंच भी मिलती है जो बाहरी लोगों के लिए पहुंच योग्य नहीं थीं।

+0

धन्यवाद, अब मैं प्रतिबंध के कारणों को स्पष्ट रूप से समझता हूं ... यह एक सुरक्षा छेद होगा ... बड़ा एक! –

+5

कृपया इसे सुरक्षा छेद के रूप में न सोचें। एक्सेस संशोधक कोई सुरक्षा प्रदान नहीं करते हैं, यदि आप डेटा चाहते थे तो आप केवल स्मृति स्थान पढ़ सकते हैं। – DrYap

5

आम तौर पर, आप इसे Base::foo() का उपयोग करके करेंगे, जो वर्तमान उदाहरण के बेस क्लास को संदर्भित करता है।

हालांकि, अगर आपके कोड को जिस तरीके से आप कोशिश कर रहे हैं और इसे अनुमति नहीं है, तो आपको या तो foo() सार्वजनिक बनाना होगा या बेस के मित्र को व्युत्पन्न करना होगा।

0

आप गुंजाइश ऑपरेटर के साथ स्पष्ट रूप से आधार कार्य फोन (बेस :: foo())। लेकिन इस मामले में, बेस क्लास foo (यह शुद्ध वर्चुअल) परिभाषित नहीं करता है, इसलिए जब आप this->b->foo(); कहते हैं तो निष्पादित करने के लिए वास्तव में कोई फ़ंक्शन नहीं है क्योंकि बी बेस के लिए सूचक है और व्युत्पन्न नहीं है।

+1

से व्युत्पन्न कक्षाओं के किसी भी उदाहरण को स्टोर करना है, लेकिन ओपी का कोड वर्तमान उदाहरण के बेस क्लास को संदर्भित नहीं करता है। वह एक और उदाहरण का उपयोग कर रहा है, जो संभवतः एक व्युत्पन्न वर्ग है जो शुद्ध-वर्चुअल फ़ंक्शन लागू करता है। (अन्यथा, उदाहरण नहीं बनाया जा सका।) –

+0

@ जोनाथन वुड मैं समझता हूं कि आप क्या कह रहे हैं, लेकिन सिर्फ उस कोड से जा रहे हैं, ऐसा लगता है कि वह एक सार आधार वर्ग (बेस) को तुरंत चालू करने की कोशिश कर रहा है और शुद्ध कहता है वर्चुअल फ़ंक्शन (बेस :: foo()), जो नो-नो है (जैसा कि ऊपर वर्णित GWW और 341008 भी है)। – Gemini14

0

आप सुरक्षित ओवरराइड फ़ंक्शन तक कैसे पहुंचते हैं?

--- कहां से?

आप केवल एक विरासत के माध्यम से संरक्षित सदस्य तक पहुंच सकते हैं (उसी वर्ग के तरीकों के अलावा)। कहना उदाहरण के लिए यदि आप एक class Derived1 जो Derived से विरासत है, तो Derived1 की वस्तुओं foo() कॉल कर सकते हैं।

संपादित करें: MSDN article संरक्षित पहुंच विनिर्देशक पर। एक आधार स्तरीय में

1

यह थोड़ा कमजोर होगा यह काम नहीं है, लेकिन वर्गों के साथ यहां आपके द्वारा निर्धारित,?

virtual void foo2() { 
    reinterpret_cast<Derived *>(this->b)->foo(); 
} 

आधार वस्तु के लिए vtable पर reinterpret_cast अंक, और इस के सदस्यों एक्सेसर के माध्यम से यह कहता है।

2

एक समाधान Base में स्थिर संरक्षित फ़ंक्शन घोषित करना होगा जो कॉल को निजी/संरक्षित फ़ंक्शन (उदाहरण में foo) पर रीडायरेक्ट करता है।

चलें कहते हैं:

class Base { 
protected: 
    static void call_foo(Base* base) { base->foo(); } 
private: 
    virtual void foo() = 0; 
}; 

class Derived : public Base { 
private: 
    Base* b; 
protected: 
    virtual void foo(){/* Some implementation */}; 
    virtual void foo2() 
    { 
     // b->foo(); // doesn't work 
     call_foo(b); // works 
    } 
}; 

इस तरह, हम कैप्सूलीकरण नहीं टूटते क्योंकि Base के डिजाइनर, एक स्पष्ट विकल्प सभी व्युत्पन्न वर्ग एक दूसरे पर foo कॉल करने के लिए अनुमति देने के लिए कर सकते हैं, जबकि foo डाल करने से परहेज सार्वजनिक इंटरफेस में या दोस्तों में Base के सभी संभावित उप-वर्गों को स्पष्ट रूप से बदलना।

इसके अलावा, इस पद्धति है कि क्या foo की परवाह किए बिना काम करता है आभासी या नहीं, या क्या यह निजी या सुरक्षित है।

Here ऊपर कोड और here थोड़ा और व्यापार तर्क के साथ एक ही विचार का एक और संस्करण के चल रहे संस्करण के लिए एक कड़ी है।

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