2011-08-08 18 views
29

नीचे एक उदाहरण के संरक्षित फ़ील्ड x तक पहुंचने का एक सूक्ष्म उदाहरण है। बी ए का उप-वर्ग है इसलिए टाइप बी के किसी भी चर के प्रकार ए बी :: foo() का उपयोग बी के x फ़ील्ड का उपयोग क्यों कर सकता है, लेकिन एक्स का फ़ील्ड नहीं है?सूक्ष्म सी ++ विरासत त्रुटि

class A { 
protected: 
    int x; 
}; 

class B : public A { 
protected: 
    A *a; 
    B *b; 
public: 
    void foo() { 
    int u = x;  // OK : accessing inherited protected field x 
    int v = b->x; // OK : accessing b's protected field x 
    int w = a->x; // ERROR : accessing a's protected field x 
    } 
}; 

यहाँ त्रुटि मैं जी ++

$ g++ -c A.cpp 
A.cpp: In member function ‘void B::foo()’: 
A.cpp:3: error: ‘int A::x’ is protected 
A.cpp:14: error: within this context 

उत्तर

2

साथ मिल लोक विरासत में है:
बेस कक्षा के सभी Public membersव्युत्पन्न वर्ग की Public Members बन &
सभी Protected membersबेस ई कक्षाDerived Class के Protected Members बनें।

उपर्युक्त नियम के अनुसार:
संरक्षित सदस्य xA से वर्ग B के सदस्य संरक्षित हो जाता है।

class B अपने सदस्य समारोह foo में अपनी ही संरक्षित सदस्यों तक पहुँच सकते हैं, लेकिन यह कर सकते हैं A का ही पहुँच सदस्यों के माध्यम से जो यह A नहीं सभी वर्गों निकाला गया था।

इस मामले में, class B यह इस निहित वर्ग की रक्षा की सदस्य तक नहीं पहुँच सकता, एक A सूचक a शामिल हैं।

क्यों B::foo() पहुँच के सदस्यों class B सूचक b निहित कर सकते हैं?

नियम है:
प्रति वर्ग आधार पर सी ++ अभिगम नियंत्रण कार्यों में, पर नहीं प्रति-वस्तु के आधार पर।
तो class B का एक उदाहरण हमेशा class B के किसी अन्य उदाहरण के सभी सदस्यों तक पहुंच प्राप्त करेगा।

एक कोड नमूना है, जो शासन को दर्शाता है:

#include<iostream> 

class MyClass 
{ 
    public: 
     MyClass (const std::string& data) : mData(data) 
     { 
     } 

     const std::string& getData(const MyClass &instance) const 
     { 
      return instance.mData; 
     } 

    private: 
     std::string mData; 
}; 

int main() { 
    MyClass a("Stack"); 
    MyClass b("Overflow"); 

    std::cout << "b via a = " << a.getData(b) << std::endl; 
    return 0; 
} 
+0

लेकिन वस्तु है 'x' इस उदाहरण में' b' के एक संरक्षित सदस्य है , और पहुंच की अनुमति नहीं है। मुझे नहीं लगता कि यह सवाल का जवाब देता है। –

+0

@ बिली ओनेल: सी ++ एक्सेस कंट्रोल में प्रति-वर्ग आधार पर काम करता है, प्रति-ऑब्जेक्ट आधार पर नहीं, इसलिए कक्षा बी का ऑब्जेक्ट कक्षा बी के अन्य ऑब्जेक्ट के सदस्यों तक पहुंच सकता है। –

18

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

लेकिन ए के संरक्षित सदस्यों को A प्रकार की वस्तु का उपयोग करके कक्षा के बाहर एक्सेस नहीं किया जा सकता है।

यहाँ स्टैंडर्ड से प्रासंगिक पाठ (2003)

11,5 संरक्षित सदस्य पहुँच [वर्ग है।संरक्षित]

