c ++ क्लैंग द्वारा ओवरलोडेड वर्चुअल फंक्शन चेतावनी?


80

निम्नलिखित कोड का संकलन करते समय क्लैंग एक चेतावनी देता है:

struct Base
{
    virtual void * get(char* e);
//    virtual void * get(char* e, int index);
};

struct Derived: public Base {
    virtual void * get(char* e, int index);
};

चेतावनी है:

warning: 'Derived::get' hides overloaded virtual function [-Woverloaded-virtual]

(उक्त चेतावनी को सक्षम करने की आवश्यकता है)।

मुझे समझ में नहीं आता क्यों। ध्यान दें कि बेस में समान घोषणा को अनसुना करने से चेतावनी समाप्त हो जाती है। मेरी समझ यह है कि चूंकि दो मिलते हैं () फ़ंक्शंस में अलग-अलग हस्ताक्षर होते हैं, इसलिए कोई छुपा नहीं हो सकता है।

क्लैंग सही है? क्यों?

ध्यान दें कि यह XOS के हाल के संस्करण को चलाने वाले MacOS X पर है।

clang --version
Apple LLVM version 5.0 (clang-500.1.74) (based on LLVM 3.3svn)

अपडेट: Xcode 4.6.3 के साथ समान व्यवहार।

जवाबों:


115

ओवरराइडिंग का इरादा होने पर ओवरलोड्स के आकस्मिक छिपने को रोकने के लिए यह चेतावनी है। थोड़ा अलग उदाहरण पर विचार करें:

struct chart; // let's pretend this exists
struct Base
{
    virtual void* get(char* e);
};

struct Derived: public Base {
    virtual void* get(chart* e); // typo, we wanted to override the same function
};

जैसा कि यह एक चेतावनी है, इसका मतलब यह नहीं है कि यह एक गलती है, लेकिन यह एक संकेत हो सकता है। आमतौर पर इस तरह की चेतावनियों का मतलब है कि उन्हें अधिक स्पष्ट करके उन्हें बंद करना और संकलक को यह बताना कि आपने जो लिखा है उसका इरादा क्या है। मेरा मानना ​​है कि इस मामले में आप निम्न कार्य कर सकते हैं:

struct Derived: public Base {
    using Base::get; // tell the compiler we want both the get from Base and ours
    virtual void * get(char* e, int index);
};

11
यह बताया जा सकता है कि, "स्थानीय रूप से चेतावनी को बंद करने" का यह समाधान कोड के शब्दार्थ को भी बदल रहा है: अब आप getफ़ंक्शन के सदस्य को स्थिर प्रकार की वस्तु पर एकल तर्क के साथ आमंत्रित कर सकते हैं Derived। उपयोग की घोषणा के बिना, एक ही बात एक संकलन त्रुटि को जन्म देगी।
विज्ञापन एन

29

संरचनात्मक सार्वजनिक इंटरफ़ेस को बरकरार रखते हुए चेतावनी को अक्षम करने का एक और तरीका होगा:

struct Derived: public Base
{
    virtual void * get(char* e, int index);
private:
    using Base::get;
};

यह चेतावनी को चुप करते हुए Derivedकॉल करने के लिए एक उपभोक्ता को Derived::get(char* e)रोकता है:

Derived der;
der.get("", 0); //Allowed
der.get("");    //Compilation error

2
यह निश्चित रूप से इस चेतावनी को हटाने का एक सुरक्षित तरीका है जब आपने आधार की कक्षा getपद्धति को बदलने की योजना बनाई थी !
jpo38

हालांकि, उन मामलों से सावधान रहें, जहां यह एक अस्पष्ट कॉल का कारण होगा। तो यह समाधान 100% भी नहीं बचा है।
sigy

22

आर। मार्टिनो फर्नांडीस का समाधान पूरी तरह से वैध है यदि आप वास्तव get()में एकल चर * तर्क को लेने की विधि को Derivedदायरे में लाना चाहते हैं ।

वास्तव में, आपके द्वारा प्रदान की गई स्निपेट में, आभासी तरीकों की कोई आवश्यकता नहीं है (क्योंकि बेस और व्युत्पन्न एक ही हस्ताक्षर के साथ कोई विधि साझा नहीं करते हैं)।

यह मानते हुए कि वास्तव में बहुरूपता की आवश्यकता है, छिपाने का व्यवहार फिर भी हो सकता है जो अभीष्ट है। इस मामले में, निम्नलिखित प्रज्ञा के साथ, क्लैंग की चेतावनी को स्थानीय रूप से अक्षम करना संभव है:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
    // Member declaration raising the warning.
#pragma clang diagnostic pop

1
यह जवाब दोगुना आश्चर्यजनक था। सबसे पहले यह सटीक उत्तर था कि मैं क्या ढूंढ रहा था, कि मैं "अपना तरीका चाहता था"। जैसा कि मैंने अपने कोड में एक टिप्पणी लिखी थी कि प्रज्ञा के कारण और क्लैंग कैसे बेवकूफ था, मेरी आँखों ने पकड़ लिया कि मैंने ओवरराइड लिखा है, लेकिन चेतावनी ओवरलोड थी। फिर मैंने क्लिक किया और महसूस किया कि मैं constविरासत में मिली विधि को भूल गया हूं , और क्लैंग बिल्कुल सही था। जब संदेह में, संकलक पर भरोसा करें। जब आप संकलक पर संदेह करते हैं, तो संकलक पर भरोसा करें। :) +1 दोनों मुझे देने के लिए जो मैंने चाहा और जरूरत थी!
नेवेलिस

17

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

यह नमूना कोड संकलित नहीं होगा:

class A
{
public:
    virtual void Foo() {}
};

class B : public A
{
public:
    virtual void Foo(int a) {}
};


int main()
{
    B b;
    b.Foo();
    return 0;
}

1
यह एक अच्छा बिंदु है: छिपाना वास्तव में सक्रिय रूप से हो रहा है, भले ही इसे रोकने के लिए विभिन्न हस्ताक्षर पर्याप्त हों।
जीन-डेनिस म्यू

छिपाने की मेरी परिभाषा में एक ही हस्ताक्षर है लेकिन ओवरराइड नहीं करना है ... जो कि यहां नहीं है।
NGauthier

संक्षेप में सी ++ से छिपाने से बचने के लिए समाधान : "यदि आप चाहते हैं कि आधार वर्ग के कार्यों को उम्मीदवारों के रूप में विचार करने के लिए संकलक द्वारा व्युत्पन्न वर्ग में एक घोषित घोषणा डालें", जैसा कि अन्य उत्तरों में दिखाया गया है।
21

यदि इसमें एक समाधान भी शामिल होगा (उपयोग कर ...) यह स्वीकृत उत्तर होना चाहिए, क्योंकि यह एकमात्र ऐसा है जो सही ढंग से बताता है कि क्या होता है और यह एक वैध चेतावनी क्यों है
माइकएम

1
मुझे लगता है कि यह सबसे स्पष्ट उत्तर है। हालांकि ध्यान देने योग्य है कि आप वास्तव में अभी भी कॉल कर सकते हैं b.Foo();। आपको बस लिखने की जरूरत है b.A::Foo();
टिम्मम्म
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.