2012-06-07 12 views
12

मान लिया जाये कि मैं दो वर्गों, आदिम प्रकार लिखने के लिए सबसे पहले एक (bool, int, float, आदि) और दूसरा एक विस्तार पहले भी जटिल प्रकार लिखना पड़ा:सी ++ इस टेम्पलेट विधि को विधि अधिभार में क्यों पसंद करता है?

struct Writer { 
    virtual void Write(int value) = 0; 
}; 

struct ComplexWriter : public Writer { 
    template <typename TValue> void Write(const TValue &value) { 
     boost::any any(value); 
     Write(any); 
    } 
    //virtual void Write(int value) = 0; // see question below 
    virtual void Write(const boost::any &any) = 0; 
}; 

विचार है कि यदि है कोई myWriter.Write(someIntValue); पर कॉल करता है, int अधिभार टेम्पलेट विधि पर प्राथमिकता प्राप्त करेगा।

इसके बजाय, मेरा कंपाइलर (विजुअल सी ++ 11.0 आरसी) हमेशा टेम्पलेट विधि चुनता है। निम्नलिखित कोड का टुकड़ा, उदाहरण के लिए, कंसोल के लिए Wrote any प्रिंट होगा:

struct ComplexWriterImpl : public ComplexWriter { 
    virtual void Write(int value) { std::cout << "Wrote an int"; } 
    virtual void Write(const boost::any &any) { std::cout << "Wrote any"; } 
}; 

void TestWriter(ComplexWriter &writer) { 
    int x = 0; 
    writer.Write(x); 
} 

int main() { 
    ComplexWriterImpl writer; 
    TestWriter(writer); 
} 

व्यवहार अचानक बदल जाता है जब मैं ComplexWriter कक्षा में Write(int) प्रणाली की घोषणा के साथ-साथ (देखें पहली लाइन खोजें बाहर टिप्पणी की)। इसके बाद यह कंसोल पर Wrote an int प्रिंट करता है।

क्या यह मेरे संकलक को व्यवहार करना चाहिए? क्या सी ++ मानक स्पष्ट रूप से कहता है कि एक ही कक्षा (और आधार वर्ग नहीं) में परिभाषित केवल ओवरलोड को एक टेम्पलेट विधि पर प्राथमिकता दी जाएगी?

+2

