वंशानुक्रम: 'ए' 'बी' का एक दुर्गम आधार है


82
$ cat inheritance.cpp 
#include <iostream>

using namespace std;

class A { };
class B : private A { };

int main() {
    A* ab = new B;
}
$
$ g++ inheritance.cpp
inheritance.cpp: In function 'int main()':
inheritance.cpp:9: error: 'A' is an inaccessible base of 'B'
$

मैं अभी इस त्रुटि को नहीं समझता।

जैसा कि मैं समझता हूं, और जैसा कि यह ट्यूटोरियल पुष्टि करता है, privateविरासत को केवल यह बदलना चाहिए class Bकि बाहरी दुनिया के सदस्य कैसे दिखाई देते हैं।

मुझे लगता है कि निजी स्पेसिफिक class Bयहाँ के सदस्यों की दृश्यता को बदलने की तुलना में अधिक कर रहा है।

  • मुझे यह त्रुटि क्या है और इसका क्या मतलब है?
  • मूल रूप से C ++ में इस प्रकार के कोड की अनुमति देने में क्या गलत है? पूरी तरह से हानिरहित दिखता है।

जवाबों:


100

विरासत को निजी बनाकर, आप मूल रूप से कह रहे हैं कि यहां तक ​​कि यह भी कि ए को विरासत में मिला है (बिल्कुल भी) निजी है - बाहरी दुनिया के लिए सुलभ / दृश्यमान नहीं है।

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

निजी विरासत जरूरी नहीं है (या सामान्य रूप से भी) Liskov प्रतिस्थापन सिद्धांत का पालन करना है । लोक विरासत का दावा है कि एक व्युत्पन्न वस्तु आधार वर्ग का एक उद्देश्य के लिए प्रतिस्थापित किया जा सकता है, और उचित अर्थ विज्ञान होगा अभी भी उत्पन्न होती हैं। निजी विरासत हालांकि यह दावा नहीं करता है । निजी विरासत द्वारा निहित संबंध का सामान्य विवरण "के संदर्भ में" लागू किया गया है।

सार्वजनिक विरासत का मतलब है कि एक व्युत्पन्न वर्ग आधार वर्ग की सभी क्षमताओं को बनाए रखता है और संभावित रूप से इसके अलावा अधिक जोड़ता है। निजी विरासत का अर्थ अक्सर कम या ज्यादा विपरीत होता है: यह कि व्युत्पन्न वर्ग एक सामान्य आधार वर्ग का उपयोग करता है ताकि अधिक प्रतिबंधित इंटरफ़ेस के साथ कुछ को लागू किया जा सके।

उदाहरण के लिए, आइए इस क्षण के लिए मान लें कि C ++ मानक पुस्तकालय में कंटेनरों को टेम्पलेट के बजाय वंशानुक्रम का उपयोग करके लागू किया गया था। वर्तमान प्रणाली में, std::dequeऔर std::vectorकंटेनर हैं, और std::stackएक कंटेनर एडाप्टर है जो एक अधिक प्रतिबंधित इंटरफ़ेस प्रदान करता है। चूंकि यह टेम्प्लेट पर आधारित है, आप या std::stackतो एडॉप्टर के रूप में उपयोग कर सकते हैं ।std::dequestd::vector

यदि हम विरासत के साथ अनिवार्य रूप से समान प्रदान करना चाहते थे, तो हम शायद निजी विरासत का उपयोग std::stackकरेंगे , इसलिए कुछ इस तरह होगा:

class stack : private vector {
    // ...
};

इस मामले में, हम निश्चित रूप से नहीं चाहते हैं कि उपयोगकर्ता हमारे हेरफेर करने stackमें सक्षम हो जैसे कि यह एक था vector। ऐसा करने से (और संभावना) एक स्टैक की अपेक्षाओं का उल्लंघन हो सकता है (उदाहरण के लिए, उपयोगकर्ता विशुद्ध रूप से स्टैक जैसी फैशन के बजाय बीच में आइटम सम्मिलित / हटा सकता है)। हम मूल vectorरूप से अपने स्टैक को लागू करने के लिए एक सुविधाजनक तरीके के रूप में उपयोग कर रहे हैं , लेकिन अगर (उदाहरण के लिए) हमने stackअकेले स्टैंड के लिए कार्यान्वयन को बदल दिया (बेस क्लास पर निर्भरता नहीं है) या इसके संदर्भ में इसे फिर से लागू करते हैं std::deque, तो हम ऐसा नहीं चाहते हैं किसी भी क्लाइंट कोड को प्रभावित करने के लिए - क्लाइंट कोड के लिए, यह सिर्फ एक स्टैक माना जाता है, न कि कुछ विशेष किस्म के वेक्टर (या डीके)।