जब किसी व्युत्पन्न वर्ग का कोई मित्र या सदस्य फ़ंक्शन किसी संरक्षित गैर-सदस्यीय सदस्य फ़ंक्शन या बेस क्लास के संरक्षित गैर-डेटा संबंधी डेटा सदस्य को संदर्भित करता है, तब तक एक एक्सेस चेक क्लॉज 11.102 में वर्णित लोगों के अतिरिक्त लागू होता है) सदस्य को एक सूचक (5.3.1), का उपयोग व्युत्पन्न वर्ग (या उस वर्ग से प्राप्त किसी भी वर्ग) के सूचक, संदर्भ, या ऑब्जेक्ट के माध्यम से होना चाहिए (5.2.5)। यदि सदस्य को सूचक के लिए उपयोग करना है, तो नेस्टेड-नाम-विनिर्देशकर्ता व्युत्पन्न वर्ग (या उस वर्ग से प्राप्त वर्ग) का नाम देगा।

और उदाहरण के रूप में मानक (2003) से इस प्रकार ही: ऊपर के उदाहरण fr() में

[Example: 

class B { 
    protected: 
    int i; 
    static int j; 
}; 

class D1 : public B { 
}; 

class D2 : public B { 
    friend void fr(B*,D1*,D2*); 
    void mem(B*,D1*); 
}; 

void fr(B* pb, D1* p1, D2* p2) 
{ 
    pb->i = 1; // ill-formed 
    p1->i = 2; // ill-formed 
    p2->i = 3; // OK (access through a D2) 
    p2->B::i = 4; // OK (access through a D2, even though naming class is B) 
    int B::* pmi_B = &B::i; // ill-formed 
    int B::* pmi_B2 = &D2::i; // OK (type of &D2::i is int B::*) 
    B::j = 5; // OK (because refers to static member) 
    D2::j =6; // OK (because refers to static member) 
} 
void D2::mem(B* pb, D1* p1) 
{ 
    pb->i = 1; // ill-formed 
    p1->i = 2; // ill-formed 
    i = 3; // OK (access through this) 
    B::i = 4; // OK (access through this, qualification ignored) 
    int B::* pmi_B = &B::i; // ill-formed 
    int B::* pmi_B2 = &D2::i; // OK 
    j = 5; // OK (because j refers to static member) 
    B::j = 6; // OK (because B::j refers to static member) 
} 
void g(B* pb, D1* p1, D2* p2) 
{ 
    pb->i = 1; // ill-formed 
    p1->i = 2; // ill-formed 
    p2->i = 3; // ill-formed 
} 
—end example] 

नोट D2 के एक दोस्त समारोह है, mem()D2 के एक सदस्य समारोह है, और g() है न तो एक दोस्त, न ही एक सदस्य समारोह।

+1

क्योंकि यह सार्वजनिक विरासत है, 'ए' संरक्षित सदस्य 'बी' के संरक्षित सदस्य बन जाते हैं। निजी नहीं –

+0

@ बिली: सही। और जवाब भी ठीक किया। – Nawaz

+0

** सार्वजनिक Ihneritance ** में, बेस क्लास के संरक्षित सदस्य व्युत्पन्न वर्ग के संरक्षित यादगार बन जाते हैं और बेस क्लास के सार्वजनिक सदस्य व्युत्पन्न वर्ग के सार्वजनिक सदस्य बन जाते हैं। –

10

पर विचार करें:

class A { 
protected: 
    int x; 
}; 

class C : public A 
{ 
}; 

class B : public A { 
protected: 
    unique_ptr<A> a; 
public: 
    B() : a(new C) // a now points to an instance of "C" 
    { } 

    void foo() { 
    int w = a->x; // B accessing a protected member of a C? Oops. 
    } 
}; 
+0

यह एक अच्छा उदाहरण है! +1 – jweyrich

+0

यह इसकी व्याख्या नहीं करता है, क्योंकि आपके पास एक ही तर्क होगा यदि 'ए' और' foo 'दोनों' ए 'के सदस्य थे (यानी,' ए ''सी' का उदाहरण हो सकता है) - लेकिन यह सी ++ के साथ बस ठीक है! – wcochran

