c++ - निजी, सार्वजनिक, और संरक्षित विरासत के बीच अंतर




inheritance encapsulation (11)

निजी:

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

जनता:

बेस क्लास के सार्वजनिक सदस्यों को उस बेस क्लास के सदस्यों, इसके व्युत्पन्न वर्ग के सदस्यों के साथ-साथ आधार वर्ग और व्युत्पन्न कक्षा के बाहर के सदस्यों द्वारा एक्सेस किया जा सकता है।

संरक्षित:

बेस क्लास के संरक्षित सदस्यों को बेस क्लास के सदस्यों के साथ-साथ इसके व्युत्पन्न वर्ग के सदस्यों द्वारा भी पहुंचा जा सकता है।

संक्षेप में:

निजी : आधार

संरक्षित : आधार + व्युत्पन्न

सार्वजनिक : आधार + व्युत्पन्न + कोई अन्य सदस्य

सी ++ में public , private और protected विरासत के बीच क्या अंतर है? एसओ पर मिलने वाले सभी प्रश्न विशिष्ट मामलों के साथ सौदा करते हैं।


इसे मूल वर्ग के सार्वजनिक सदस्यों को व्युत्पन्न वर्ग से कैसे उजागर किया जाता है इसके साथ करना है।

  • सार्वजनिक -> बेस क्लास के सार्वजनिक सदस्य सार्वजनिक होंगे (आमतौर पर डिफ़ॉल्ट)
  • संरक्षित -> बेस क्लास के सार्वजनिक सदस्यों की रक्षा की जाएगी
  • निजी -> बेस क्लास के सार्वजनिक सदस्य निजी होंगे

चूंकि litb बताते हैं, सार्वजनिक विरासत पारंपरिक विरासत है जिसे आप अधिकांश प्रोग्रामिंग भाषाओं में देखेंगे। यह मॉडल "आईएस-ए" संबंध है। निजी विरासत, सीए ++ के लिए विशिष्ट कुछ AFAIK, संबंधों में लागू "नियमों में लागू" है। यही है कि आप व्युत्पन्न वर्ग में सार्वजनिक इंटरफ़ेस का उपयोग करना चाहते हैं, लेकिन नहीं चाहते कि व्युत्पन्न वर्ग के उपयोगकर्ता को उस इंटरफ़ेस तक पहुंच प्राप्त हो। कई लोग तर्क देते हैं कि इस मामले में आपको बेस क्लास को एकत्र करना चाहिए, जो बेस क्लास को निजी आधार के रूप में रखने के बजाय बेस क्लास की कार्यक्षमता का पुन: उपयोग करने के लिए व्युत्पन्न सदस्य बनें।


मुझे एक आसान जवाब मिला और इसलिए मुझे अपने भविष्य के संदर्भ के लिए पोस्ट करने का भी सोचा।

लिंक से इसकी http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/ विरासत- http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/ specifiers http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/

class Base
{
public:
    int m_nPublic; // can be accessed by anybody
private:
    int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)
protected:
    int m_nProtected; // can be accessed by Base member functions, or derived classes.
};

class Derived: public Base
{
public:
    Derived()
    {
        // Derived's access to Base members is not influenced by the type of inheritance used,
        // so the following is always true:

        m_nPublic = 1; // allowed: can access public base members from derived class
        m_nPrivate = 2; // not allowed: can not access private base members from derived class
        m_nProtected = 3; // allowed: can access protected base members from derived class
    }
};

int main()
{
    Base cBase;
    cBase.m_nPublic = 1; // allowed: can access public members from outside class
    cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class
    cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class
}

यदि आप किसी अन्य वर्ग से सार्वजनिक रूप से वारिस करते हैं, तो सभी जानते हैं कि आप विरासत में हैं और आप बेस क्लास पॉइंटर के माध्यम से किसी भी व्यक्ति द्वारा बहुरूप रूप से उपयोग किए जा सकते हैं।

यदि आप सुरक्षित रूप से वारिस करते हैं तो केवल आपके बच्चों के वर्ग आपको पॉलिमॉर्फिक रूप से उपयोग करने में सक्षम होंगे।

