2013-03-20 11 views
13

मेरे पास मूल श्रेणी होने के साथ विरासत श्रृंखला है। मैं एक क्लास टेम्पलेट लिखने में सक्षम होना चाहता हूं जो आधार को प्राप्त करता है और संभवतः एक और बेस-व्युत्पन्न कक्षा संभव है। मैं आभासी विरासत का उपयोग कर सकता था, लेकिन मुझे एक और समाधान मिला। मैं जानना चाहता हूं कि यह सामान्य/काफी/वैध वर्ग डिज़ाइन है:सी ++ ओओ डिज़ाइन: टेम्पलेट पैरामीटर का विरासत

एक क्लास टेम्पलेट लिखें जिसमें टेम्पलेट पैरामीटर वह वर्ग है जो इसे प्राप्त करता है, यानी इसे बेस या बेस-व्युत्पन्न क्लास होना चाहिए। कन्स्ट्रक्टर में मैं वास्तव में यह सुनिश्चित करने के लिए स्थिर आवेषण का उपयोग कर सकता हूं कि उपयोगकर्ता ने किसी भी अवैध वर्ग को टेम्पलेट पैरामीटर के रूप में उपयोग नहीं किया है।

यदि यह काम करता है, तो मेरे पास कभी भी आभासी विरासत की समस्या नहीं होगी ... सवाल यह है कि ऐसा करना ठीक है। मैंने इसे अन्य परियोजनाओं में कभी नहीं देखा, इसलिए मैं इसका उपयोग करने से पहले सुनिश्चित करना चाहता हूं।

संपादित:

class Base 
{ 
}; 

class Derived : public Base 
{ 
}; 

template <Class TheBase> 
class MyDerived : public TheBase 
{ 
}; 

अब मैं Base या किसी Base व्युत्पन्न वर्ग, उदा का उपयोग कर सकते हैं: बस सुनिश्चित करें कि मैं तुम्हें भ्रमित न करें होने के लिए, यहाँ कुछ कोड है Derived, TheBase पैरामीटर के रूप में।

+5

क्या आप हमें कुछ कोड दिखा सकते हैं? मुझे लगता है कि यह बेहतर जवाब पाने में मदद करेगा। –

+1

ईमानदारी से ऐसा लगता है कि आप [उत्सुकता से आवर्ती टेम्पलेट पैटर्न (सीआरटीपी)] (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) का वर्णन कर रहे हैं। – WhozCraig

+2

"मुझे कभी वर्चुअल विरासत की समस्या नहीं होगी" ... क्या आपने कभी मर्फी के कानून के बारे में सुना है? :) –

उत्तर

10

बाद में संपादित करें: एक साल बाद, यहां मैं अपना उत्तर संशोधित कर रहा हूं। मैंने शुरुआत में गलती से कहा था कि पोस्ट ओपी पैटर्न सीआरटीपी था। यह सही नहीं है। यह वास्तव में एक मिश्रण है, कृपया सही स्पष्टीकरण के लिए पेज पर डैनियल महलर का उत्तर कम पढ़ें।

मूल: इस तरह के डिज़ाइन का उपयोग करना ठीक है। उदाहरण के लिए WTL इसका उपयोग करता है। इसका उपयोग Static Polymorphism को लागू करने के लिए किया जाता है और इसे Curiously recurring template pattern

+1

बिल्कुल सीआरटीपी नहीं, लेकिन अभी भी उपयोगी है। उदाहरण के लिए, बदलने योग्य इंटरफेस चुनने के लिए यह अच्छा है। – ThomasMcLeod

5

यहां एक अच्छा आदर्श वाक्य है: प्रकारों के लिए टेम्पलेटिंग का उपयोग करें, लेकिन व्यवहार के लिए विरासत का उपयोग करें।

इसे चिपकाएं। निश्चित रूप से बहुत कम कटौती/चालें हैं जिनका उपयोग आप काम पूरा करने के लिए कर सकते हैं, लेकिन लंबे समय तक इन खराब डिजाइन विकल्पों में सिरदर्द होगा। यदि आप इस तरह का उपयोग करना चाहते हैं, तो लाभ और दोषों का शोध करना सुनिश्चित करें।

अब, आपके प्रश्न पर वापस जाकर, जो आपने पूछा है वह करना संभव है: CRTP, और Static polymorphism देखें।

+1

+1 बहुत अच्छा बिंदु! – Walter

+1

