2015-02-15 6 views
5

यहाँ के लिए लेखन क्लोन विधि मेरी मामला है:रोकें प्रत्येक उपवर्ग

class A 
{ 
public: 
    virtual A* clone() = 0; 
}; 

class B : public A 
{ 
    virtual B* clone() override 
    { 
     return new B(); 
    } 
}; 

मेरी कोड A की sublcasses के अब 100% में सिर्फ clone विधि ठीक उसी तरह केवल वर्ग D के लिए मैं वापसी प्रकार D है लागू और मैं निश्चित रूप से D का ऑब्जेक्ट बना देता हूं।

मैं इस डुप्लिकेशन को कैसे रोक सकता हूं? क्या पैटर्न या चाल मदद कर सकते हैं?

मैंने CRTP pattern का उपयोग करने का विचार किया है, लेकिन यह टेम्पलेट का उपयोग करता है, और मेरा कार्य वर्चुअल है। जैसा कि हम टेम्पलेट्स और आभासी कार्यों को समझते हैं असंगत हैं।

NVI pattern या तो काम नहीं करता है, क्योंकि क्लोन विधियों के रिटर्न प्रकार अलग हैं।

+0

आप सीआरटीपी, टेम्पलेट्स और आभासी कार्यों का उपयोग कर सकते हैं प्रति असंगत नहीं हैं। –

+0

शायद आप नहीं कर सकते, मुझे यकीन है कि आप शुद्ध वर्चुअल फ़ंक्शंस को पूरा करने के लिए विरासत का उपयोग कर सकते हैं या नहीं। हालांकि यह अभी भी टेम्पलेट्स से स्वतंत्र है। हो सकता है कि आप एकाधिक विरासत का उपयोग न करें बल्कि एक मध्यवर्ती वर्ग का उपयोग करके, 'कक्षा बी: सार्वजनिक क्लोनेबल {...} 'और' टेम्पलेट <कक्षा बी, कक्षा डी> कक्षा क्लोनबल: सार्वजनिक बी {.. ।} '। –

+0

आपका डुप्लिकेट कोड क्या है? प्रत्येक उपclass में क्लोन विधियों की परिभाषा केवल नए टी कॉल के साथ?या यह आपके असली प्रोजेक्ट में क्लोन विधियों में एक बड़ा कोड है? यदि यह दूसरा मामला है, तो आप केवल एक टेम्पलेट फ़ंक्शन कर सकते हैं जो किसी ऑब्जेक्ट को क्लोन करता है और इस क्लोन फ़ंक्शन को आपके क्लोन विधियों से कॉल करता है। – Johnmph

उत्तर

3

[class.virtual]/8:

D::f की covariant वापसी प्रकार में वर्ग प्रकार से अलग हैं कि B::f की, D::f की वापसी प्रकार में वर्ग प्रकार पर पूरा किया जाएगा D::f की घोषणा का बिंदु या प्रकार D श्रेणी होगी।

तो CRTP, पूरी तरह से काम नहीं कर सकते हैं के बाद से टेम्पलेट तर्क जो व्युत्पन्न वर्ग को संदर्भित करता है एक अधूरी प्रकार होगा, और इस तरह covariant वापसी प्रकार मुश्किल अनुकरण करने के लिए कर रहे हैं।

class A 
{ 
public: 
    virtual A* clone() = 0; 
}; 

namespace detail { 
    template <typename T> 
    struct Cloner : A { 
     using A::A; // For constructors 
     virtual A* clone() override {return new T;} 
    }; 
} 

template <typename T> 
struct Cloner : detail::Cloner<T> { 
    using detail::Cloner<T>::Cloner; // For constructors 

    // For callers 
    template <class=void> 
    T* clone() {return static_cast<T*>(detail::Cloner<T>::clone());} 
}; 

class B : public Cloner<B> 
{ 
}; 

Demo:

हालांकि, यहां एक कोशिश है।

नोट दो बातें:

  • व्युत्पन्न वर्ग प्रकार के सूचक के लौटने clone का अधिभार एक समारोह टेम्पलेट है। ऐसा इसलिए है कि हम वर्चुअल फ़ंक्शन clone को ओवरराइड नहीं करते हैं: यदि हम चाहते हैं, तो कोड खराब हो जाएगा, क्योंकि रिटर्न प्रकार कॉन्वर्सेंट नहीं है (ऊपर देखें)।

  • क्योंकि clone एक फ़ंक्शन टेम्पलेट है, यह सुनिश्चित करने के लिए कि यह बिल्कुल कहलाता है, हम इसे वर्चुअल clone फ़ंक्शन को छुपाने दे सकते हैं। यह विरासत के माध्यम से प्राप्त किया गया है: व्युत्पन्न कक्षाओं में नाम बेस कक्षाओं में नाम छिपाते हैं। इस प्रकार यदि हम B-पॉइंटर/संदर्भ के माध्यम से कॉल करते हैं, तो हमें उपयुक्त रिटर्न प्रकार (B*) मिलता है, क्योंकि में detail::Cloner से पहले नाम देखा गया है।

+0

हमें दूसरे 'संरचना क्लोनर' की आवश्यकता क्यों है? इसके अलावा हमें 'टेम्पलेट ' की आवश्यकता क्यों है। शायद आप कुछ छोटे स्पष्टीकरण दे सकते हैं। धन्यवाद। – Narek

+0

@Narek 1. नाम छिपाना 2. ओवरराइड नहीं। – Columbo

+0

मैं दो शब्दों में समझने के लिए सी ++ में अच्छा नहीं हूं, क्षमा करें। कृपया अधिक विस्तृत स्पष्टीकरण की सराहना करेंगे। – Narek

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