यदि आप निजी तौर पर वारिस करते हैं तो आप केवल माता-पिता वर्ग विधियों को निष्पादित करने में सक्षम होंगे।

जो मूल रूप से ज्ञान का प्रतीक है, शेष वर्गों में आपके माता-पिता वर्ग के साथ आपके संबंध हैं


विरासत की दृश्यता सीमित करने से कोड यह देखने में सक्षम नहीं होगा कि कुछ वर्ग किसी अन्य वर्ग को प्राप्त करता है: आधार से व्युत्पन्न से लागू रूपांतरण काम नहीं करेंगे, और बेस से व्युत्पन्न तक static_cast भी काम नहीं करेगा।

केवल कक्षा के सदस्य / मित्र निजी विरासत देख सकते हैं, और केवल सदस्य / मित्र और व्युत्पन्न कक्षाएं संरक्षित विरासत देख सकती हैं।

सार्वजनिक विरासत

  1. आईएस-ए विरासत है। एक बटन है-एक खिड़की, और कहीं भी जहां खिड़की की आवश्यकता है, एक बटन भी पारित किया जा सकता है।

    class button : public window { };
    

संरक्षित विरासत

  1. कार्यान्वित इन-इन-टर्म-इन। शायद ही उपयोगी। boost::compressed_pair खाली कक्षाओं से प्राप्त करने के लिए और रिक्त बेस क्लास ऑप्टिमाइज़ेशन का उपयोग करके स्मृति को सहेजने के लिए उपयोग किया जाता है (नीचे उदाहरण टेम्पलेट का उपयोग बिंदु पर रखने के लिए नहीं करता है):

    struct empty_pair_impl : protected empty_class_1 
    { non_empty_class_2 second; };
    
    struct pair : private empty_pair_impl {
      non_empty_class_2 &second() {
        return this->second;
      }
    
      empty_class_1 &first() {
        return *this; // notice we return *this!
      }
    };
    

निजी विरासत

  1. कार्यान्वित-इन-शर्तों-की। बेस क्लास का उपयोग केवल व्युत्पन्न वर्ग को लागू करने के लिए है। लक्षणों के साथ उपयोगी और यदि आकार मायने रखता है (रिक्त लक्षण जिनमें केवल फ़ंक्शंस हैं, खाली बेस क्लास ऑप्टिमाइज़ेशन का उपयोग करेंगे)। हालांकि, अक्सर रोकथाम बेहतर समाधान है। तारों के लिए आकार महत्वपूर्ण है, इसलिए यह अक्सर देखा जाता है

    template<typename StorageModel>
    struct string : private StorageModel {
    public:
      void realloc() {
        // uses inherited function
        StorageModel::realloc();
      }
    };
    

सार्वजनिक सदस्य

  1. कुल

    class pair {
    public:
      First first;
      Second second;
    };
    
  2. पहुंचकर्ता

    class window {
    public:
        int getWidth() const;
    };
    

संरक्षित सदस्य

  1. व्युत्पन्न कक्षाओं के लिए उन्नत पहुंच प्रदान करना

    class stack {
    protected:
      vector<element> c;
    };
    
    class window {
    protected:
      void registerClass(window_descriptor w);
    };
    

निजी सदस्य

  1. कार्यान्वयन विवरण रखें

    class window {
    private:
      int width;
    };
    

ध्यान दें कि सी-शैली जानबूझकर एक व्युत्पन्न कक्षा को संरक्षित या निजी आधार वर्ग में परिभाषित और सुरक्षित तरीके से कास्टिंग करने और दूसरी दिशा में डालने की अनुमति देती है। इसे हर कीमत से बचा जाना चाहिए, क्योंकि यह कार्यान्वयन विवरण पर निर्भर कोड बना सकता है - लेकिन यदि आवश्यक हो, तो आप इस तकनीक का उपयोग कर सकते हैं।


विरासत के बारे में सी ++ की विशेषताओं को समझने के लिए इन कोडों को देखें ... मैंने परिणाम अंत में डाल दिया ... उम्मीद है कि यह मदद करता है।

#include <iostream>
using namespace std;

