राइट-पूर्ण यहां पुनः लिखें, और बहुत आसान है।
मैं s3rius से सहमत हूं कि आपको अभी भी std :: vector का उपयोग करना चाहिए। आप का उपयोग आप बिल्लियों भंडारण कर रहे हैं आदर्श रूप में करता है, तो चाहता हूँ ...
std::vector<Cat>
और यदि आप कुत्तों के भंडारण कर रहे हैं, आप चाहते हैं ...
std::vector<Dog>
हालांकि, अगर आप रन-टाइम की जरूरत है पॉलिमॉर्फिज्म चुनने के लिए कि आप किस मामले से निपट रहे हैं।
रणनीति डिजाइन पैटर्न का एक तरीका है (या प्रेरित है)। अपने इंटरफेस के लिए उन वैक्टरों के लिए बेस क्लास को परिभाषित करें, और उस टेम्पलेट क्लास को उस इंटरफ़ेस को कार्यान्वित करें जिसमें वेक्टर शामिल है।
class Animals_IF
{
public:
virtual int size() const = 0;
};
template<typename T> class Animals_Vector
{
private:
std::vector<T> store;
public:
int size() const;
};
template<typename T> int Animals_Vector<T>::size() const
{
return store.size();
}
यहां मुद्दा यह है कि इंटरफ़ेस Cat
या Dog
उल्लेख नहीं कर सकते क्योंकि यह विशेष प्रकार, निश्चित रूप से है, जिसके कारण मैं size
ऊपर के उदाहरण विधि के रूप में चुना है पता नहीं है।
एक समाधान संभावित प्रकारों के boost::variant
का उपयोग करके मूल्यों को पारित करना है, इसलिए प्रत्येक रणनीति/रैपर कक्षाएं यह जांच सकती हैं कि उन्हें प्राप्त होने वाले मूल्यों का उपयोग करने से पहले सही प्रकार हैं। संस्करण में रैपिंग/अनैपिंग मानों को टेम्पलेट विधियों द्वारा (गैर-टेम्पलेट) बेस क्लास में संभाला जा सकता है।
ऐसे मामलों में जहां सभी लपेटने और अनचाहे अक्षम हो जाते हैं, आपको यह निर्धारित करना होगा कि आप किस मामले से निपट रहे हैं, फिर सही रणनीति/रैपर प्रकार (आधार वर्ग नहीं) के माध्यम से कॉल करें। ऐसा करने के लिए, सभी रणनीति/रैपर मामलों का एक बढ़ावा :: संस्करण है। इससे आपको पॉइंटर-टू-बेस-क्लास भी नहीं मिलती है। वास्तव में, कक्षा में पॉइंटर-टू-बेस-क्लास और boost::variant
दोनों को लपेटें (जहां आवश्यक हो वहां टेम्पलेट विधियों के साथ)।
class Animals_IF
{
public:
typedef boost::variant<Cat,Dog> Animal;
virtual int size() const = 0;
template<typename T> void slow_push (const T &p)
{
push_ (Animal (p));
}
private:
virtual void slow_push_ (const Animal &p) = 0;
};
template<typename T> class Animals_Vector
{
public:
int size() const;
void fast_push (const T &p);
private:
std::vector<T> store;
void slow_push_ (const Animal &p);
};
template<typename T> int Animals_Vector<T>::size() const
{
return store.size();
}
template<typename T> void Animals_Vector<T>::fast_push (const T &p)
{
store.push (p);
}
template<typename T> void Animals_Vector<T>::slow_push_ (const Animal &p)
{
const T* item = boost::get<T> (&p);
if (T) store.push (*item);
// else throw?
}
class Animals
{
public:
int size() const
{
// null check needed?
return ptr->size();
}
template<typename T> void slow_push (const T &p)
{
// null check needed?
ptr->slow_push (p);
}
template<typename T> void fast_push (const T &p)
{
Animals_Vector<T> *lptr = boost::get<T> (&store);
if (lptr) lptr->fast_push (p);
// else throw?
}
private:
Animals_IF* ptr;
boost::variant<Animals_Vector<Cat>,Animals_Vector<Dog>> store;
};
कुछ भी नहीं है कि साझा इंटरफ़ेस वास्तव में प्रदान कर सकते हैं अगर कोई (क्योंकि हर विधि मान पास करने की जरूरत है, और रैपिंग/वेरिएंट के रूप में unwrapping अस्वीकार्य है) पूरी रणनीति बात अनावश्यक है। बस अलग-अलग std :: वेक्टर प्रकारों का एक बढ़ावा :: संस्करण है।
इसके अलावा, fast_push
उपरोक्त नहीं होगा क्योंकि push
लाभ के लिए बहुत आसान है - विचार यह है कि दृष्टिकोण जटिल तरीकों के लिए तेज़ है जो बार-बार रन-टाइम प्रकार की जांच से बचने से बचा सकता है, ऊपर सामने।
बीटीडब्ल्यू - अच्छा सवाल।
क्या यह कोई समझ में आता है "मेरे पास एक एकल प्रकार का संग्रह है जिसका प्रकार केवल रनटाइम पर जाना जाता है"? मेरी उम्र हो सकती है लेकिन यह –
नहीं है शायद उसका अर्थ भिन्न प्रकार का संग्रह है? ऐसा लगता है कि आप विकल्प और व्यापार बंद जानते हैं। आपको बस यह तय करने की ज़रूरत है कि यह आपके लिए और अधिक महत्वपूर्ण है। – goji
@EdHeal: मुझे लगता है कि इसका मतलब है कि कंटेनर में मान एकरूप प्रकार के हैं, लेकिन उस प्रकार संकलन समय पर ज्ञात नहीं है। विषम प्रकार के कंटेनर में इसे तुलना करें, जो अधिक शक्तिशाली है लेकिन इसकी आवश्यकता नहीं है। –