2011-02-10 13 views
11

नीचे दिए गए कोड को देखते हुए, कंपाइलर एक संदेश दिखा रहा है जो error: templates may not be ‘virtual’ इंगित करता है। क्या किसी को बग को हल करने के बारे में कोई सुझाव है?टेम्पलेट्स 'वर्चुअल' नहीं हो सकते हैं

template < class FOO_TYPE> 
class CFoo{ 
    public: 
     ... 
     template < class BAR_TYPE > 
     virtual void doSomething(const CBar<BAR_TYPE> &); // here's the error 
     ... 
     virtual ~CFoo(); 
    protected: 
     MyClass <FOO_TYPE> * m_pClass; 
}; 

template < class FOO_TYPE > 
template < class BAR_TYPE > 
void CFoo<FOO_TYPE>::doSomething(const CBar<BAR_TYPE> & refBar){ 
    ... 
} 
+5

यह एक बग नहीं है, यह एक सुविधा है, आप वर्चुअल वर्क टेम्पलेट घोषित नहीं कर सकते हैं। आपको एक और दृष्टिकोण तलाशने की ज़रूरत है, और यह उस पर निर्भर करता है कि आप क्या करने की कोशिश कर रहे हैं ... – Nim

+0

बात यह है कि फ़ंक्शन का पैरामीटर एक टेम्पलेट ऑब्जेक्ट है और मैं इसकी घोषणा नहीं बदल सकता। – Javier

+0

सीबीर के प्रत्येक उदाहरण के लिए आपको एक अलग फ़ंक्शन की आवश्यकता क्यों है? –

उत्तर

16

को देखने के लिए यह अवैध क्यों है सबसे आसान कारण vtable पर विचार कर रहा है: यहाँ नमूना कोड आप यह अनुमान लगा रहा है। बेशक, यह सिर्फ एक आम कार्यान्वयन है, और दूसरों की अनुमति है। लेकिन सी ++ में सभी virtual फ़ंक्शंस ऐसे डिज़ाइन किए गए हैं जिन्हें वे एक vtable के साथ कार्यान्वित किया जा सकता है।

अब CFoo<int> में कितनी प्रविष्टियां हैं? क्या doSomething<float> के लिए कोई प्रविष्टि है? और doSomething<float*>? और doSomething<float**>? इस तरह के टेम्पलेट्स कार्यों के एक अनंत सेट को उत्पन्न करने की अनुमति देते हैं। आम तौर पर यह कोई समस्या नहीं है, क्योंकि आप केवल एक सीमित सबसेट का उपयोग करते हैं, लेकिन वर्चुअल फ़ंक्शंस के लिए यह सबसेट ज्ञात नहीं है, और इसलिए Vtable को अनंत होने की आवश्यकता होगी।

अब, यह संभव है कि आप वास्तव में vtable में केवल एक ही प्रविष्टि चाहते थे। उस मामले में, आप इसे लिखते इस प्रकार हैं:

template < class FOO_TYPE, class BAR_TYPE> 
class CFoo{ 
    public: 
     ... 
     virtual void doSomething(const CBar<BAR_TYPE> &); // now OK. 
     ... 
     virtual ~CFoo(); 
    protected: 
     MyClass <FOO_TYPE> * m_pClass; 
}; 

इसका मतलब है कि CFoo<int, float> के लिए vtable प्रविष्टियां हो, तो doSomething(float const&) के लिए होगा।

+1

सभी संकलन इकाइयों को संकलित करने के बाद इसे लिंक चरण में जाना जा सकता है। यहां पर छोड़ने के लिए मानक थोड़ा तेज है। –

+3

@ v.oddou: यथार्थवादी नहीं। लिंकर को सभी संभावित बेस क्लास, और तत्काल टेम्पलेट्स के लिए सभी वर्चुअल कॉल से मिलान करना होगा। उन तत्कालताओं को संकलित करने की आवश्यकता है। बदले में उन नए तात्कालिकताओं में नई वर्चुअल कॉल हो सकती है, इसलिए इस प्रक्रिया को पुनरावृत्ति करना होगा। – MSalters

1

ठीक है, त्रुटि संदेश बहुत स्पष्ट है। Member function templates can't be virtual। इसका समाधान कैसे करें आपकी समस्या पर निर्भर करता है, लेकिन सबसे आसान काम यह है कि सदस्य गैर-आभासी कार्य करता है और आपके डिज़ाइन पर पुनर्विचार करता है।