class A {
private:
    void pri();
    A(int a);
protected:
    virtual void pro() {}
public:
    void pub1() { cout<<"A.pub1()\n"; }
    virtual void pub2() { cout<<"A.pub2()\n"; }
    virtual void pub3() { cout<<"A.pub3()\n"; }
    virtual void pub4() { cout<<"A.pub4()\n"; }
    virtual void pub5() { cout<<"A.pub5()\n"; }
    virtual void pub6() { cout<<"A.pub6()\n"; }
    virtual void pub7() { cout<<"A.pub7()\n"; }
    virtual void pub8() { cout<<"A.pub8()\n"; }
    void pub9() { cout<<"A.pub9()\n"; }
    virtual void pub10() { cout<<"A.pub10()\n"; }
    void pub11() { cout<<"A.pub11()\n"; }
    explicit A() {}
    virtual ~A() {}
};

class B : public A {
private:
    void pri() { cout<<"B.pri()\n"; }
protected:
    virtual void pub4() { cout<<"B.pub4()\n"; }
    void pub6() { cout<<"B.pub6()\n"; }
public:
    void pro() { cout<<"B.pro() "; B::pri(); }
    void pub1() { cout<<"B.pub1()\n"; }
    void pub2() { cout<<"B.pub2()\n"; }
    void pub5() { cout<<"B.pub5()\n"; }
    virtual void pub7() { cout<<"B.pub7()\n"; }
    virtual void pub8() { cout<<"B.pub8()\n"; }
    virtual void pub9() { cout<<"B.pub9()\n"; }
    void pub10() { cout<<"B.pub10()\n"; }
    void pub11() { cout<<"B.pub11()\n"; }
    explicit B() {}
};

class C : protected B {
public:
    void pub4_() { cout<<"C.pub4_() "; B::pub4(); }
    virtual void pub5() { cout<<"C.pub5()\n"; }
};

class D : private B {
public:
    void pub4_() { cout<<"D.pub4_() "; B::pub4(); }
};

class E : public B {
public:
    virtual void pub4() { cout<<"E.pub4()\n"; }
    virtual void pub7() { cout<<"E.pub7()\n"; }
    virtual void pub8() { cout<<"E.pub8()\n"; }
    virtual void pub9() { cout<<"E.pub9()\n"; }
    virtual void pub10() { cout<<"E.pub10()\n"; }
    virtual void pub11() { cout<<"E.pub11()\n"; }
};

void testClasses() {
    A* ap=new B();
    ap->pub1(); // == A::pub1() //important
    // (new B()).pub1() can't override non-virtual A::pub1() for an A* pointer.
    ap->pub2(); // == B::pub2() //important
    // (new B()).pub1() can override virtual A::pub1() for an A* pointer.
    B b;
    b.A::pub1();
    b.pro();
    B* bp=new B;
    bp->pub3();
    C c;
    //c.pub3(); //error
    //c.pub4(); //error
    c.pub4_();
    c.pub5();
    D d;
    //d.pub3(); //error
    //d.pub4(); //error
    d.pub4_();
    E e;
    //e.pub4(); //error
    delete ap;
    ap = new E();
    ap->pub4();
    ap->pub5();
    ap->pub6();
    ap->pub7();
    delete bp;
    bp = new E();
    e.pub8();
    e.A::pub8();
    e.B::A::pub8();
    e.B::pub8();
    ap->pub8();
    bp->pub8();
    e.pub9();
    e.A::pub9();
    e.B::A::pub9();
    e.B::pub9();
    ap->pub9(); // important
    bp->pub9();
    e.pub10();
    e.A::pub10();
    e.B::A::pub10();
    e.B::pub10();
    ap->pub10(); // important
    bp->pub10(); // very important... eventhough B::pub10() is non-virtual,
                 // bp->pub10() != b.pub10();
    e.pub11();
    e.A::pub11();
    e.B::A::pub11();
    e.B::pub11();
    ap->pub11();
    bp->pub11();
    delete ap;
    delete bp;
    return;
}

int main() {
    testClasses();
    return 0;
}









/////////////////////////////////////////
........
Result :
........

