2010-08-31 18 views
7

मैं तृतीय पक्ष लाइब्रेरी द्वारा प्रदान की गई कक्षा का विस्तार कर रहा हूं। कक्षा, चलो इसे Foo पर कॉल करें, reset() विधि है जिसे Foo के व्यवहार को पुनरारंभ करने के लिए कहा जा सकता है। reset() विधि कक्षा द्वारा आंतरिक रूप से भी उपयोग की जाती है। , दुर्भाग्य सेतृतीय पक्ष विधियों को लागू करें वर्चुअल

class Bar : public Foo 
{ 
    public: 
    void reset() { 
     /* ...something... */ 
     Foo::reset(); 
    } 
}; 

के बाद से Foo::reset() विधि, आभासी नहीं है Bar::something() फोन करके मुझे मिलता है:

class Foo 
{ 
    public: 
    void reset() { 
     /* ... */ 
    } 
    void something() { 
     reset(); 
    } 
}; 

अब तक, मैं क्रम में reset() विधि ओवरलोड मेरी अतिरिक्त सुविधाओं को रीसेट करने के रूप में अच्छी तरह की जरूरत है Foo::reset() विधि Bar::reset() के बजाय बुलाया गया।

क्या कोई तरीका है (Foo::something() ओवरलोडिंग से अलग) इसे पिछड़ा वर्चुअल बनाने के लिए?

+0

वैसे, इस तरह से मैंने हमेशा वर्चुअल के रूप में सेट करना सीखा जो कि दोनों सार्वजनिक और आंतरिक रूप से उपयोग किया जाता है। – Dacav

+1

यह एक बुरा निर्णय है, एनवीआई के लिए Google और आप सार्वजनिक आभासी तरीकों से बचने के लिए एक प्रवृत्ति देखेंगे। जिस समस्या का आप सामना कर रहे हैं वह अलग है: आप उस वर्ग को विस्तारित नहीं कर सकते जिसे विस्तारित करने के लिए डिज़ाइन नहीं किया गया था। –

+0

मैं दृढ़ता से गैर वर्चुअल इंटरफेस का समर्थन करता हूं। 'वर्चुअल' सार्वजनिक विधियों का उपयोग करना आपके आंतरिक में हैंडल लौटने जैसा है -> यह नो-नो है। –

उत्तर

5

आप उन वर्गों का विस्तार नहीं कर सकते हैं जिन्हें विस्तारित नहीं किया गया था।

1

नहीं यह संभव नहीं है। विधि की घोषणा की जाती है जब विधि घोषित की जाती है और आप बाद में इसे बेस क्लास में नहीं बदल सकते हैं।

आपको ऐसा करने की अनुमति देने के लिए आपदा से कम कुछ भी नहीं होगा। वर्चुअल विधियां गैर-वर्चुअल विधियों से अलग तरीके से व्यवहार करती हैं और किसी ऑब्जेक्ट को डिज़ाइन करते समय इसे जिम्मेदार माना जाना चाहिए। इस प्रस्ताव के साथ मुझे यह विचार करना होगा कि मेरी सभी विधियां 2 अलग-अलग तरीकों से व्यवहार कर सकती हैं। यह महत्वपूर्ण रूप से आवेदन की डिजाइन लागत में जोड़ता है और विश्वसनीयता को कम करता है।

1

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

संपादित करें:

आप रचना की कोशिश कर सकते हैं, उदाहरण के

class Bar { 
    Foo f; 
    // foo's methods, etc, wrapped here 
    void something() { 
     f.reset(); 
     reset(); 
    } 
}; 

लेकिन यदि आपको पूरे, निहित रूपांतरण की आवश्यकता है, तो आप अभी भी भर चुके हैं।

3

आप अपनी लाइब्रेरी में reset() वर्चुअल नहीं बना सकते हैं ताकि यह बेस क्लास के कोड को बदले बिना बेस क्लास को प्रभावित कर सके। स्टार्टर्स के लिए, कंपाइलर ने आवश्यक बहीखाता कोड नहीं जोड़ा है जो इसे reset() पर आभासी कॉल करने की अनुमति देता है।

2

विरासत का उपयोग करके इसे करने का कोई 'साफ तरीका' नहीं है। वर्चुअल एक संकलन/लिंक समय अंतर है: रनटाइम (आभासी) बनाम सीधे लिंकिंग (गैर-वर्चुअल) पर विधि को हल करने के लिए vtable का उपयोग करना।

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