2009-03-06 12 views
7

वर्चुअल फ़ंक्शंस और सी ++ विरासत तंत्र का उपयोग करके टेम्पलेट्स और बूस्ट अवधारणाओं जैसे कुछ बनाम संबंधों के बीच संबंध क्या है?सी ++ अवधारणा जांच बनाम विरासत

ऐसा लगता है कि संभव है कि काफी संभव है। अर्थात्, यह दृष्टिकोण के साथ बहुलक व्यवहार प्राप्त करना संभव प्रतीत होता है। तो, दूसरे के ऊपर एक का पक्ष लेने का अर्थ कब होता है?

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

तो, एक ओर, मैं कंटेनरों को polymorphicly व्यवहार करना चाहता हूँ। दूसरी तरफ, अगर मुझे कुछ एल्गोरिदम सही ढंग से कार्यान्वित करना है तो मुझे अभी भी अवधारणाओं का उपयोग करना होगा। एक जूनियर डेवलपर क्या करना है?

उत्तर

6

मैं अवधारणाओं के बारे में सोचता हूं कि मेटा-इंटरफ़ेस का एक प्रकार है। वे अपनी क्षमताओं के बाद प्रकारों को वर्गीकृत करते हैं। अगला सी ++ संस्करण देशी अवधारणाओं की आपूर्ति करता है। मुझे तब तक यह समझ में नहीं आया जब तक कि मैं सी ++ 1x की अवधारणाओं में नहीं आया और कैसे वे अलग-अलग असंबद्ध प्रकारों को एक साथ रखने की अनुमति देते हैं। कल्पना करें कि आपके पास Range इंटरफ़ेस है। आप इसे दो तरीकों से मॉडल कर सकते हैं।

class Range { 
    virtual Iterator * begin() = 0; 
    virtual Iterator * end() = 0; 

    virtual size_t size() = 0; 
}; 
बेशक

, हर वर्ग कि निकला है कि रेंज इंटरफ़ेस लागू करता है और अपने कार्यों के साथ इस्तेमाल किया जा सकता से: एक एक उप प्रकार संबंध है। लेकिन अब आप देखते हैं कि यह सीमित है। एक सरणी के बारे में क्या? यह भी एक रेंज है!

T t[N]; 

begin() => t 
end() => t + size() 
size() => N 

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

auto concept Range<typename T> { 
    typename iterator; 
    iterator T::begin(); 
    iterator T::end(); 
    size_t T::size(); 
} 

अब, आप कुछ प्रकार जो अगर T उचित सदस्य कार्य पूरा किया जा सकता का समर्थन किया संचालन के बारे में कुछ कहना। आपकी लाइब्रेरी में, आप जेनेरिक फ़ंक्शन लिखेंगे। यह आपको इतने लंबे समय के रूप में यह आवश्यक कार्रवाई का समर्थन करता है किसी भी प्रकार स्वीकार की अनुमति देता है:

template<Range R> 
void assign(R const& r) { 
    ... iterate from r.begin() to r.end(). 
} 

यह प्रतिस्थापन का एक बड़ा तरह है। कोई भी प्रकार उस बिल को फिट करेगा जो अवधारणा का पालन करता है, न केवल उन प्रकारों जो सक्रिय रूप से कुछ इंटरफ़ेस को कार्यान्वित करते हैं। अगला सी ++ मानक आगे जाता है: यह Container अवधारणा को परिभाषित करता है जो सादे सरणी द्वारा फिट किया जाएगा (अवधारणा मानचित्र को कैल्चर किया गया है जो परिभाषित करता है कि कुछ प्रकार कुछ अवधारणा कैसे फिट बैठता है) और अन्य, मौजूदा मानक कंटेनर।

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

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

// tag types for the comparator cagetory 
struct not_comparable { }; 
struct basic_comparable : not_comparable { }; 

template<typename T> 
class MyVector : public BasicContainer<T> { 
    typedef basic_comparable comparator_kind; 
}; 

/* Container concept */ 
T::comparator_kind: comparator category 

यह यह करने के लिए एक उचित आसान तरीका वास्तव में है,। अब आप एक फ़ंक्शन कॉल कर सकते हैं और यह सही कार्यान्वयन के लिए आगे बढ़ेगा।

