2008-09-16 25 views
35

निम्नलिखित उदाहरण को देखते हुए, मुझे b->DoSomething() के बजाय कथन b->A::DoSomething() का स्पष्ट रूप से उपयोग क्यों करना है?सी ++ ओवरलोड रिज़ॉल्यूशन

क्या कंपाइलर का ओवरलोड रिज़ॉल्यूशन यह नहीं समझ सकता कि मैं किस विधि के बारे में बात कर रहा हूं?

मैं उपयोग कर रहा हूँ माइक्रोसॉफ्ट वी.एस. 2005 (नोट: आभासी इस मामले में मदद नहीं करता है का उपयोग कर।)

class A 
{ 
    public: 
    int DoSomething() {return 0;}; 
}; 

class B : public A 
{ 
    public: 
    int DoSomething(int x) {return 1;}; 
}; 

int main() 
{ 
    B* b = new B(); 
    b->A::DoSomething(); //Why this? 
    //b->DoSomething(); //Why not this? (Gives compiler error.) 
    delete b; 
    return 0; 
} 
+0

मैं कक्षा बी में एक पॉइंटर का उपयोग कर कक्षा ए में DoSomething() को कॉल करने की कोशिश कर रहा हूं। – Abe

उत्तर

40

दो "भार के" एक ही दायरे में नहीं हैं। डिफ़ॉल्ट रूप से, संकलक केवल सबसे छोटा संभव नाम स्कोप मानता है जब तक कि उसे नाम मिलान नहीं मिलता है। तर्क मिलान बाद में किया जाता है। आपके मामले में इसका मतलब है कि संकलक B::DoSomething देखता है। यह फिर तर्क सूची से मेल खाता है, जो विफल रहता है।

एक समाधान 'B रों दायरे में A से अधिभार नीचे खींचने के लिए होगा:

class B : public A { 
public: 
    using A::DoSomething; 
    // … 
} 
+1

वास्तव में यदि वे एक ही दायरे में नहीं हैं, तो उन्हें ओवरलोड भी नहीं कहा जाता है, साथ ही – Chubsdad

+3

@Chubsdad: यही कारण है कि मैंने शब्द रखा उद्धरण में। और एक बार विधि को एक ही दायरे में खींच लिया जाता है, यह एक अधिभार बन जाता है। –

13

अधिभार संकल्प सी ++

के ugliest भागों में से एक है मूल रूप से संकलक एक नाम मैच "पाता है बी के दायरे में कुछ (int) ", मानता है कि पैरामीटर मेल नहीं खाते हैं, और एक त्रुटि के साथ बंद हो जाता है।

यह वर्ग बी

class A 
{ 
    public: 
    int DoSomething() {return 0;} 
}; 

class B : public A 
{ 
    public: 
    using A::DoSomething; 
    int DoSomething(int x) {return 1;} 
}; 


int main(int argc, char** argv) 
{ 
    B* b = new B(); 
    // b->A::DoSomething(); // still works, but... 
    b->DoSomething(); // works now too 
    delete b; 
    return 0; 
} 
2

में एक :: DoSomething का उपयोग करते समय आप एक व्युत्पन्न वर्ग में एक समारोह को परिभाषित द्वारा दूर किया जा सकता है तो यह आधार वर्ग में उस नाम के साथ सभी कार्यों छुपाता है। यदि बेस क्लास फ़ंक्शन वर्चुअल है और उसके पास संगत हस्ताक्षर है तो व्युत्पन्न क्लास फ़ंक्शन बेस क्लास फ़ंक्शन को ओवरराइड करता है। हालांकि, यह दृश्यता को प्रभावित नहीं करता है।

आप आधार वर्ग समारोह एक का उपयोग कर घोषणा के साथ दृश्यमान बना सकते हैं:

class B : public A 
{ 
    public: 
    int DoSomething(int x) {return 1;}; 
    using A::DoSomething; 
}; 
1

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

class B : public A 
{ 
    public: 
    using A::DoSomething; 
    int DoSomething(int x) {return 1;}; 
}; 
1

समारोह समारोह से में एक ही नाम के साथ छिपा हुआ है उपclass (लेकिन एक अलग हस्ताक्षर के साथ)। ए :: DoSomething() का उपयोग करने के रूप में, आप उपयोग कथन का उपयोग कर इसे अनदेखा कर सकते हैं;

5

नहीं, यह व्यवहार यह सुनिश्चित करने के लिए मौजूद है कि आप गलती से दूरस्थ आधार वर्गों से विरासत में नहीं पहुंच पाएंगे।

इसके आस-पास पहुंचने के लिए, आपको कंपाइलर को यह बताने की आवश्यकता है कि आप बी श्रेणी में ए :: DoSomething का उपयोग करके कॉल करना चाहते हैं।

इस व्यवहार के त्वरित और आसान अवलोकन के लिए this article देखें।

3

इसका नाम नाम समाधान के तरीके से कुछ करना है। असल में, हम पहले उस दायरे को पाते हैं जिसमें से नाम आता है, और फिर हम उस दायरे में उस नाम के लिए सभी अधिभार एकत्र करते हैं।हालांकि, आपके मामले में गुंजाइश वर्ग बी है, और वर्ग बी में, बी :: DoSomething छुपाता एक :: DoSomething:

3.3.7 नाम छुपा [basic.scope.hiding]

.. [स्निप] ...

3 सदस्य कार्य परिभाषा में, स्थानीय नाम की घोषणा को उसी नाम के साथ कक्षा के सदस्य की घोषणा छुपाती है; basic.scope.class देखें। एक व्युत्पन्न वर्ग (class.derived) में एक सदस्य की घोषणा एक ही नाम के एक आधार वर्ग के एक सदस्य की घोषणा छुपाता है; class.member.lookup देखें।

नाम छुपा के कारण

, ए :: DoSomething भी अधिभार संकल्प

+0

वास्तविक विनिर्देश संदर्भ अच्छा है। – Sam

2

कि अधिक भार नहीं कर रहा है के लिए विचार नहीं किया है! वह छुपा रहा है!

5

एक व्युत्पन्न वर्ग में एक विधि की उपस्थिति में एक ही नाम (चाहे मापदंडों का) आधार वर्ग में साथ सभी तरीकों छुपाता है। यह इस तरह की समस्याओं से बचने के लिए किया जाता है:

class A {} ; 
class B :public A 
{ 
    void DoSomething(long) {...} 
} 

B b; 
b.DoSomething(1);  // calls B::DoSomething((long)1)); 
बाद में किसी से

में परिवर्तन वर्ग एक:

class A 
{ 
    void DoSomething(int) {...} 
} 
अब अचानक

:

B b; 
b.DoSomething(1);  // calls A::DoSomething(1); 

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

+0

बहुत अच्छा मुद्दा, मुझे कहना होगा। अधिकांश उत्तरों में मैंने देखा है कि त्रुटि क्यों होती है और इससे कैसे बचें, लेकिन आपका बिंदु दिखाता है कि यह सुविधा असली दुनिया परिदृश्य में क्यों आवश्यक और उपयोगी है !! –

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