-1। उस आदर्श वाक्य से हमारे पास कोई नीति-आधारित डिज़ाइन नहीं होगा। सब के बाद इतना अच्छा मुद्दा नहीं है। –

+0

यह नहीं कह रहा है कि 'इस तरह के डिजाइन का कभी भी उपयोग न करें', यह लोगों को उनके विकल्पों को फिर से सोचने के लिए प्रोत्साहित करना है। यह नीति डिजाइन जैसे अच्छी तरह से स्थापित डिजाइन प्रतिमानों के साथ करने के लिए नोटिस कर रहा है। आप पूरी तरह से बिंदु खो रहे हैं। – meyumer

7

यह ठीक है, जैसा कि ज़ेडिरियन बताते हैं। कारण यह काम करता है (सरलीकृत) यह है कि C++ में टेम्पलेट्स, सी # में जेनेरिक के विपरीत, संकलित समय हैं। यह मेरे लिए "यह एक टाइपिफ" कहने के लिए मुझे याद दिलाएगा और मुझे इसके लिए बहुत सारी फ्लाक मिल जाएगी, लेकिन चलो इसे सरल रखें और कहें कि यह था।

पर विचार करें:

class base { 
protected: 
    base() { }; 
    virtual ~base() { }; 
}; 

template<class T> 
class super : public T { 
}; 

और बाद में:

super<base> s; 

बिल्कुल ठीक। यह वास्तव में एक सुंदर निर्माण है। क्योंकि यह संकलित समय है, आप अपनी बेस क्लास चुन सकते हैं, जो कि कुछ डिज़ाइन मुहावरे बहुत अनुकूल हो सकते हैं।

+2

+1 मेरे से थोड़ा अधिक विस्तार में जाने के लिए। मैं जोड़ूंगा कि यह एक उपयोगी पैटर्न है जब आपको बेस क्लास के रूप में कुछ पुन: प्रयोज्य कोड लिखने की आवश्यकता होती है, लेकिन कुछ कोड कुछ प्रकार के व्युत्पन्न वर्गों के साथ काम करने में सक्षम नहीं होंगे। उस स्थिति में, आधार वर्ग में पैटर्न का उपयोग यह निर्धारित करने के लिए किया जा सकता है कि व्युत्पन्न प्रकार के गुण (जैसे std :: is_base_of) हैं और कुछ शर्तों को पूरा करते समय कुछ कोड सक्षम करते हैं। –

+1

उत्तर के लिए धन्यवाद! मैंने यह सुनिश्चित करने के लिए पोस्ट में कुछ कोड जोड़ा है कि मेरा वर्णन लोगों को भ्रमित नहीं करता है – cfa45ca55111016ee9269f0a52e771

18

यह एक वैध डिजाइन पैटर्न है। यह मिश्रित विरासत है, सीआरटीपी नहीं।मिक्सिन विरासत प्रोग्रामर द्वारा विरासत पदानुक्रम को मैन्युअल रूप से रैखिक रूप से रैखिक रूप से एकाधिक विरासत को अनुकरण करने का एक तरीका प्रदान करता है। टेम्पलेटेड कक्षाएं मिश्रण हैं। यदि आप एकाधिक मिक्सिन वाले वर्ग को विस्तारित करना चाहते हैं तो आपको Big<Friendly<Dog> > जैसी संरचना का क्रम तय करना होगा। सी ++ में मिक्सिन प्रोग्रामिंग को इस Dr Dobb's article में वर्णित किया गया है। मिक्सिन का उपयोग here वर्णित गोफ सजावट पैटर्न के स्थिर संस्करण को लागू करने के लिए किया जा सकता है। मिक्सिन सी ++ में एक सिमर भूमिका निभाते हैं जो स्केल & स्मॉलटाक में गुण (सी ++ लक्षण नहीं) खेलते हैं।

CRTP में यह है आधार वर्ग एक टेम्पलेट है कि:

template <class Param> 
class Base { ... }; 

class Derived : public Base<Derived> { ... }; 
+1

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

1

आपको क्या करने की कोशिश कर रहे हैं दो वर्गों जो एक आम आधार वर्ग हो सकता है से प्राप्त करना है, यह सही है? उस स्थिति में आप वर्चुअल विरासत समस्याओं के साथ सौदा करते हैं (यानी आपको वर्चुअल दोनों कक्षाओं में रुचि रखने वाले दोनों वर्गों के लिए बेस क्लास की विरासत घोषित करनी होगी)। कुछ रनटाइम समर्थन (2 vpointers और) के कारण यह केवल एक छोटा (संभावित महत्वहीन) ओवरहेड का कारण बनता है।

