2011-11-16 18 views
5

मैं विरासत के बारे में पढ़ रहा हूँ और मैं एक प्रमुख मुद्दा है कि मैं घंटों के लिए हल करने में सक्षम नहीं किया गया है:आभासी विरासत भ्रम

को देखते हुए एक वर्ग Barvirtual कार्यों के साथ एक वर्ग है,

class Bar 
{ 
    virtual void Cook(); 
}; 

क्या के बीच अलग है:

class Foo : public Bar 
{ 
    virtual void Cook(); 
}; 

और

class Foo : public virtual Bar 
{ 
    virtual void Cook(); 
}; 

? Googling और पढ़ने के घंटे इसके उपयोग के बारे में बहुत सारी जानकारी के साथ आया, लेकिन वास्तव में कोई भी मुझे बताओ कि दोनों के बीच क्या अंतर है, और बस मुझे और भ्रमित करें।

+2

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

+0

आज़माएं: [यह खोज] (http://stackoverflow.com/search?क्यू = वर्चुअल + विरासत +% 5 बीसी% 2 बी% 2 बी% 5 डी) –

+0

[सी ++ वर्चुअल बेस क्लास में?] (http://stackoverflow.com/questions/21558/in-c-virtual-base-class) के संभावित डुप्लिकेट –

उत्तर

4

वर्चुअल विरासत केवल प्रासंगिक है यदि वर्ग Foo से उत्तराधिकारी हैं।अगर मैं निम्नलिखित को परिभाषित:

class B {}; 
class L : virtual public B {}; 
class R : virtual public B {}; 
class D : public L, public R {}; 

तब अंतिम वस्तु केवल B की एक प्रति, दोनों L और R द्वारा साझा शामिल होंगे। virtual के बिना, D प्रकार की एक वस्तु B की दो प्रतियां, L में से एक, और R में से एक होगी।

कुछ तर्क है कि सभी विरासत आभासी होनी चाहिए (क्योंकि उन मामलों में जहां यह एक फर्क पड़ता है, यही वह समय है जो आप समय के अधिकांश चाहते हैं)। अभ्यास में, हालांकि, अधिकांश मामलों में वर्चुअल विरासत महंगा है, और आवश्यक नहीं है: एक अच्छी तरह से डिज़ाइन किया गया सिस्टम में, अधिकांश विरासत केवल एक या से अधिक "इंटरफेस" से प्राप्त एक ठोस वर्ग का होगा; ऐसी कंक्रीट कक्षा आमतौर पर होने के लिए डिज़ाइन नहीं की गई है, इसलिए कोई समस्या नहीं है। लेकिन अपवाद हैं: उदाहरण के लिए, यदि आप इंटरफ़ेस में इंटरफ़ेस को परिभाषित करते हैं, और फिर एक्सटेंशन को एक्सटेंशन इंटरफ़ेस से प्राप्त करना चाहिए, क्योंकि एक ठोस कार्यान्वयन कई एक्सटेंशन लागू करना चाहता है। या यदि आप मिक्स्डिन डिज़ाइन कर रहे हैं, जहां कुछ कक्षाएं केवल इंटरफ़ेस का हिस्सा लागू करती हैं, और अंतिम कक्षा इन कक्षाओं में से कई से प्राप्त होती है ( इंटरफ़ेस का एक हिस्सा)। अंत में, कि क्या करने के लिए के रूप में criteron वारिस के लगभग या नहीं भी मुश्किल नहीं है:

  • अगर विरासत सार्वजनिक नहीं है, यह शायद नहीं आभासी होना चाहिए (मैं कभी नहीं देखा है एक अपवाद), अन्यथा

  • अगर वर्ग एक आधार वर्ग होने के लिए नहीं बनाया गया है, आभासी विरासत के लिए कोई आवश्यकता नहीं है, अन्यथा

  • विरासत आभासी होना चाहिए।

में कुछ अपवाद भी हैं, लेकिन उपरोक्त नियमों सुरक्षा की ओर गलती; वर्चुअल विरासत आवश्यक नहीं है, यहां तक ​​कि उन मामलों में भी वस्तुतः वारिस करने के लिए यह "सही" है।

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

5

कार्यक्षमता के अनुसार 2 संस्करणों के बीच बहुत अंतर नहीं है। virtual विरासत के मामले में, प्रत्येक कार्यान्वयन आम तौर पर एक (vptr जैसा) सूचक (virtual फ़ंक्शंस के मामले में) जोड़ता है। कौन सा कारण एकाधिक वंशानुक्रम के लिए (diamond inheritance समस्या) उत्पन्न एकाधिक आधार वर्ग प्रतियां

इसके अलावा, virtual विरासत प्रतिनिधियों इसके आधार वर्ग के निर्माता कॉल करने के लिए सही से बचने के लिए मदद करता है। उदाहरण के लिए,

class Bar; 
class Foo : public virtual Bar 
class Other : public Foo // <--- one more level child class 

तो, अब Bar::Bar() सीधे Other::Other() से बुलाया जाएगा और यह भी अन्य आधार वर्गों के बीच पहले स्थान पर रखा जाएगा।

यह प्रतिनिधिमंडल सुविधा सी ++ 03 में एक final class (जावा में) कार्यक्षमता को लागू करने में मदद करता है:

class Final { 
    Final() {} 
    friend class LastClass; 
}; 

class LastClass : virtual Final { // <--- 'LastClass' is not derivable 
... 
}; 

class Child : public LastClass { // <--- not possible to have object of 'Child' 
}; 
3

इस मामले में, कोई फर्क नहीं। आभासी विरासत व्युत्पन्न वर्ग

struct A 
{ 
    int a; 
}; 

struct B : public virtual A 
{ 
    int b; 
} 

struct C : public virtual A 
{ 
    int c; 
}; 

struct D : public B, public C 
{ 
}; 

वहाँ D के उदाहरण में सदस्य चर a की एक प्रतिलिपि है द्वारा सुपर क्लास subobjects साझा करने उदाहरणों से संबंधित है; यदि A वर्चुअल बेस क्लास नहीं था, तो D के उदाहरण में दो A सबोबजेक्ट होंगे।

+0

"_ इस मामले में, कोई फर्क नहीं पड़ता ._" जब तक आप 'static_cast' का उपयोग करने का प्रयास नहीं करते! – curiousguy

0

वर्चुअल फ़ंक्शन एक ऐसा फ़ंक्शन है जो संभवतः व्युत्पन्न वर्ग में अलग-अलग कार्यान्वयन करेगा (हालांकि यह आवश्यक नहीं है)।

आपके अंतिम उदाहरण में वर्चुअल विरासत है। एक ऐसे मामले की कल्पना करें जहां आपके पास बेस क्लास से ली गई दो कक्षाएं (ए और बी) हैं (चलिए इसे 'बेस' कहते हैं)। अब आभासी विरासत के बिना ए और बी से व्युत्पन्न एक तीसरी कक्षा सी की कल्पना करें, सी में 'बेस' की दो प्रतियां होंगी। संकलन करते समय अस्पष्टता हो सकती है। आभासी विरासत में महत्वपूर्ण बात यह है कि 'बेस' वर्ग कन्स्ट्रक्टर (यदि कोई हो) के पैरामीटर कक्षा सी में प्रदान किए जाने चाहिए, क्योंकि ए और बी से ऐसी कॉलों को अनदेखा कर दिया जाएगा।

+0

"_That संकलन करते समय अस्पष्टता का कारण बन सकता है ._" यह ** ** एक अस्पष्टता का कारण बन जाएगा _iff_ आप 'सी' आईएस-ए 'बेस' आज़माएं। – curiousguy

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