मैं नहीं दिख रहा है जहाँ आप एक टेम्प्लेट के साथ एक विधि लेने पूर्णांक ओवरलोड। आपके पास दो असंबंधित वर्ग हैं, 'राइटर' एक विधि के साथ 'int' और' ComplexWriter 'लेने वाली विधि के साथ (और' बूस्ट :: किसी भी कॉन्स्ट 'और' विधि 'लेते हुए एक विधि है। अपने परीक्षण कोड में आप 'ComplexWriter' का उपयोग करते हैं, इसलिए निश्चित रूप से यह' ComplexWriter' के सदस्य को कॉल करेगा। यदि आप वास्तव में पूरी तरह से असंबंधित वर्ग 'लेखक' के सदस्य को कॉल करने की उम्मीद करते हैं, तो क्या आप समझा सकते हैं कि क्यों (और कैसे) इसे करना चाहिए? – celtschk

+2

आप उल्लेख करते हैं कि 'ComplexWriter'' राइटर 'बढ़ाता है, लेकिन आपके द्वारा सूचीबद्ध कोड में यह' राइटर 'से प्राप्त नहीं होता है। क्या यह सही सेटअप है? – Attila

+0

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

उत्तर

7

समस्या यह है कि बिंदु पर आप संकलक एक ComplexWriter नहीं एक ComplexWriterImpl देखता writer.Write(x) कॉल कर रहे है, इसलिए यह काम करता है ComplexWriter में परिभाषित की केवल बारे में पता है - टेम्पलेट समारोह और boost::any कार्य करते हैं।

ComplexWriter किसी भी आभासी कार्यों है कि एक int स्वीकार शामिल नहीं है, तो यह कोई तरीका नहीं है पूर्णांक अधिभार ComplexWriterImpl

में परिभाषित किया गया जब आप ComplexWriter वर्ग के लिए आभासी अधिभार में जोड़ें, फिर संकलक के माध्यम से कॉल करने के लिए है जागरूक ComplexWriter कक्षा में एक पूर्णांक अधिभार नहीं है कि हो जाता है और इसलिए यह करने के लिए के माध्यम से कॉल में ComplexWriterImpl

संपादित कार्यान्वयन है: कि आप ComplexWriter & लेखक के बीच विरासत में संपादित कर लिया है अब, मैं के लिए एक अधिक पूर्ण विवरण मिल गया है आप:

जब आप उप-वर्ग बनाते हैं और इसमें कोई फ़ंक्शन परिभाषित करते हैं तो बेस श्रेणी में उस नाम के सभी कार्यों को उनके तर्क प्रकारों के बावजूद छुपाया जाएगा।

आप कीवर्ड का उपयोग कर के साथ इस के आसपास मिल सकता है मेरा मानना ​​है कि: http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9

संपादित करें 2:

struct ComplexWriter : public Writer { 
    template <typename TValue> void Write(const TValue &value) { 
     boost::any any(value); 
     Write(any); 
    } 
    using Writer::Write; 
    virtual void Write(const boost::any &any) = 0; 
}; 

अधिक जानकारी के लिए इस सामान्य प्रश्न प्रविष्टि देख बस पुष्टि करते हैं कि यह वास्तव में अपनी समस्या को हल करता है: http://ideone.com/LRb5a

+0

हाँ, मैं अपने स्निपेट में बेस क्लास निर्दिष्ट करना भूल गया था। कॉम्प्लेक्सवाइटर राइटर से प्राप्त करता है, लेकिन जिस व्यवहार को मैं देख रहा हूं वह है जैसा मैंने समझाया है, यहां तक ​​कि आधार वर्ग के साथ भी सही ढंग से निर्दिष्ट किया गया है। – Cygon

+0

@ साइगॉन हाँ, ने देखा कि। मैं बस अभी एक स्पष्टीकरण/संपादन के साथ आने की कोशिश कर रहा हूं। हालांकि अगर मैं असफल रहता हूं तो मैं इस जवाब को हटा सकता हूं! – obmarg

+0

किसी भी मामले में त्वरित उत्तर के लिए धन्यवाद! बेस क्लास को निर्दिष्ट करने के लिए भूलना वास्तव में एक मूर्खतापूर्ण गलती थी क्योंकि यह पूरे प्रश्न को छोड़ देता था :) – Cygon

2

आप ComplexWriter "इंटरफेस" के माध्यम से वस्तु पर पहुंचते हैं, संकलक Write(int) को समारोह कॉल है कि कक्षा में परिभाषाओं का उपयोग को हल करने की कोशिश करेंगे। यदि ऐसा करने में सक्षम नहीं है, तो यह आधार वर्गों पर विचार करेगा।

इस मामले में, आपके पास दो उम्मीदवार हैं: Write(any) और टेम्पलेट संस्करण। चूंकि इस बिंदु पर कोई स्पष्ट Write(int) उपलब्ध नहीं है, इसलिए इन दो विकल्पों के बीच चयन करना होगा।Write(any) को एक निहित रूपांतरण की आवश्यकता है, जबकि टेम्पलेट संस्करण नहीं है, इसलिए टेम्पलेट संस्करण को कॉल किया जाता है (जो बदले में Write(any) पर कॉल करता है)।

Write(int)Writer से उपलब्ध कराने के लिए, आयात Writer::Write कार्य:

class ComplexWriter : public Writer 
{ 
    using Writer::Write; 
    // rest is as before 
}; 
संबंधित मुद्दे