आपका कोड सीआरटीपी नहीं है (सीआरटीपी में बेस क्लास व्युत्पन्न कक्षा प्राप्त करने वाला एक टेम्पलेट है) और किसी भी तरह से डबल विरासत समस्या से छुटकारा पाने की कोशिश नहीं कर रहा है।

जहाँ तक मैं इसे देख सकता हूं आप या तो वर्चुअल विरासत स्वीकार कर सकते हैं और कम से कम ओवरहेड में आभासी कीवर्ड का उपयोग कर सकते हैं या आप अपने कोड को दोबारा कर सकते हैं।

मैं पूरी तरह से समझ नहीं पाया कि आप क्या करने की कोशिश कर रहे हैं, लेकिन यदि आप एक सामान्य आधार वर्ग के साथ दो अलग-अलग वर्गों से उत्तराधिकारी होने का प्रयास कर रहे हैं (वर्चुअल विरासत इस बारे में सब कुछ है) और किसी कारण से आप नहीं तो आप निम्नलिखित फैशन में CRTP का उपयोग कर सकते आभासी कीवर्ड का उपयोग करना चाहते हैं,:

#include <iostream> 
using namespace std; 

template<class Derived> 
class Base 
{ 
public: 
    void basefunc() { cout << "base here"<< endl; } 
    virtual void polyfunc() { cout << "base poly here"<< endl; } 
}; 

class Derived : public Base<Derived> 
{ 
public: 
    void derivedfunc() { cout << "derived here"<< endl; } 
    virtual void polyfunc() { cout << "derived poly here"<< endl; } 
}; 

class OtherDerived : public Base<OtherDerived> 
{ 
public: 
    void otherderivedfunc() { cout << "otherderived here"<< endl; } 
    virtual void polyfunc() { cout << "otherderived poly here"<< endl; } 
}; 

class InheritingFromBoth : public Derived, public OtherDerived 
{ 
public: 
    void inheritingfunc() { cout << "inheritingfromboth here" << endl; } 
    virtual void polyfunc() { cout << "inheritingfromboth poly here"<< endl; } 
}; 

int main() { 

    Derived obj; 
    OtherDerived obj2; 

    InheritingFromBoth *obj3 = new InheritingFromBoth(); 
    Derived *der = dynamic_cast<Derived*>(obj3); 
    der->polyfunc(); 
    OtherDerived *der2 = dynamic_cast<OtherDerived*>(obj3); 
    der2->polyfunc(); 

    Base<Derived>* bptr = dynamic_cast<Base<Derived>*>(obj3); 
    bptr->polyfunc(); 
    Base<OtherDerived>* bptr2 = dynamic_cast<Base<OtherDerived>*>(obj3); 
    bptr2->polyfunc(); 



    return 0; 
} 

आधार वर्ग आप विरासत अस्पष्टता से बच सकेंगे के दो अलग-अलग विविधताएं बनाने के द्वारा।

  • एक वर्ग बेस और एक से से विरासत:

    एक बहुत आसान, शायद क्लीनर, बेहतर समाधान यदि आप एक आधार है और एक ही समय में एक आधार-व्युत्पन्न वर्ग से विरासत का इरादा पीछा कर रहा है बेस-व्युत्पन्न वर्ग मुझे लगता है कि आप एक ही समय में बेस तरीकों और बेस व्युत्पन्न तरीकों का उपयोग करने में सक्षम होना चाहते हैं बनाता है ..

यदि आप संभावित नाम-छुपाकरने के लिए अपने वर्ग डिजाइनिंग में ध्यान देनाऔर केवल उन कार्यों के व्यवहार को "कस्टमाइज़" करने के लिए बहुरूपता का उपयोग करें जिन्हें आप वास्तव में अलग करना चाहते हैं (और जिसे कास्ट-नियंत्रित किया जा सकता है), फिर Base -> Derived -> YourClass के रूप में एक स्वच्छ पदानुक्रम अंततः आपकी समस्याओं का समाधान कर सकता है।

आपके विशिष्ट मामले में आपका दृष्टिकोण काम करता है, जैसा कि अन्य लोगों द्वारा नोट किया गया है, लेकिन मुझे नहीं लगता कि आपके डबल विरासत मुद्दे को प्रभावी ढंग से हल कर सकते हैं। आखिर में केवल विशिष्ट डिजाइन केस कम-बुरा समाधान का कारण बन सकता है।

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