7
class messageA { 
}; 

class messageB { 
}; 

template<class T> 
class queue { 
public: 
    virtual ~queue() {} 
    void submit(T& x) {} 
}; 

class A : public queue<messageA>, public queue<messageB> 
{ 
}; 

int main() 
{ 
    A aa; 
    aa.submit(messageA()); 
    aa.submit(messageB()); 
} 

मेरा पहला विचार यह है कि उपर्युक्त कोड ठीक होना चाहिए, क्योंकि कक्षा ए में 2 अधिभारित सबमिट फ़ंक्शन होंगे, जो संदेश ए और संदेश बी ऑब्जेक्ट स्वीकार करेंगे।एकाधिक विरासत टेम्पलेट कक्षा

मैं जान सकती हूँ क्यों है वहाँ एक अस्पष्ट:

हालांकि, संकलक मुझे निम्न त्रुटि देता है? क्या यह बिल्कुल स्पष्ट नहीं है कि, पहली सबमिट कॉल के लिए, मैं संदेश ए संस्करण को कॉल करना चाहता हूं? दूसरे जमा कॉल के लिए, मैं संदेश बी संस्करण को कॉल करना चाहता हूं?


------ Build started: Project: main, Configuration: Release Win32 ------ 
Compiling... 
main.cpp 
.\main.cpp(21) : error C2385: ambiguous access of 'submit' 
     could be the 'submit' in base 'queue<messageA>' 
     or could be the 'submit' in base 'queue<messageB>' 
.\main.cpp(21) : error C3861: 'submit': identifier not found 
.\main.cpp(22) : error C2385: ambiguous access of 'submit' 
     could be the 'submit' in base 'queue<messageA>' 
     or could be the 'submit' in base 'queue<messageB>' 
.\main.cpp(22) : error C2664: 'queue<T>::submit' : cannot convert parameter 1 from 'messageB' to 'messageA &' 
     with 
     [ 
      T=messageA 
     ] 
.\main.cpp(22) : error C3861: 'submit': identifier not found 
+0

ध्यान दें कि 'messageA' से 'messageA' तक अंतर्निहित रूपांतरण मानक C++ नहीं है; एक गैर-कॉन्स्ट संदर्भ केवल एक lvalue (http://msdn.microsoft.com/en-us/library/186yxbac(VS.80).aspx) से बाध्य हो सकता है। 'सबमिट()' फ़ंक्शन को 'टी &' के बजाय 'कॉन्स्ट टी &' स्वीकार करना चाहिए। –

उत्तर

11

मैं अभी कोई संकलक है, लेकिन मुझे लगता है कि एक विरासत अन्य छिपाने सकता है: संकलक Koenig Lookup का उपयोग करेगा सही प्रतीक को खोजने के लिए, और अगर मैं सही ढंग से याद है, संकलक एक बार एक उपयुक्त लगता है प्रतीक (यानी, "सबमिट" नामक एक विधि), यह दूसरों के लिए माता-पिता और/या बाहरी क्षेत्रों में खोजना बंद कर देगा।

इस मामले में, मैंने सोचा कि विरासत वर्ग दोनों को प्रतीक के लिए खोजा जाएगा, लेकिन आपके सटीक कंपाइलर (विजुअल सी ++ 2003? 2008? 2010?) के बिना, मैं और अधिक अनुमान नहीं लगा सकता।

कुछ विचार करने के बाद, एक और संभावना है कि संकलक दोनों प्रतीकों मिला है, लेकिन जो कॉल करने के लिए फैसला करने में असमर्थ है (प्रतीक संकल्प के उस पल में, संकलक केवल प्रतीक नाम के लिए परवाह है, न कि इसका सटीक प्रोटोटाइप)। मेरा मानना ​​है कि यह आखिरी स्पष्टीकरण सही है।

अपने व्युत्पन्न वर्ग में बयान का उपयोग कर जोड़ने का प्रयास करें:

class A : public queue<messageA>, public queue<messageB> 
{ 
    using queue<messageA>::submit ; 
    using queue<messageB>::submit ; 
} ; 

लाने के लिए दोनों एक वर्ग दायरे में सीधे तरीकों सबमिट करें।

नोट भी, कि आपके सबमिट विधियां गैर-कॉन्स्ट संदर्भ के रूप में संदेश ले रही हैं, जबकि कन्स्ट्रक्टर में, आपके संदेश पैरामीटर अस्थायी हैं (और इस प्रकार, कॉन्स आर-मान)।

फिर से writting मुख्य रूप:

int main() 
{ 
    A aa; 
    messageA mA ; 
    messageA mB ; 
    aa.submit(mA); 
    aa.submit(mB); 
} 

मदद कर सकता है संकलन (इस लाइन 22 पर संकलक त्रुटि समझा सकता है)।

या आप गैर-कॉन्स्ट संदर्भों के बजाय कॉन्स्ट संदर्भ स्वीकार करने के लिए अपने सबमिट विधियों के प्रोटोटाइप को बदल सकते हैं।

नोट: फिर भी संकलक के बिना, तो मस्तिष्क डिबग अपने कोड ... :-P के लिए ऊपर कोड की कोशिश कर रहा ...

+0

"_ मुझे लगता है कि एक विरासत दूसरे को छुपा सकती है" नहीं। "_ कंपाइलर कोएनिग लुकअप_ का उपयोग करेगा" नहीं, यह नहीं होगा। "_ कंपाइलर दोनों प्रतीकों को मिला, लेकिन यह तय करने में असमर्थ है कि किस कॉल को कॉल करना है" हां। – curiousguy

+0

"_ememporaries (और इस प्रकार, कॉन्स आर-मान) ._" नहीं, अस्थायी ** ** स्थिर नहीं हैं **। – curiousguy

1
Something* smth1 = ((Base<Something> *)d)->createBase<Something>(); 

ठीक काम करता है।

+0

"' ((बेस *) डी) "बदसूरत और बहुत खतरनाक: आप इस सी-स्टाइल कास्ट के साथ एक गंभीर प्रकार का मुद्दा छिपाएंगे। ओटीओएच, यह 'बेस और डीबेस = * डी; dBase।createBase (); 'सुरक्षित है। – curiousguy

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