+0

धन्यवाद। मेरे मामले में, मुझे पैरामीटर के रूप में यह "refBar" होना चाहिए और यह एक टेम्पलेट श्रेणी से संबंधित है। – Javier

+1

क्या आप जानते हैं कि कितने अलग टेम्पलेट पैरामीटर होंगे? 3? 8? क्या आप उनमें से प्रत्येक के लिए फ़ंक्शन अधिभारित कर सकते हैं? यदि आप नहीं जानते हैं, तो संकलक कैसे जानेंगे कि कितने वर्चुअल फ़ंक्शन हैं? –

+0

@ बो: केवल 2 पैरामीटर: FOO_TYPE और BAR_TYPE – Javier

1

यदि आपको वास्तव में इस विधि को वर्चुअल बनाने की आवश्यकता है, तो CBar<> पॉलिमॉर्फिक बनाने पर विचार करें और आधार प्रकार को पास करें जिसमें टेम्पलेट नहीं किया गया है।

संपादित करें: कुछ इस तरह:

// non-templated base class 
class BarBase 
{ 
// common methods go here.. 
}; 

template <typename BAR_TYPE> 
class CBar : public BarBase 
{ 
// implement methods from BarBase ... 
}; 

template < class FOO_TYPE> 
class CFoo{ 
    public: 
     ... 
     // now we take the base type, and this method does not need to be a template 
     virtual void doSomething(BarBase const* ptrBar); 
     ... 
     virtual ~CFoo(); 
    protected: 
     MyClass <FOO_TYPE> * m_pClass; 
}; 

template < class FOO_TYPE > 
void CFoo<FOO_TYPE>::doSomething(BarBase const* ptrBar){ 
.. 
} 
+0

क्षमा करें, मुझे वह नहीं मिला। क्या आप एक उदाहरण बनाने में दिमाग रखते हैं? – Javier

1

आप उपयोग कर सकते हैं कि हम क्या "टेम्पलेट डिज़ाइन पैटर्न" के रूप में सिम्बियन में कहते हैं।

class Base { 
public: 
     virtual int DoSomething() = 0; 
protected: 
     Base(); 
}; 

class IntermediateBase : public Base { 
protected: 
     IntermediateBase(void* aSomeParam, void* aArg) 
     : iSomeParam(aSomeParam) 
     , iArgs(aArg) 
     {} 

     virtual int DoSomething() = 0; 
protected: 
     void* iSomeParam; 
     void* iArgs; 
}; 

template <class TYPE, class INPUT> 
class ConcreteClass : public IntermediateBase { 
     typedef int (TYPE::*MemberFuncPtr)(const INPUT&); 
public: 
     ConcreteClass(TYPE& aCommandType, 
         INPUT& aArgumentsToCommand, 
         MemberFuncPtr aMFP) 
     : IntermediateBase(static_cast<TYPE*>(&aCommandType), 
          static_cast<INPUT*>(&aArgumentsToCommand)) 
     , iMFP(aMFP) 
     {} 

     virtual int DoSomething() // VIRTUAL AND INLINE Note - dont make it 
            // virtual and inline in production if 
            // possible to avoid out-of-line copy 
     { 
      return static_cast<TYPE*>(iSomeParam)->*ConcreteClass::iMFP) 
          (*(static_cast<INPUT*>(iArgs)); 
     } 
private: 
     MemberFuncPtr iMFP; 
}; 
+15

स्वरूपण मुझे कुछ चोट पहुंचाना चाहता है। – GManNickG

+0

क्षमा करें, मैंने इसे अभी स्वरूपित किया है। कोड चित्रण के लिए – Viren

+0

धन्यवाद। मैंने 'doSomething' विधि को' तर्क 'के रूप में परिभाषित किया है क्योंकि यह तर्क है। केवल दो टेम्पलेट प्रकार हैं, जो 'सीएफयू' से संबंधित हैं और दूसरा 'सीबीर' के कारण है। मुझे लगता है कि एक डबल टेम्पलेट वर्ग के रूप में 'CFU ' घोषित करके ठीक होना चाहिए। तुम क्या सोचते हो? – Javier

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