क्या सभी आभासी कार्यों को व्युत्पन्न कक्षाओं में लागू करने की आवश्यकता है?


91

यह एक साधारण प्रश्न की तरह लग सकता है, लेकिन मुझे इसका जवाब कहीं और नहीं मिलेगा।

मान लीजिए कि मेरे पास निम्नलिखित हैं:

class Abstract {
public:
    virtual void foo() = 0;
    virtual void bar();
}

class Derived : Abstract {
public:
    virtual void foo();
}

क्या यह ठीक है कि व्युत्पन्न वर्ग बार () फ़ंक्शन को लागू नहीं करता है? क्या होगा यदि मेरे सभी व्युत्पन्न वर्गों को बार () फ़ंक्शन की आवश्यकता नहीं है, लेकिन कुछ करते हैं। क्या एक सार आधार वर्ग के सभी आभासी कार्यों को व्युत्पन्न वर्गों में लागू करने की आवश्यकता है, या केवल वही जो शुद्ध आभासी हैं? धन्यवाद

जवाबों:


82

व्युत्पन्न वर्गों को सभी आभासी कार्यों को स्वयं लागू करने की आवश्यकता नहीं है । उन्हें केवल शुद्ध को लागू करने की आवश्यकता है। 1 इसका मतलब है कि प्रश्न में कक्षा सही है। यह अपने पूर्वज वर्ग से कार्यान्वयन विरासत में मिला है । (यह माना जाता है कि कहीं लागू किया गया है। प्रश्न में कोड विधि की घोषणा करता है, लेकिन इसे परिभाषित नहीं करता है। आप इसे इन्रेन को ट्रेंकी के उत्तर शो के रूप में परिभाषित कर सकते हैं, या आप इसे अलग से परिभाषित कर सकते हैं।)DerivedbarAbstractAbstract::bar


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


3
और यहां तक ​​कि यह (शुद्ध आभासी कार्यों का क्रियान्वयन) केवल अगर उन्हें अस्थिर करने का इरादा है (एक सार आधार वर्ग होने के विपरीत)।
क्रिश्चियन राऊ

1
यही तो मैने सोचा। लेकिन मैं अपने प्रोजेक्ट में ऐसा कर रहा हूं, और मुझे यह कहते हुए एक लिंकिंग त्रुटि हो रही है कि Derived :: bar () के लिए "अनसुलझे बाहरी प्रतीक" हैं; लेकिन मैंने कभी भी Derived के भीतर बार घोषित नहीं किया, इसलिए लिंकर फंक्शन बॉडी की तलाश क्यों कर रहा है?
मिकेस्तूब

1
@pixelpusher के पास निश्चित रूप Derived::barसे एक फंक्शन बॉडी है Abstract::bar। तो ऐसा लगता है कि अनुवाद इकाई जहां परिभाषित है (क्या इसे कहीं भी परिभाषित किया गया है?) अनुवाद इकाई में लिंक नहीं है जहां इसे कहा जाता है।
क्रिश्चियन रौ

2
@ रोब: They only need to implement the pure ones.यह भ्रामक है। व्युत्पन्न वर्गों को शुद्ध आभासी कार्यों को लागू करने की आवश्यकता नहीं है ।
नवाज

मैं मदद की सराहना करता हूं लेकिन @trenki ने सिर पर कील ठोक दी। यद्यपि आप ईसाई राउ भी सही थे, क्योंकि यह परिभाषित नहीं था।
मिकेस्तुब

47

केवल शुद्ध आभासी तरीकों को व्युत्पन्न कक्षाओं में लागू किया जाना है, लेकिन आपको अभी भी अन्य आभासी तरीकों की परिभाषा (और सिर्फ एक घोषणा नहीं) की आवश्यकता है। यदि आप एक की आपूर्ति नहीं करते हैं, तो लिंकर बहुत अच्छी तरह से शिकायत कर सकता है।

