2012-01-19 12 views
70

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

मान लीजिए मैं निम्नलिखित है: यह

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

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

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

उत्तर

59

व्युत्पन्न वर्गों नहींसभी आभासी कार्यों के लिए खुद को लागू करने के लिए है। उन्हें केवल शुद्ध वाले को लागू करने की आवश्यकता है। इसका मतलब है कि प्रश्न में Derived वर्ग सही है। यह bar अपने पूर्वजों वर्ग, Abstract से कार्यान्वयन विरासत में मिला है। (मतलब यह है कि Abstract::bar कहीं कार्यान्वित किया जाता है। प्रश्न में कोड विधि वाणी है, लेकिन यह परिभाषित नहीं करता है। तुम्हें पता है, Trenki's answer शो के रूप में इनलाइन यह परिभाषित कर सकते हैं या आप इसे अलग से परिभाषित कर सकते हैं।)


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

+2

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

+0

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

+0

@ पिक्सेलपशर निश्चित रूप से 'व्युत्पन्न :: बार' में एक कार्य निकाय है, जो कि सार :: बार' है। तो ऐसा अनुवाद इकाई लगता है जहां इसे परिभाषित किया गया है (क्या यह कहीं भी परिभाषित किया गया है?) अनुवाद इकाई में लिंक नहीं है जहां इसे कहा जाता है। –

3

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

31

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

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(); 
}; 

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

तो, सिर्फ अपने वैकल्पिक आभासी विधि के बाद {} डाल आप एक खाली डिफ़ॉल्ट कार्यान्वयन देता है।

+2

बिंगो। यह मेरा मुद्दा था, बहुत बहुत धन्यवाद। :) – mikestaub

+0

वाक्यविन्यास में टाइपो? – Goldname

7

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

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

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

संदर्भ:

सी ++ 03 मानक: 10.3 आभासी कार्यों [class.virtual]

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

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

gcc faq doccuments यह रूप में अच्छी तरह:

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

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

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

0

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

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

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

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