1
यह भी लागू होता हैprotected
सबमशीन

12

निजी विरासत को केवल यह बदलना चाहिए कि कक्षा बी के सदस्य बाहरी दुनिया को कैसे दिखाई देते हैं

ऐसा होता है। और अगर

A* p = new B;

अनुमति दी गई थी, तब किसी भी विरासत में मिले सदस्यों Bको बाहरी दुनिया से एक्सेस किया जा सकता था, बस एक बनाकर A*। चूंकि वे निजी तौर पर विरासत में मिले हैं, इसलिए यह पहुंच अवैध है, और इसलिए यह अपस्टेक है।


8

clang++ थोड़ा और अधिक समझने योग्य त्रुटि संदेश देता है:

example.cpp:9:13: error: cannot cast 'B' to its private base class 'A'
    A* ab = new B;
            ^
example.cpp:6:11: note: declared private here
class B : private A { };
          ^~~~~~~~~
1 error generated.

मैं सी ++ विशेषज्ञ नहीं हूं, लेकिन ऐसा लगता है कि यह सिर्फ अनुमति नहीं है। मैं कल्पना के आसपास जाऊंगा और देखूंगा कि मैं क्या कर रहा हूं।

संपादित करें: यहां कल्पना से प्रासंगिक संदर्भ है - खंड 4.10 सूचक रूपांतरण , पैरा 3:

प्रकार का एक prvalue "करने के लिए सूचक सीवी D ", जहाँ Dएक वर्ग प्रकार है, प्रकार का एक prvalue "सीवी सूचक में बदला जा सकता B", जहाँ बी के एक आधार वर्ग है D। यदि Bएक दुर्गम या अस्पष्ट आधार वर्ग है D, तो इस रूपांतरण की आवश्यकता वाले कार्यक्रम को आधार बनाया जाता है।


5

यह बहुत आसान है: तथ्य यह Aहै कि निजी तौर पर विरासत में मिला है इसका मतलब है कि Bफैली हुई Aयह एक रहस्य है, और केवल Bइसे "जानता है"। निजी विरासत की यही परिभाषा है।


4
लेकिन अगर मैं privateसाथ देता हूं तो मुझे वही त्रुटि मिलती है protected
लेज़र

2
वास्तव में। "संरक्षित" का अर्थ है कि ज्ञान Bऔर (और मित्रों) के उपवर्गों तक सीमित है B। " A* ab = new B;" एक काल्पनिक वर्ग में कानूनी होगा Cजो एक उपवर्ग था B
अर्नेस्ट फ्राइडमैन-हिल

3

निजी विरासत का मतलब है कि व्युत्पन्न वर्ग के बाहर, विरासत की जानकारी छिपी हुई है। इसका मतलब है कि आप व्युत्पन्न वर्ग को आधार वर्ग में नहीं डाल सकते हैं: कॉल करने वाले के लिए संबंध ज्ञात नहीं है।


धन्यवाद, लेकिन यह किसी भी तरह से मतलब नहीं है। privateकेवल व्यवसाय को नियंत्रित करना चाहिए कि सदस्य कैसे व्यवहार करते हैं। यदि विरासत की जानकारी छिपी नहीं है तो क्या नुकसान होगा?
लेज़र

1
निजी उत्तराधिकार एकत्रीकरण / रचना का एक रूप है। यह करने के लिए एक रास्ता है है एक आधार वर्ग के गुणों, बिना किया जा रहा है आधार वर्ग की एक वस्तु। यदि वह नहीं है जो आप चाहते हैं, तो निजी विरासत आपके लिए नहीं है। बस यही काम करता है।
tmpearce

0

यह काम कर रहा है

#include <iostream>

using namespace std;

class A{
    public:
        virtual void update() = 0;
};

class B: public A{
    public:
    virtual void update(){std::cout<<"hello";};
};

int main()
{
    A *a = new B();

    a->update();

    return 0;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.