इसलिए, {}अपनी वैकल्पिक वर्चुअल विधि के बाद ही आपको खाली डिफ़ॉल्ट कार्यान्वयन प्रदान करना होगा:

class Abstract {
public:
    virtual void foo() = 0; // pure virtual must be overridden
    virtual void bar() {}   // virtual with empty default implementation
};

class Derived : Abstract {
public:
    virtual void foo();
};

एक अधिक शामिल डिफ़ॉल्ट कार्यान्वयन हालांकि एक अलग स्रोत फ़ाइल में जाएगा।


7

आईएसओ सी ++ मानक निर्दिष्ट करता है कि एक वर्ग के सभी आभासी तरीके जो शुद्ध-आभासी नहीं हैं, उन्हें परिभाषित किया जाना चाहिए।

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

आपके कोड उदाहरण में उपरोक्त नियम के अनुसार, virtual void bar();बेस क्लास में एक परिभाषा की आवश्यकता है।

संदर्भ:

C ++ 03 मानक: 10.3 वर्चुअल फ़ंक्शंस [class.virtual]

एक वर्ग में घोषित एक आभासी कार्य को परिभाषित किया जाएगा, या उस कक्षा में शुद्ध (10.4) घोषित किया जाएगा, या दोनों; लेकिन कोई निदान की आवश्यकता नहीं है (3.2)।

तो या तो आपको फ़ंक्शन को शुद्ध आभासी बनाना चाहिए या इसके लिए एक परिभाषा प्रदान करनी चाहिए।

जीसीसी फैक doccuments यह रूप में अच्छी तरह:

आईएसओ सी ++ मानक निर्दिष्ट करता है कि एक वर्ग के सभी आभासी तरीके जो शुद्ध-आभासी नहीं हैं, को परिभाषित किया जाना चाहिए, लेकिन इस नियम के उल्लंघन के लिए किसी निदान की आवश्यकता नहीं है [class.virtual]/8। इस धारणा के आधार पर, जीसीसी केवल अनुवाद इकाई में निहित रूप से परिभाषित निर्माणकर्ताओं, असाइनमेंट ऑपरेटर, विध्वंसक और एक वर्ग की आभासी तालिका का उत्सर्जन करेगा जो इसकी पहली ऐसी गैर-इनलाइन विधि को परिभाषित करता है।

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

इसका समाधान यह सुनिश्चित करना है कि सभी वर्चुअल तरीके जो शुद्ध नहीं हैं, परिभाषित किए गए हैं। ध्यान दें कि एक विध्वंसक को परिभाषित किया जाना चाहिए, भले ही वह शुद्ध-आभासी घोषित हो [class.dtor]/7


3

हां, यह ठीक है ... आपको केवल एक मूल बेस क्लास से ली गई कक्षा को तुरंत करने के लिए किसी भी शुद्ध आभासी कार्यों को लागू करने की आवश्यकता है।


1

हां, यह सही है कि एक व्युत्पन्न वर्ग को उस फ़ंक्शन को ओवरराइड करना होता है जो पेरेंट क्लास में प्योर वर्चुअल है। प्योर वर्चुअल फंक्शन वाले पैरेंट क्लास को केवल इसलिए एब्सट्रैक्ट क्लास कहा जाता है क्योंकि यह चाइल्ड क्लास को प्योर वर्चुअल फंक्शन का अपना शरीर देना चाहिए।

नॉर्मल वर्चुअल फंक्शन्स के लिए: - इसके लिए जरूरी नहीं कि उन्हें आगे से ओवरराइड किया जाए, क्योंकि कुछ चाइल्ड क्लास के पास यह फंक्शन हो सकता है, कुछ के पास नहीं।

वर्चुअल फंक्शन मैकेनिज्म का मुख्य उद्देश्य रन टाइम पोलीमोर्फिज्म है, चाहे शुद्ध वर्चुअल फंक्शन (अमूर्त वर्ग) का मुख्य उद्देश्य स्वयं के शरीर के साथ एक ही नाम फंक्शन का होना अनिवार्य है।

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