template<typename Container> 
void takesAdvantage(Container const& c) { 
    takesAdvantageOfCompare(c, typename Container::comparator_kind()); 
} 

// implementation for basic_comparable containers 
template<typename Container> 
void takesAdvantage(Container const& c, basic_comparable) { 
    ... 
} 

// implementation for not_comparable containers 
template<typename Container> 
void takesAdvantage(Container const& c, not_comparable) { 
    ... 
} 

वास्तव में विभिन्न तकनीकें हैं जिनका उपयोग इसे लागू करने के लिए किया जा सकता है। एक और तरीका हर बार विभिन्न कार्यान्वयन को सक्षम या अक्षम करने के लिए boost::enable_if का उपयोग करना है।

+0

सी ++ 1 एक्स? क्या इसका मतलब है कि उन्होंने इस दशक में नए मानक को छोड़ दिया है या आप भविष्य में सी ++ विकास के बारे में बात कर रहे हैं? – jpalecek

+0

http://www.research.att.com/~bs/C++0xFAQ.html#concepts – jmucchiello

+0

jpalecek, वे इसे 2010 में रिलीज़ करना चाहते हैं। मेरे पास इसे C++ 1x कहने की आदत है :) –

0

यदि संकलन समय पर कोई निर्णय लिया जा सकता है, तो टेम्पलेट का उपयोग करें। अन्यथा विरासत और आभासी कार्यों का उपयोग करें।

1

हां, दोनों तंत्र के साथ बहुलक व्यवहार संभव है। वास्तव में, दोनों पॉलिमॉर्फिज्म भी हैं।

वर्चुअल फ़ंक्शंस आपको गतिशील बहुरूपता देता है (क्योंकि यह रनटाइम पर तय होता है), जबकि टेम्पलेट्स आपको स्थिर पॉलीमोर्फिज्म देते हैं (संकलन समय पर सब कुछ तय किया जाता है)।

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

(बेशक एक या दूसरे को प्राथमिकता देने के अन्य कारण भी हो सकते हैं। विशेष रूप से, टेम्पलेट्स को आपको हेडर फाइलों में बहुत से कोड को स्थानांतरित करने की आवश्यकता होती है जो समस्या हो सकती है या नहीं, और संकलन की गति को भुगतना पड़ता है, जो भी या एक समस्या नहीं हो सकता है।)

0

इस विशेष मामले के आप की तरह

template<typename T> 
class ContainerBase{}; 

template<typename T> 
class ContainerDerived : public ContainerBase<T> {}; 

कुछ कर सकते हैं के बाद से प्रत्येक 'कंटेनर' प्रकार प्रत्येक टेम्पलेट प्रकार के लिए अद्वितीय है, वहाँ के लिए कोई कारण सदस्य कार्यों है प्रत्येक कंटेनर प्रकार टेम्पलेट प्रकार के लक्षणों पर विशेष नहीं किया जा सका।

0

संकलन समय और रन-टाइम बहुरूपता निम्नलिखित कोड पर विचार के बीच अंतर का एक सरल उदाहरण के रूप में:

template<typename tType> 
struct compileTimePolymorphism 
{ }; 

// compile time polymorphism, 
// you can describe a behavior on some object type 
// through the template, but you cannot interchange 
// the templates 
compileTimePolymorphism<int> l_intTemplate; 
compileTimePolymorphism<float> l_floatTemplate; 
compileTimePolymorphism *l_templatePointer; // ???? impossible 

struct A {}; 
struct B : public A{}; 
struct C : public A{}; 

// runtime polymorphism 
// you can interchange objects of different type 
// by treating them like the parent 
B l_B; 
C l_C: 
A *l_A = &l_B; 
l_A = &l_C; 

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

दो एक टेम्पलेट जो बहुरूपी है परिभाषित करते हुए जोड़ा जा सकता है:

template<typename tType> 
struct myContainer : public tType 
{}; 

सवाल तो वह जगह है जहाँ अपने कंटेनर के व्यवहार (क्रम बहुरूपता) को बदलने की जरूरत है, और जहां व्यवहार वस्तुओं पर निर्भर करता है इसमें शामिल है (संकलन समय polymorphism)।