A.pub1()
B.pub2()
A.pub1()
B.pro() B.pri()
A.pub3()
C.pub4_() B.pub4()
C.pub5()
D.pub4_() B.pub4()
E.pub4()
B.pub5()
B.pub6()
E.pub7()
E.pub8()
A.pub8()
A.pub8()
B.pub8()
E.pub8()
E.pub8()
E.pub9()
A.pub9()
A.pub9()
B.pub9()
A.pub9()
E.pub9()
E.pub10()
A.pub10()
A.pub10()
B.pub10()
E.pub10()
E.pub10()
E.pub11()
A.pub11()
A.pub11()
B.pub11()
A.pub11()
B.pub11()

सारांश:

  • निजी: कक्षा के भीतर छोड़कर कोई भी इसे देख नहीं सकता है
  • संरक्षित: निजी + व्युत्पन्न कक्षाएं इसे देख सकती हैं
  • सार्वजनिक: दुनिया इसे देख सकती है

विरासत में, आप (कुछ भाषाओं में) कुछ दिशा में डेटा सदस्य के सुरक्षा प्रकार को बदल सकते हैं, उदाहरण के लिए संरक्षित से सार्वजनिक तक।


सार्वजनिक विरासत मॉडल एक आईएस-ए संबंध है। साथ में

class B {};
class D : public B {};

हर D एक B

निजी विरासत मॉडल एक आईएस-कार्यान्वित-उपयोग संबंध (या जिसे भी कहा जाता है) मॉडल करता है। साथ में

class B {};
class D : private B {};

D B नहीं है, लेकिन प्रत्येक D इसके क्रियान्वयन में B का उपयोग करता है। इसके बजाय रोकथाम का उपयोग करके निजी विरासत को समाप्त किया जा सकता है:

class B {};
class D {
  private: 
    B b_;
};

इस D को भी B का उपयोग करके लागू किया जा सकता है, इस मामले में इसके b_ का उपयोग कर। रोकथाम विरासत की तुलना में प्रकारों के बीच कम तंग युग्मन है, इसलिए आम तौर पर इसे प्राथमिकता दी जानी चाहिए। कभी-कभी निजी विरासत की बजाय रोकथाम का उपयोग निजी विरासत के रूप में सुविधाजनक नहीं है। अक्सर आलसी होने के लिए यह एक लंगड़ा बहाना है।

मुझे नहीं लगता कि किसी को पता है कि protected विरासत मॉडल क्या हैं। कम से कम मैंने अभी तक कोई ठोस स्पष्टीकरण नहीं देखा है।


दृश्यता विरासत मॉडल निर्दिष्ट करने के लिए इन तीनों कीवर्ड का एक पूरी तरह से अलग संदर्भ में भी उपयोग किया जाता है।

यह तालिका घटक घोषणा और विरासत मॉडल के संभावित संयोजनों को इकट्ठा करती है जब सबक्लास पूरी तरह से परिभाषित होने पर घटकों तक परिणामी पहुंच प्रस्तुत करता है।

यह निम्न तरीके से पढ़ता है (पहली पंक्ति पर एक नज़र डालें):

यदि एक घटक को सार्वजनिक के रूप में घोषित किया जाता है और इसकी कक्षा को जनता के रूप में विरासत में मिला है तो परिणामस्वरूप पहुंच सार्वजनिक है

एक उदाहरण:

 class Super {
    public:      int p;
    private:     int q;
    protected:   int r;
 };

 class Sub : private Super {};

 class Subsub : public Sub {};

क्लास सबब में चर, p , q , r लिए परिणामी पहुंच कोई नहीं है

एक और उदाहरण:

class Super {
    private:     int x;
    protected:   int y;
    public:      int z;
 };
class Sub : protected Super {};

वेरिएबल y लिए परिणामी पहुंच, कक्षा उप में z संरक्षित है और चर x लिए कोई नहीं है

एक और विस्तृत उदाहरण:

