2009-06-22 30 views
16

मैं तीन अलग-अलग आधार वर्ग है:सी ++ समारोह अधिभावी

class BaseA 
{ 
public: 
    virtual int foo() = 0; 
}; 

class BaseB 
{ 
public: 
    virtual int foo() { return 42; } 
}; 

class BaseC 
{ 
public: 
    int foo() { return 42; } 
}; 

मैं तो (ए, बी या सी के लिए विकल्प के एक्स) इस तरह आधार से निकाले जाते हैं:

class Child : public BaseX 
{ 
public: 
    int foo() { return 42; } 
}; 

कैसे समारोह है तीन अलग-अलग आधार वर्गों में ओवरराइड? क्या मेरी तीन निम्नलिखित धारणाएं सही हैं? क्या कोई अन्य चेतावनी है?

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

उत्तर

13

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

    BaseA साथ
  • , यह संकलन और foo() आभासी जा रहा है और वर्ग Child में क्रियान्वित करने के साथ इच्छित रूप निष्पादित करेंगे।
  • BaseB के साथ ही, यह foo() वर्चुअल() के साथ और Child में निष्पादन के साथ इच्छित संकलन और निष्पादित करेगा।
  • BaseC के साथ तथापि, यह संकलन होगा और निष्पादित, लेकिन यह BaseC संस्करण यदि आप इसे BaseC के संदर्भ से कहते हैं, और Child संस्करण पर अमल होगा यदि आप Child के संदर्भ के साथ कहते हैं।
16

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

सी के साथ, हालांकि, फ़ंक्शन ओवरराइड नहीं किया गया है, लेकिन अधिभारित है। उस स्थिति में, केवल स्थिर प्रकार मायने रखता है: यह ऑब्जेक्ट वास्तव में क्या है (गतिशील प्रकार)

0

कक्षा बाल संकलन करता है, तो एक से ली गई, तो आप सिर्फ उस प्रकार की वस्तुओं का दृष्टांत नहीं कर सकते हैं।

यदि आप बेस से कुछ फ़ंक्शंस ओवरराइड करने जा रहे थे, तो यह मूल्यवान हो सकता है, और फिर फिर से प्राप्त हो सकता है।

2

baseâ के साथ, बच्चे वर्ग संकलन नहीं करता है, शुद्ध आभासी समारोह

यह सच है केवल यदि आप baseâ की एक वस्तु बनाने की कोशिश परिभाषित नहीं है।आप) का बाल की एक वस्तु बनाने और foo तो आप कॉल कर सकते हैं (या तो baseâ * या बाल *

BaseB, बच्चे में समारोह के साथ जब एक BaseB पर foo बुला कहा जाता है * या बाल * ।

ऑब्जेक्ट के प्रकार पर निर्भर करता है क्योंकि ऑब्जेक्ट बेसबी या चाइल्ड हो सकता है। यदि ऑब्जेक्ट बेसबी है तो बेसबी :: foo को कॉल किया जाता है।

BaseC, बच्चे में thefunction के साथ जब बच्चे पर foo बुला कहा जाता है * लेकिन BaseB * ( माता पिता कक्षा में समारोह कहा जाता है) पर नहीं।

हाँ, लेकिन आप इसे कभी नहीं करना चाहते हैं।

+0

क्या कोई विशिष्ट कारण है कि मैं ऐसा नहीं करना चाहता हूं? यद्यपि मैं नहीं कर सकता, इसके विपरीत, एक उदाहरण के साथ आना जहां मैं चाहता हूं *। क्या कोई तकनीकी कारण है या इसे सिर्फ "खराब अभ्यास" माना जाता है? – Mizipzor

+1

मुझे कोई तकनीकी कारण नहीं दिख रहा है लेकिन यह वास्तव में भ्रमित है। – Naveen

+0

@ मिज़िपोजर शायद आप किसी और के वर्ग के रूप में विरासत में हैं, लेकिन आपके पास उनका कोड नहीं है। आदर्श डिजाइन नहीं है लेकिन यह हो सकता है। – Kae

2

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

1

यह अधिकतर इस बात पर निर्भर करता है कि आपने इसे कैसे कहा।

अगर तुमने किया था:

class Child : public BaseA 
{ 
public: 
    int foo() { return 42; } 
}; 

और

BaseA baseA = new Child(); 
baseA->foo(); 

किया यह बच्चे की foo समारोह कॉल करेगा।

हालांकि, अगर आप इस किया था:

BaseA baseA = new BaseA(); 

यह एक संकलन समय त्रुटि उत्पन्न होगा।

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