2011-01-12 17 views

उत्तर

65

कुछ मामलों में, हाँ, मूल व्यय प्रकार के साथ वापसी प्रकार covariant के रूप में एक अलग रिटर्न प्रकार का उपयोग करके वर्चुअल फ़ंक्शन को ओवरराइड करने के लिए एक व्युत्पन्न वर्ग के लिए कानूनी है। उदाहरण के लिए, निम्नलिखित पर विचार:

class Base { 
public: 
    virtual ~Base() {} 

    virtual Base* clone() const = 0; 
}; 

class Derived: public Base { 
public: 
    virtual Derived* clone() const { 
     return new Derived(*this); 
    } 
}; 

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

Base* ptr = /* ... */ 
Base* clone = ptr->clone(); 

लिखना होता है clone() करने के लिए कॉल हमेशा एक Base वस्तु के लिए एक सूचक वापस आ जाएगी, क्योंकि भले ही यह एक रिटर्न Derived*, यह सूचक निश्चित रूप से Base* पर परिवर्तनीय है और ऑपरेशन अच्छी तरह से परिभाषित है।

अधिक आम तौर पर, फ़ंक्शन का रिटर्न प्रकार कभी भी इसके हस्ताक्षर का हिस्सा नहीं माना जाता है। जब तक रिटर्न टाइप कॉन्वर्सेंट होता है तब तक आप किसी भी सदस्य फ़ंक्शन को किसी भी रिटर्न प्रकार से ओवरराइड कर सकते हैं।

+6

यह "आप किसी भी प्रकार के रिटर्न प्रकार के साथ किसी सदस्य फ़ंक्शन को ओवरराइड कर सकते हैं" सही नहीं है। जब तक रिटर्न टाइप समान या कॉन्वर्सेंट (जिसे आपने समझाया), अवधि तक आप ओवरराइड कर सकते हैं। यहां कोई और सामान्य मामला नहीं है। – bronekk

+0

@ bronekk- आपके द्वारा उद्धृत शेष वाक्य में कहा गया है कि नए रिटर्न प्रकार को मूल प्रकार कहीं भी उपयोग करने योग्य होना चाहिए; यही है, नया प्रकार मूल के साथ covariant है। – templatetypedef

+0

कि शेष वाक्य सही नहीं है; 'base *' 'long' 'और' derived * '' int' के साथ 'बेस *' को बदलने की कल्पना करें (या दूसरी तरफ, कोई फर्क नहीं पड़ता)। यह काम नहीं करेगा। – bronekk

44

हां। रिटर्न प्रकारों को तब तक अलग होने की अनुमति है जब तक वे covariant हों। सी ++ मानक इस (§10.3/5) की तरह यह वर्णन करता है:

एक अधिभावी समारोह की वापसी प्रकार ओवरराइड समारोह की वापसी प्रकार या कार्यों की कक्षाओं के साथ covariant के लिए या तो समान होगा। एक समारोह D::f एक समारोह B::f ओवरराइड करता है, तो कार्य की वापसी प्रकार covariant कर रहे हैं निम्नलिखित मानदंडों को पूरा:

  • दोनों वर्गों की ओर इशारा या वर्गों 98)
  • में वर्ग के लिए संदर्भ B::f की वापसी प्रकार D::f की वापसी प्रकार में वर्ग के रूप में एक ही कक्षा है या, D::f की वापसी प्रकार में वर्ग का एक स्पष्ट प्रत्यक्ष या अप्रत्यक्ष आधार वर्ग है और D
  • दोनों संकेत में पहुँचा जा सकता है या संदर्भ है D::f के रिटर्न प्रकार में समान सीवी-योग्यता और वर्ग प्रकार में B::f के रिटर्न प्रकार में कक्षा प्रकार की तुलना में समान सीवी-योग्यता के समान सीवी-योग्यता है।

फ़ुटनोट 98 बाहर है कि अंक "वर्ग या वर्गों के लिए बहु स्तरीय संकेत के लिए संदर्भ के लिए बहु स्तरीय संकेत की अनुमति नहीं है।"

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

struct Base { /* ... */ }; 
struct Derived: public Base { /* ... */ }; 

struct B { 
    virtual Base* func() { return new Base; } 
    virtual ~B() { } 
}; 
struct D: public B { 
    Derived* func() { return new Derived; } 
}; 

int main() { 
    B* b = new D; 
    Base* base = b->func(); 
    delete base; 
    delete b; 
} 

कारण यह काम करता है क्योंकि func के किसी भी फोन करने वाले एक Base सूचक उम्मीद कर रही है। कोई भी Base सूचक करेगा। इसलिए, यदि D::func हमेशा Derived पॉइंटर वापस करने का वादा करता है, तो यह हमेशा पूर्वजों वर्ग द्वारा निर्धारित अनुबंध को पूरा करेगा क्योंकि Derived सूचक को Base पॉइंटर में रूपांतरित किया जा सकता है। इस प्रकार, कॉलर्स हमेशा वे उम्मीद करेंगे जो वे उम्मीद करते हैं।


वापसी प्रकार अलग-अलग करने के लिए अनुमति के अलावा, कुछ भाषाओं पैरामीटर प्रकार अधिभावी समारोह भिन्न करने की भी अनुमति देते हैं। जब वे ऐसा करते हैं, तो उन्हें आमतौर पर contravariant होने की आवश्यकता होती है। यही है, यदि B::fDerived* स्वीकार करता है, तो D::f को Base* स्वीकार करने की अनुमति होगी। Descendants looser होने की अनुमति दी जाती है, और वे कठोर जो वे वापस लौटते हैं। सी ++ पैरामीटर-प्रकार contravariance की अनुमति नहीं देता है। यदि आप पैरामीटर प्रकार बदलते हैं, तो सी ++ इसे एक नया नया फ़ंक्शन मानता है, इसलिए आप ओवरलोडिंग और छिपाने लगते हैं।इस विषय पर अधिक जानकारी के लिए, विकिपीडिया में Covariance and contravariance (computer science) देखें।

+0

ठीक है, मैंने आज कुछ सीखा। +1। –

+2

क्या यह वास्तविक सुविधा या रिटर्न प्रकार से दुष्प्रभाव का उपयोग नहीं किया जा रहा है? –

+1

@ मार्टिन, निश्चित रूप से एक सुविधा। मुझे यकीन है कि ओवरलोड रिज़ॉल्यूशन के साथ इसके साथ कुछ लेना देना नहीं था। यदि आप फ़ंक्शन ओवरराइड कर रहे हैं तो वापसी प्रकार * है * उपयोग किया जाता है। –

2

वर्चुअल फ़ंक्शन के व्युत्पन्न क्लास कार्यान्वयन में Covariant Return Type हो सकता है।

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