+0

@wcochran: सच नहीं है। इस उदाहरण में, 'बी'' सी' की विरासत श्रृंखला में नहीं है - इसे सी के किसी भी हिस्से तक पहुंच नहीं होनी चाहिए। यदि दोनों 'ए' के ​​सदस्य थे, तो 'ए' में होगा दोनों वर्गों की विरासत श्रृंखला। –

0

कक्षा B वर्ग A के समान नहीं है। यही कारण है कि कक्षा B के सदस्य कक्षा A के गैर-सार्वजनिक सदस्यों तक नहीं पहुंच सकते हैं।

दूसरी ओर, वर्ग Bव्युत्पन्न सार्वजनिक रूप से वर्ग A, इसलिए वर्ग B से अब एक (सुरक्षित) सदस्य x वर्ग B के किसी भी सदस्य का उपयोग कर सकते हैं जो है।

1

बी :: foo() का उपयोग बी के एक्स फ़ील्ड को क्यों नहीं कर सकता है, लेकिन एक्स का क्षेत्र नहीं है?

एक संरक्षित सदस्य को केवल उसी वर्ग (या व्युत्पन्न कक्षाओं) के अन्य सदस्यों द्वारा उपयोग किया जा सकता है।

b->x कक्षा बी (विरासत के माध्यम से) के एक संरक्षित सदस्य को इंगित करता है, इसलिए B::foo() इसका उपयोग कर सकता है।

a->x कक्षा ए के उदाहरण के संरक्षित सदस्य को इंगित करता है, इसलिए B::foo() इसका उपयोग नहीं कर सकता है।

0

मूल अवधारणा के साथ शुरू की सुविधा देता है,

class A { 
protected: 
    int x; 
}; 

class B : public A { 
public: 
    void foo() { 
    int u = x;  // OK : accessing inherited protected field 
    } 
}; 

के बाद से बच्चे को माता-पिता इनहेरिट है, बच्चे एक्स हो जाता है। इसलिए आप सीधे बच्चे के foo() विधि में एक्स तक पहुंच सकते हैं। यह संरक्षित चर की अवधारणा है। आप सीधे बच्चे में माता-पिता के संरक्षित चर का उपयोग कर सकते हैं। नोट: यहां मैं कह रहा हूं कि आप सीधे एक्स तक पहुंच सकते हैं लेकिन ए के ऑब्जेक्ट के माध्यम से नहीं! क्या फर्क पड़ता है ? चूंकि, एक्स संरक्षित है, आप ए के बाहर ए की संरक्षित वस्तुओं तक नहीं पहुंच सकते हैं। इससे कोई फर्क नहीं पड़ता कि यह कहां है - यदि इसका मुख्य या बच्चा है। यही कारण है कि आप निम्नलिखित तरीकों से

class B : public A { 
protected: 
    A *a; 
public: 
    void foo() { 
    int u = x;  // OK : accessing inherited protected field x 
    int w = a->x; // ERROR : accessing a's protected field x 
    } 
}; 

यहां एक दिलचस्प अवधारणा आती है। आप कक्षा में अपनी वस्तु का उपयोग कर कक्षा के एक निजी चर का उपयोग कर सकते हैं!

class dummy { 
private : 
int x; 
public: 
    void foo() { 
    dummy *d; 
    int y = d->x; // Even though x is private, still you can access x from object of d - But only with in this class. You cannot do the same outside the class. 
    } 
}; 

// समान चर के लिए है। इसलिए आप निम्न उदाहरण तक पहुंचने में सक्षम हैं।

class B : public A { 
protected: 
    A *a; 
    B *b; 
public: 
    void foo() { 
    int u = x;  // OK : accessing inherited protected field x 
    int y = b->x; // OK : accessing b's protected field x 
    int w = a->x; // ERROR : accessing a's protected field x 
    } 
}; 

आशा है कि यह बताते हैं :)

सी ++ पूरा ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग, जहां के रूप में जावा शुद्ध उन्मुख :)

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