2012-04-16 24 views
6

चर्चा करते हुए एक और so questionनाम छुपा और आभासी कार्यों

कोड पर विचार करें के बारे में भ्रम की स्थिति:

class Base { 
public: 
    virtual void gogo(int a){ 
     printf(" Base :: gogo (int) \n"); 
    }; 

    virtual void gogo(int* a){ 
     printf(" Base :: gogo (int*) \n"); 
    }; 
}; 

class Derived : public Base{ 
public: 
    virtual void gogo(int* a){ 
     printf(" Derived :: gogo (int*) \n"); 
    }; 
}; 

int main(){ 

    // 1)  
    Derived * obj = new Derived ; 
    obj->gogo(7); // this is illegal because of name hiding 


    // 2)  
    Base* obj = new Derived ; 
    obj->gogo(7); // this is legal 
} 

मामले 2)

कॉल obj->gogo(7) के लिए रन टाइम पर हल हो गई है।

चूंकि obj->gogo(7) कानूनी है। ऐसा लगता है कि Derived के vtable में पीआरआर virtual void gogo(int a) शामिल है जो छुपा होना चाहिए था।

मेरे भ्रम की स्थिति है, क्योंकि नाम छुपा का कारण बनता है मामला 1) अवैध होने के लिए तो कैसे 2 में कॉल) रन टाइम पर

क) क्या व्युत्पन्न की vtable हल हो गई है पूर्णांक gogo के लिए() सूचक होता है।

बी) यदि ए) सत्य नहीं है, तो वर्चुअल फ़ंक्शंस के लिए कॉल रेज़ोल्यूशन बेस क्लास के vtable तक पहुंच जाता है।

+0

@AndersK फ़ंक्शन 'बेस :: gogo (int)' वास्तव में 'व्युत्पन्न :: gogo (int *)' से छिपा हुआ है। लेकिन 'व्युत्पन्न' वर्ग में 'बेस :: gogo;' कथन का उपयोग करके इस विशेष समस्या को हल किया जाएगा। –

+0

@ माइकल विल्ड हाँ, मैंने अपनी गलती देखी। –

उत्तर

0

चूंकि आपने obj को Base* के रूप में घोषित किया है, तो vtable इसे Base के सभी तरीकों को देता है। यद्यपि वर्चुअल विधियों के लिए जो Derived द्वारा ओवरराइड किए गए हैं, ओवरडिन संस्करणों को बुलाया जाता है, अन्य विधियां (या विधि ओवरलोड) अभी भी Base में घोषित की गई हैं।

हालांकि, अगर आप Derived* के रूप में सूचक की घोषणा की, vtable यह Derived के तरीकों देते हैं, जो कि Base में एक ही नाम था छुपा होगा। इसलिए, obj->gogo(7); काम नहीं करेगा। इसी तरह, यह भी गैर-कानूनी है:

Base* obj = new Derived(); 

// legal, since obj is a pointer to Base, it contains the gogo(int) method. 
obj->gogo(7); 

// illegal, it has been cast into a pointer to Derived. gogo(int) is hidden. 
(reinterpret_cast<Derived*>(obj))->gogo(7); 

यह कानूनी है:

Derived* obj = new Derived ; 
obj->Base::gogo(7); // legal. 

देखें here

+0

आपके उदाहरण में 'dynamic_cast' अधिक उपयुक्त नहीं होगा? – Griwes

+0

जहां तक ​​मुझे पता है कि वास्तविक 'vtable' लुकअप के साथ कुछ भी नहीं है लेकिन स्थिर टाइपिंग और नाम छिपाने के साथ (बो पर्सन का जवाब देखें)। यदि प्रकार 'व्युत्पन्न' है, तो वे अर्थशास्त्र लागू होते हैं, यदि प्रकार 'आधार' है, तो अन्य अर्थात् लागू होता है। – KillianDS

5

आप वर्चुअल फ़ंक्शंस कॉल और ओवरलोड रिज़ॉल्यूशन को भ्रमित कर रहे हैं।

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

मामले में 1) आपको संकलन समय पर ओवरलोड रिज़ॉल्यूशन से एक त्रुटि प्राप्त होती है। नाम छिपाने के कारण, कक्षा Derived में केवल एक कॉल करने योग्य कार्य है। int* के साथ, उस फ़ंक्शन को कॉल करने का आपका एकमात्र विकल्प है।

+0

कोई त्रुटि नहीं है। चूंकि दोनों 'gogo() 'अधिभार को' बेस 'में घोषित किया गया था, इसलिए एक ओवरराइड करने से दूसरे को छुपाया नहीं जाएगा। –

+0

यह उपर्युक्त व्यवहार बताता है। क्या सी ++ मानक (या कोई पुस्तक/दस्तावेज़) एक ही चीज़ का वर्णन करता है। मेरा मतलब है कि उद्धरण प्राप्त करना संभव है। – fizzbuzz

+0

@fizzbuzz - एक आंतरिक दायरे में घोषित एक नाम हमेशा एक बाहरी दायरे में एक नाम छुपाता है। इस मामले में व्युत्पन्न वर्ग आंतरिक दायरा और आधार वर्ग बाहरी क्षेत्र है। –

1

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

तो, जब आप व्युत्पन्न कक्षा में किसी फ़ंक्शन को फिर से परिभाषित नहीं करते हैं और उस फ़ंक्शन को कॉल करते हैं, तो संकलक व्युत्पन्न के दायरे की जांच करता है, पता चलता है कि वहां कोई ऐसा फ़ंक्शन परिभाषित नहीं है। फिर यह बेस क्लास के दायरे की जांच करता है, फ़ंक्शन को खोजता है और तदनुसार फ़ंक्शन कॉल को इस विशेष परिभाषा से जोड़ता है।

लेकिन, जब आप विभिन्न हस्ताक्षर के साथ फ़ंक्शन को फिर से परिभाषित करते हैं, तो संकलक इस फ़ंक्शन के साथ कॉल से मेल खाता है, असंगतता को देखता है और शिकायत करता है।

आप व्युत्पन्न वर्ग परिभाषा में "बेस :: gogo का उपयोग करके" जोड़कर इस व्यवहार को बदल सकते हैं। मुझे उम्मीद है कि यह बताता है।

2

आप ओवरलोडेड फ़ंक्शन को ओवरराइड करना चाहते हैं लेकिन छिपाने वाले नियम इस तरह काम नहीं करते हैं।

"छुपा नियम कहता है कि एक आंतरिक दायरे में एक इकाई बाहरी नाम में एक ही नाम के साथ चीजों को छुपाती है।"

नोट, यह अप्रासंगिक है कि इसमें अलग हस्ताक्षर हैं यानी gogo(int* a) बेस से सभी gogo(whatever) फ़ंक्शंस छुपाएगा। ओवरराइडिंग तब होती है जब आपके कार्यों का एक ही नाम, समान हस्ताक्षर और वर्चुअल (इसलिए, केवल gogo(int* a) ओवरराइड हो जाएगा)।

सी ++ एफएक्यू पुस्तक "गैर-वर्चुअल ओवरलोड जिन्हें गैर-ओवरलोडेड वर्चुअल कहते हैं" का उपयोग करने का सुझाव देती है। (अध्याय 2 9 .05)। आभासी कार्यों क्रमशः

gogo(int a) and gogo(int* a)

जो कॉल करेंगे: मूल रूप से आप गैर आभासी अतिभारित कार्यों आधार वर्ग में बनाने

आभासी gogo_i (पूर्णांक एक) और आभासी gogo_pi (int * क)

और व्युत्पन्न कक्षा में इस वर्चुअल को ओवरराइड करें।

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