class Super {
private:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};
int main(void) {
    Super object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

अब एक उपclass परिभाषित करते हैं:

class Sub : Super { };

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

उप नामित परिभाषित वर्ग जो Super नामक वर्ग का Sub वर्ग है या Sub वर्ग Super क्लास से लिया गया है। Sub वर्ग न तो नए चर और न ही नए कार्यों का परिचय देता है। क्या इसका मतलब यह है कि Super क्लास वास्तव में एक Super क्लास 'ऑब्जेक्ट्स की एक प्रति होने के बाद Sub वर्ग के किसी भी वस्तु को सभी लक्षणों को विरासत में मिला है?

नहीं यह नहीं है

यदि हम निम्नलिखित कोड संकलित करते हैं, तो हमें संकलन त्रुटियों के अलावा कुछ भी नहीं मिलेगा, जिसमें कहा गया है कि विधियां put और पहुंच योग्य नहीं हैं। क्यूं कर?

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

हमें संकलक को सूचित करना है कि हम पहले उपयोग की जाने वाली एक्सेस पॉलिसी को संरक्षित करना चाहते हैं।

class Sub : public Super { };

गुमराह मत बनो : इसका मतलब यह नहीं है कि सुपर क्लास (स्टोरेज वैरिएबल की तरह) के निजी घटक सार्वजनिक रूप से कुछ जादुई तरीके से बदल जाएंगे। निजी घटक निजी बने रहेंगे, जनता सार्वजनिक रहेगी।

Sub वर्ग के ऑब्जेक्ट्स "लगभग" वही चीजें कर सकते हैं जैसे उनके पुराने भाई बहन Super क्लास से बनाए जाते हैं। "लगभग" क्योंकि उप-वर्ग होने का तथ्य यह भी है कि कक्षा सुपरक्लास के निजी घटकों तक पहुंच खो गई है । हम Sub क्लास का सदस्य फ़ंक्शन नहीं लिख सकते हैं जो सीधे स्टोरेज वैरिएबल में हेरफेर करने में सक्षम होगा।

यह एक बहुत ही गंभीर प्रतिबंध है। क्या कोई कामकाज है?

हां

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

class Super {
protected:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};

class Sub : public Super {
public:
    void print(void) {cout << "storage = " << storage;}
};

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get() + 1);
    object.print();
    return 0;
}

जैसा कि आप उदाहरण कोड में देखते हैं, हम Sub क्लास के लिए एक नई कार्यक्षमता देखते हैं और यह एक महत्वपूर्ण बात करता है: यह सुपर क्लास से स्टोरेज वैरिएबल तक पहुंचता है

यदि वैरिएबल को निजी के रूप में घोषित किया गया तो यह संभव नहीं होगा। मुख्य कार्यक्षेत्र में वेरिएबल अवशेष छुपाए गए हैं, इसलिए यदि आप कुछ भी लिखते हैं:

object.storage = 0;

कंपाइलर आपको सूचित करेगा कि यह एक error: 'int Super::storage' is protected

अंत में, अंतिम कार्यक्रम निम्नलिखित आउटपुट का उत्पादन करेगा:

storage = 101

Accessors    | Base Class | Derived Class | World
—————————————+————————————+———————————————+———————
public       |      y     |       y       |   y
—————————————+————————————+———————————————+———————
protected    |      y     |       y       |   n
—————————————+————————————+———————————————+———————
private      |            |               |    
  or         |      y     |       n       |   n
no accessor  |            |               |

y: accessible
n: not accessible

जावा के लिए this उदाहरण के आधार पर ... मुझे लगता है कि हजारों शब्दों के लायक एक छोटी सी टेबल :)


class A 
{
public:
    int x;
protected:
    int y;
private:
    int z;
};

class B : public A
{
    // x is public
    // y is protected
    // z is not accessible from B
};

class C : protected A
{
    // x is protected
    // y is protected
    // z is not accessible from C
};

class D : private A    // 'private' is default for classes
{
    // x is private
    // y is private
    // z is not accessible from D
};

महत्वपूर्ण नोट: कक्षा बी, सी और डी सभी में चर, एक्स, वाई और जेड होते हैं। यह सिर्फ पहुंच का सवाल है।

संरक्षित और निजी विरासत के उपयोग के बारे में आप here पढ़ सकते हैं।







access-specifier