7

मान लीजिए मैं एक आधार वर्ग जो व्युत्पन्न वर्ग की क्लोनिंग है:व्युत्पन्न दिलचस्प आवर्ती टेम्पलेट्स और सहप्रसरण

class Base 
{ 
    public: 
     virtual Base * clone() 
     { 
      return new Base(); 
     } 

     // ... 
}; 

मैं व्युत्पन्न वर्ग है जो एक दिलचस्प आवर्ती टेम्पलेट पद्धति का उपयोग कर कार्यान्वित किया जाता है का एक सेट है:

template <class T> 
class CRTP : public Base 
{ 
    public: 
     virtual T * clone() 
     { 
      return new T(); 
     } 

     // ... 
}; 

और मैं आगे इस तरह से प्राप्त करने के प्रयास:

class Derived : public CRTP<Derived> 
{ 
    public: 
     // ... 
}; 

मैं के प्रभाव के लिए संकलन त्रुटियों मिलती है:

error C2555: 'CRTP<T>::clone': overriding virtual function return type differs and is not covariant from 'Base::clone' 

मुझे पता है यह शायद पूरी तरह से नहीं व्युत्पन्न जब instantiating CRTP के लिए विरासत पेड़ जानने संकलक का परिणाम है। इसके अलावा, रिटर्न प्रकार (टी *) को बदलकर (बेस *) को भी संकलित करता है। हालांकि, मैं जानना चाहता हूं कि उपरोक्त अर्थशास्त्र को बरकरार रखने वाला कोई काम है या नहीं।

+1

इसके लायक होने के लिए, जीसीसी 4.1.2 और 4.7.1 दोनों समान त्रुटियां देते हैं। –

+1

http://stackoverflow.com/questions/15570333/crtp-and-dynamic-polymorphism-compile-error – erikced

+0

@erikced का डुप्लिकेट सिर के लिए धन्यवाद। ऐसा लगता है कि मैं इतना कुछ नहीं कर सकता, मैं सिर्फ वापसी प्रकार को प्रतिस्थापित कर दूंगा। – Whanhee

उत्तर

3

एक बहुत सुंदर कामकाज नहीं है।

class Base 
{ 
    protected: 
     virtual Base * clone_p() 
     { 
      return new Base(); 
     } 
}; 


template <class T> 
class CRTP : public Base 
{ 
    protected: 
     virtual CRTP* clone_p() 
     { 
      return new T; 
     } 
    public: 
     T* clone() 
     { 
      CRTP* res = clone_p(); 
      return static_cast<T*>(res); 
     } 
}; 


class Derived : public CRTP<Derived> 
{ 
    public: 
}; 

उपयोग dynamic_cast<> बजाय static यदि आपको लगता है कि यह सुरक्षित है।

+0

सहायता के लिए धन्यवाद। काफी अर्थशास्त्र नहीं है जिसे मैं ढूंढ रहा हूं, क्योंकि आदर्श आधार में एक ही क्लोन() कॉल होगा। – Whanhee

1

आप पूरा प्रकार निर्दिष्ट करने के लिए एक अलग सिंटैक्स का उपयोग करने के साथ रह सकते हैं, तो आप निम्न (चेतावनी: अपरीक्षित कोड): कर सकता मशीनरी के साथ

आइए पहली शुरुआत:

// this gives the complete type which needs to be used to create objects 
// and provides the implementation of clone() 
template<typename T> class Cloneable: 
    public T 
{ 
public: 
    template<typename... U> Cloneable(U&&... u): T(std::forward<U>(u) ...) {} 
    T* clone() { return new Cloneable(*this); } 
private: 
    // this makes the class complete 
    // Note: T:: to make it type dependent, so it can be found despite not yet defined 
    typename T::CloneableBase::CloneableKey unlock() {} 
}; 

// this provides the clone function prototype and also makes sure that only 
// Cloneable<T> can be instantiated 
class CloneableBase 
{ 
    template<typename T> friend class Cloneable; 

    // this type is only accessible to Clonerable instances 
    struct CloneableKey {}; 

    // this has to be implemented to complete the class; only Cloneable instances can do that 
    virtual CloneableKey unlock() = 0; 
public: 
    virtual CloneableBase* clone() = 0; 
    virtual ~CloneableBase() {} 
}; 

ठीक है, अब वास्तविक वर्ग पदानुक्रम। वह एक सुंदर मानक है; कोई सीआरटीपी मध्यवर्ती या अन्य जटिलताओं। हालांकि कोई वर्ग clone फ़ंक्शन लागू नहीं करता है, लेकिन सभी CloneableBase से घोषणा (प्रत्यक्ष या परोक्ष रूप से) का उत्तराधिकारी हैं।

// Base inherits clone() from CloneableBase 
class Base: 
    public CloneableBase 
{ 
    // ... 
}; 

// Derived can inherit normally from Base, nothing special here 
class Derived: 
    public Base 
{ 
    // ... 
}; 

तरीका यहां बताया गया तो वस्तुओं को बनाने के लिए:

// However, to create new instances, we actually need to use Cloneable<Derived> 
Cloneable<Derived> someObject; 
Derived* ptr = new Cloneable<Derived>(whatever); 

// Now we clone the objects 
Derived* clone1 = someObject.clone(); 
Derived* clone2 = ptr->clone(); 

// we can get rid og the objects the usual way: 
delete ptr; 
delete clone1; 
delete clone2; 

ध्यान दें कि एक Cloneable<Derived> है-एक Derived (यह एक उपवर्ग है), इसलिए आप केवल निर्माण के लिए Cloneable उपयोग करने की आवश्यकता है, और इनकी नकल कर सकते हैं Derived ऑब्जेक्ट्स के साथ काम करने के लिए (अच्छी तरह से, tyepinfo इसे Cloneable<Derived> के रूप में भी पहचानेंगे)।

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