2014-05-19 4 views
7

This मूल रूप से हर्ब Sutter की किताब Exceptional C++ में Item 21. Overriding Virtual Functions में दिए गए उदाहरण से एक प्रति है।फ़ंक्शन ओवरलोडिंग के साथ उसे क्या करना है?

#include <iostream> 
#include <complex> 
using namespace std; 
class Base 
{ 
public: 
    virtual void f(int); 
    virtual void f(double); 
    virtual ~Base() {}; 
}; 

void Base::f(int) { cout << "Base::f(int)" << endl; } 
void Base::f(double) { cout << "Base::f(double)" << endl; } 

class Derived: public Base { 
public: 
    void f(complex<double>); 
}; 

void Derived::f(complex<double>) { cout << "Derived::f(complex)" << endl; } 

int main() 
{ 
    Base* pb = new Derived; 
    pb->f(1.0); 
    delete pb; 
} 

कोड प्रिंट Base::f(double) और मैं उस के साथ कोई समस्या नहीं। (मेरा जोर है) लेकिन मैं स्पष्टीकरण पेज 122 की चोटी पर लेखक द्वारा दिए गए समझ नहीं सके:

दिलचस्प है, भले ही बेस * PB एक व्युत्पन्न वस्तु की ओर इशारा करते है, यह कहता है आधार: : च (डबल), अधिभार संकल्प स्थिर प्रकार (यहां बेस) पर किया, नहीं गतिशील प्रकार है, क्योंकि (यहाँ व्युत्पन्न)

मेरे समझ है कि कॉल pb->f(1.0) एक आभासी कॉल और Base::f(double)Derived में f(double) के लिए अंतिम overrider है। फ़ंक्शन ओवरलोडिंग के साथ उसे क्या करना है? जबकि अधिक भार संकल्प कॉल के प्रभावित करता है एक विशेषता है

+2

पीबी को 'व्युत्पन्न *' में बदलें और देखें कि क्या होगा। – dlf

+0

@ डीएलएफ: और संकलक चेतावनी भी देता है :-) – Jarod42

+4

यह शीर्षक बहुत उपयोगी नहीं है। कल्पना करें कि अगर आप इसे खोज परिणामों में देखते हैं तो आप क्या सोचेंगे। –

उत्तर

12

यहाँ नाजुक हिस्सा है, कि आभासी तरीकों एक तंत्र हैं प्रेषण करने के लिए समारोह कॉल।

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

Base और Derived की परिभाषा हम ऊपर दिए गए आसानी से कारण सकते हैं कि अगर f(double) एक Base* तो फोन पर कहा जाता है (यदि लागू हो) आधार कार्यान्वयन के लिए वरीयता में किसी भी व्युत्पन्न ओवरराइड के लिए भेजा जाना चाहिए से

। लेकिन जवाब देने कि एक सवाल

स्रोत का कहना है जब pb->f(1.0) से पूरी तरह से अलग है, जो नामित तरीकों में से f विधि कॉल को हल करने के लिए इस्तेमाल किया जाना चाहिए उत्तर दे रहा है?

सूटर बताते हैं, कल्पना है कि जब कॉल को हल करने संकलक f नामित स्थिर प्रकार पर घोषित तरीकों पर नजर डालेंगे कहते pb द्वारा की ओर इशारा किया, इस मामले में, स्थिर प्रकार Base* इतना भार के (ओवरराइड करता है नहीं!) घोषित पर Derived सब पर विचार नहीं किया जाएगा है। हालांकि, अगर कॉल virtual पर हल करने की विधि है तो Derived पर प्रदान किए गए संभावित कार्यान्वयन का उपयोग अपेक्षित के रूप में किया जाएगा।

+3

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

3

कारण इस उदाहरण दिलचस्प है, क्योंकि, अगर pb एक Base* के बजाय एक Derived*, या यदि संकलक किसी भी तरह अधिभार संकल्प प्रदर्शन के लिए स्थिर प्रकार के बजाय गतिशील प्रकार इस्तेमाल कर सकते हैं, यह pb->f(1.0) करने के लिए कॉल से मेल खाएंगे थे void Derived::f(complex<double>) (complex<double> को double से अंतर्निहित रूप से बनाया जा सकता है)। इसका कारण यह है एक व्युत्पन्न वर्ग में f नाम के एक समारोह की उपस्थिति प्रभावी रूप से एक ही नाम के साथ किसी भी आधार वर्ग छुपाता भार के, भले ही उनके तर्क सूचियों भिन्न हैं।लेकिन चूंकि स्थिर प्रकार pb वास्तव में Base* है, ऐसा नहीं होता है।

0

इस उदाहरण में, virtual की बार-बार होने वाली घटना के बावजूद, कोई विधि ओवरराइडिंग नहीं है; व्युत्पन्न कक्षा में विधि f बेस क्लास में से किसी एक को ओवरराइड नहीं करती है, क्योंकि तर्क प्रकार मेल नहीं खाते हैं। इस परिस्थिति को देखते हुए, pb->f का कॉल कभी भी (अद्वितीय) विधि Derived::f का आह्वान नहीं कर सकता है। ओवरलोड रिज़ॉल्यूशन/नाम लुकअप (जो केवल pb->f के स्थिर प्रकार के तरीकों को मानता है) को Base::f के रूप में घोषित दो विधियों के बीच चयन करना होगा, और उदाहरण में यह तर्क प्रकार double के साथ एक का चयन करेगा। (रनटाइम पर इस एक ओवरराइड बुला खत्म हो सकता है, अगर एक Derived की तुलना में एक अलग व्युत्पन्न वर्ग में परिभाषित किया गया है, और अगर उदाहरण के संशोधित किया गया है ताकि pb संभवतः इस तरह के एक और व्युत्पन्न वर्ग की एक वस्तु को इंगित कर सकते हैं।)

एक अलग मुद्दा यह है कि fBase और Derived में विधियों को ओवरलोड रिज़ॉल्यूशन के लिए एक साथ नहीं माना जाएगा यदि f को (स्थिर) प्रकार Derived की अभिव्यक्ति से कहा जाता है, इस बार क्योंकि बेस क्लास में विधियां छिपी हुई हैं f की घोषणा Derived में, इसलिए वे ऐसी कॉल के लिए उपलब्ध नहीं हैं। मुझे लगता है कि using Base::f; घोषित करके इस छिपाने से बचा जा सकता है, जो Base::f को Derived में "लिफ्ट" करता है जैसे कि उन्हें वहां भी घोषित किया गया था (लेकिन मैं इस तंत्र के विवरण को नहीं जानता; मुझे लगता है कि लिफ्ट वर्चुअल के ओवरराइड होंगे एक ही तर्क प्रकार के साथ आधार विधि, लेकिन इससे थोड़ा अंतर होता है क्योंकि लिफ्टों को बेस क्लास में कार्यान्वयन का संदर्भ मिलता है।)

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