2010-06-23 20 views
7

कृपया निम्नलिखित कोड पर विचार करें:अतिभारित आभासी समारोह कॉल संकल्प

class Abase{}; 
class A1:public Abase{}; 
class A2:public A1{}; 
//etc 

class Bbase{ 
public: 
    virtual void f(Abase* a); 
    virtual void f(A1* a); 
    virtual void f(A2* a); 
}; 

class B1:public Bbase{ 
public: 
    void f(A1* a); 
}; 

class B2:public Bbase{ 
public: 
    void f(A2* a); 
}; 

int main(){ 
    A1* a1=new A1(); 
    A2* a2=new A2(); 
    Bbase* b1=new B1(); 
    Bbase* b2=new B2(); 
    b1->f(a1); // calls B1::f(A1*), ok 
    b2->f(a2); // calls B2::f(A2*), ok 
    b2->f(a1); // calls Bbase::f(A1*), ok 
    b1->f(a2); // calls Bbase::f(A2*), no- want B1::f(A1*)! 
} 

मुझे पता है क्यों सी ++ आधार के लिए वस्तु के this सूचक upcasting द्वारा अंतिम पंक्ति पर समारोह कॉल को हल करने के लिए चुनता इच्छुक हूँ f() के तर्क को उखाड़ फेंकने के बजाए कक्षा? क्या कोई तरीका है कि मैं जिस व्यवहार को चाहता हूं उसे प्राप्त कर सकता हूं?

उत्तर

10

कॉल करने के लिए f का कौन सा संस्करण संकलन-समय पैरामीटर के प्रकार को देखकर बनाया गया है। इस नाम समाधान के लिए रन-टाइम प्रकार पर विचार नहीं किया जाता है। चूंकि b1Bbase* प्रकार है, Bbase के सभी सदस्यों को माना जाता है; जो A2* लेता है वह सबसे अच्छा मैच है, इसलिए वह जिसे कॉल किया जाता है।

+0

धन्यवाद - जैसा कि मैं समझता हूं कि बिंदु यह है कि f() को दिए गए तर्क के आधार पर कॉल करने के लिए वर्चुअल एफ() कॉल का संकलन संकलन समय पर होता है। तो आखिरी पंक्ति पर, संकलक पहले से ही तय कर चुका है कि एफ (ए 2 *) कहा जाएगा। तब कहा जाता है कि एफ (ए 2 *) का संस्करण रनटाइम प्रकार पर निर्भर करता है। यहां, चूंकि कक्षा बी 1 एफ (ए 2 *) से अधिक नहीं है, बेस क्लास संस्करण कहा जाता है। – stw

+0

@stw, बिल्कुल सही। –

1
b1->f(static_cast<A1*>(a2)); 

यह कंपाइलर को ए 1 के पैरामीटर के साथ अधिभार विधि का उपयोग करने के लिए मजबूर होना चाहिए।

+0

एक dynamic_cast अधिक उपयुक्त है, मुझे लगता है। – Jason

+2

@ जेसन: बेस क्लास में 'static_cast' ठीक है। –

+2

मुझे लगता है कि एक स्थिर कास्ट ठीक है, क्योंकि हम जानते हैं कि कास्ट सही है और बी) यह एक उग्र है, जो सुरक्षित है। –

0

इसे नाम छिपाने के नाम से जाना जाता है। प्रत्येक एफ जो आप एक व्युत्पन्न कक्षा में घोषित करते हैं, उसके किसी भी मूल वर्ग में हर संभव एफ छाया डालती है।

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

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

+0

नहीं, यहां समस्या दूसरी तरफ है। यह नाम-छिपाने वाला होगा यदि आप एक अधिक व्युत्पन्न कक्षा में एक पॉइंटर से कॉल करेंगे जो आधार वर्ग से विधि (ओं) को छुपाता है। –

+0

ओउप्स आप सही हैं, मैंने बहुत तेज़ पढ़ा है। –

2

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

ओवरलोड रिज़ॉल्यूशन के लिए ... ओवरलोड रिज़ॉल्यूशन एक संकलन समय प्रक्रिया है, जो तर्कों के स्थिर प्रकारों और संभावित रूपांतरणों के रैंक पर आधारित है। आपने A2 * प्रकार का तर्क दिया है। f(A2 *) उम्मीदवार ने आपके तर्क ठीक से मेल खाता है। f(A1 *) उम्मीदवार को A2 * से A1 * पर एक अतिरिक्त रूपांतरण की आवश्यकता है। उम्मीदवार जो बिल्कुल मेल खाता है उसे बेहतर माना जाता है, इसलिए यह ओवरलोड रिज़ॉल्यूशन जीतता है। सरल।

+0

क्षमा करें- मैंने गलत तरीके से 'अपकास्टिंग' शब्द का उपयोग किया था। मेरा मतलब था कि वस्तु को यहां बीबीएएस के रूप में क्यों माना जाता है। उत्तर (जैसा कि आप कहते हैं) यह है कि ओवरलोड रिज़ॉल्यूशन संकलन समय पर होता है, और संकलन समय पर ऑब्जेक्ट एक बीबीएएस होता है, इसलिए संकलक एफ (ए 2 *) चुनता है। – stw

0

बीबेस में एबेज और ए 2 के लिए आपके ओवरलोड बी 1 में छिपाए गए हैं। हो सकता है कि आप इस तरह से है कि समस्या को हल करने कर सकते हैं:

class Bbase{ 
public: 
    inline void f(Abase* a) { f_(a); } 
    inline void f(A1* a) { f_(a); } 
    inline void f(A2* a) { f_(a); } 
protected: 
    virtual void f_(Abase* a); 
    virtual void f_(A1* a); 
    virtual void f_(A2* a); 
}; 

class B1:public Bbase{ 
protected: 
    void f_(A1* a); 
}; 

class B2:public Bbase{ 
protected: 
    void f_(A2* a); 
}; 

या Bbase में एक टेम्पलेट के साथ:

class Bbase{ 
public: 
    template<class myA> 
    inline void f(myA* a) { f_(a); } 
protected: 
    virtual void f_(Abase* a); 
    virtual void f_(A1* a); 
    virtual void f_(A2* a); 
};