c++ - आप std:: वेक्टर से उत्तराधिकारी नहीं होंगे




oop inheritance (8)

ठीक है, यह स्वीकार करना वास्तव में मुश्किल है, लेकिन इस समय std::vector से उत्तराधिकारी होने के लिए मेरे पास एक मजबूत प्रलोभन है।

मुझे वेक्टर के लिए लगभग 10 अनुकूलित एल्गोरिदम चाहिए और मैं उन्हें वेक्टर के सीधे सदस्य बनना चाहता हूं। लेकिन स्वाभाविक रूप से मैं बाकी std::vector इंटरफ़ेस भी रखना चाहता हूं। खैर, मेरा पहला विचार, कानून-पालन करने वाले नागरिक के रूप में, MyVector क्लास में std::vector सदस्य होना था। लेकिन फिर मुझे सभी std :: वेक्टर के इंटरफेस को मैन्युअल रूप से पुनर्निर्मित करना होगा। टाइप करने के लिए बहुत कुछ। इसके बाद, मैंने निजी विरासत के बारे में सोचा, ताकि विधियों को पुनर्निर्मित करने के बजाय मैं सार्वजनिक अनुभाग में using std::vector::member का using std::vector::member एक गुच्छा लिखूंगा। यह वास्तव में भी थकाऊ है।

और यहां मैं हूं, मुझे सच में लगता है कि मैं आसानी से std::vector से सार्वजनिक रूप से वारिस कर सकता हूं, लेकिन दस्तावेज़ीकरण में एक चेतावनी प्रदान करता हूं कि इस वर्ग को पॉलिमॉर्फिक रूप से उपयोग नहीं किया जाना चाहिए। मुझे लगता है कि ज्यादातर डेवलपर्स यह समझने के लिए पर्याप्त सक्षम हैं कि इसका उपयोग पॉलिमॉर्फिक रूप से किसी भी तरह से नहीं किया जाना चाहिए।

क्या मेरा निर्णय बिल्कुल अन्यायपूर्ण है? यदि हां, तो क्यों? क्या आप एक विकल्प प्रदान कर सकते हैं जिसमें अतिरिक्त सदस्य वास्तव में सदस्य होंगे लेकिन वेक्टर के सभी इंटरफ़ेस को पुनः टाइप करने में शामिल नहीं होंगे? मुझे शक है, लेकिन यदि आप कर सकते हैं, तो मैं बस खुश रहूंगा।

इसके अलावा, इस तथ्य के अलावा कि कुछ बेवकूफ कुछ लिख सकते हैं

std::vector<int>* p  = new MyVector

क्या MyVector का उपयोग करने में कोई अन्य यथार्थवादी खतरे है? यथार्थवादी कहकर मैं चीजों को त्यागने की तरह चीजें छोड़ देता हूं जो वेक्टर को पॉइंटर लेता है ...

खैर, मैंने अपना मामला बताया है। मैंने पाप किया है। अब मुझे माफ करने के लिए आप पर निर्भर है या नहीं :)


आप क्या हासिल करने की उम्मीद कर रहे हैं? बस कुछ कार्यक्षमता प्रदान करते हैं?

ऐसा करने के लिए C ++ बेवकूफ तरीका केवल कुछ मुक्त फ़ंक्शंस लिखना है जो कार्यक्षमता को लागू करते हैं। संभावना है कि आपको वास्तव में एक std :: वेक्टर की आवश्यकता नहीं है, विशेष रूप से आपके द्वारा कार्यान्वित की जा रही कार्यक्षमता के लिए, जिसका अर्थ है कि आप वास्तव में std :: vector से प्राप्त करने का प्रयास करके पुन: प्रयोज्यता पर हार रहे हैं।

मैं दृढ़ता से आपको मानक पुस्तकालय और शीर्षकों को देखने की सलाह देता हूं, और इस बात पर ध्यान देता हूं कि वे कैसे काम करते हैं।


दरअसल, std::vector की सार्वजनिक विरासत में कुछ भी गलत नहीं है। अगर आपको इसकी ज़रूरत है, तो बस ऐसा करें।

मैं ऐसा करने का सुझाव दूंगा कि केवल तभी यह जरूरी है। केवल तभी यदि आप मुफ्त कार्यों के साथ जो भी चाहते हैं वह नहीं कर सकते (उदाहरण के लिए कुछ राज्य रखना चाहिए)।

समस्या यह है कि MyVector एक नई इकाई है। इसका मतलब है कि एक नया सी ++ डेवलपर पता होना चाहिए कि इसका उपयोग करने से पहले यह क्या है। std::vector और MyVector बीच क्या अंतर है? यहां और वहां उपयोग करने के लिए कौन सा बेहतर है? अगर मुझे std::vector को MyVector स्थानांतरित करने की आवश्यकता है तो क्या होगा? क्या मैं बस swap() उपयोग कर सकता हूं या नहीं?

बेहतर दिखने के लिए कुछ बनाने के लिए नई इकाइयों का उत्पादन न करें। ये संस्थाएं (विशेष रूप से, इस तरह के आम) वैक्यूम में नहीं रहेंगे। वे लगातार बढ़ी हुई एन्ट्रॉपी के साथ मिश्रित वातावरण में रहेंगे।


मुझे हाल ही में std::vector से विरासत में मिला है, और यह बहुत उपयोगी पाया गया है और अब तक मुझे इसके साथ कोई समस्या नहीं हुई है।

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

दृष्टिकोण के साथ मैं देख सकता हूं कि एकमात्र समस्या गैर-आभासी विनाशक के साथ बहुत कुछ नहीं है, बल्कि कुछ अन्य विधियों, जिन्हें मैं ओवरलोड करना चाहता हूं, जैसे push_back() , resize() , insert() आदि निजी विरासत वास्तव में एक अच्छा विकल्प हो सकता है।

धन्यवाद!


यदि आप अच्छी सी ++ शैली का पालन करते हैं, तो वर्चुअल फ़ंक्शन की अनुपस्थिति समस्या नहीं है, लेकिन स्लाइसिंग ( https://.com/a/14461532/877329 )

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

void foo(SomeType* obj)
    {
    if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
        {
        obj->doStuff();
        }
    delete obj;
    }

class SpecialSomeType:public SomeType
    {
    // whatever 
    };

int main()
    {
    SpecialSomeType obj;
    doStuff(&obj); //Will crash here. But caller does not know that
//  ...
    }

इसके विपरीत, यह हमेशा काम करेगा (वर्चुअल विनाशक के साथ या बिना):

void foo(SomeType* obj)
    {
    if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
        {
        obj->doStuff();
        }
    }

class SpecialSomeType:public SomeType
    {
    // whatever 
    };

int main()
    {
    SpecialSomeType obj;
    doStuff(&obj);
//  The correct destructor *will* be called here.
    }

यदि वस्तु किसी फैक्ट्री द्वारा बनाई गई है, तो फैक्ट्री को एक काम करने वाले डिलीटर को पॉइंटर वापस करना चाहिए, जिसे delete बजाए इस्तेमाल किया जाना चाहिए, क्योंकि फैक्ट्री अपने ही ढेर का उपयोग कर सकती है। कॉलर इसे share_ptr या unique_ptr का रूप प्राप्त कर सकता है। संक्षेप में, कुछ भी delete जो आपको सीधे new से नहीं मिला था।


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

लेकिन सिद्धांत में: सी ++ 0x एफसीडी में [expr.delete] से: पहले विकल्प (ऑब्जेक्ट हटाएं) में, यदि ऑब्जेक्ट का स्थिर प्रकार हटाया जाना है तो गतिशील प्रकार से अलग है, स्थिर प्रकार एक होगा वस्तु के गतिशील प्रकार के आधार वर्ग को हटाया जाना चाहिए और स्थैतिक प्रकार में आभासी विनाशक होगा या व्यवहार अपरिभाषित है।

लेकिन आप समस्याओं के बिना std :: वेक्टर से निजी रूप से प्राप्त कर सकते हैं। मैंने निम्नलिखित पैटर्न का उपयोग किया है:

class PointVector : private std::vector<PointType>
{
    typedef std::vector<PointType> Vector;
    ...
    using Vector::at;
    using Vector::clear;
    using Vector::iterator;
    using Vector::const_iterator;
    using Vector::begin;
    using Vector::end;
    using Vector::cbegin;
    using Vector::cend;
    using Vector::crbegin;
    using Vector::crend;
    using Vector::empty;
    using Vector::size;
    using Vector::reserve;
    using Vector::operator[];
    using Vector::assign;
    using Vector::insert;
    using Vector::erase;
    using Vector::front;
    using Vector::back;
    using Vector::push_back;
    using Vector::pop_back;
    using Vector::resize;
    ...

संपूर्ण एसटीएल इस तरह से डिजाइन किया गया था कि एल्गोरिदम और कंटेनर अलग हैं

इसने विभिन्न प्रकार के इटरेटर की अवधारणा को जन्म दिया: कॉन्स इटरेटर्स, यादृच्छिक अभिगम इटरेटर आदि।

इसलिए मैं आपको इस सम्मेलन को स्वीकार करने और अपने एल्गोरिदम को इस तरह से डिजाइन करने की सलाह देता हूं कि वे इस बात पर परवाह नहीं करेंगे कि वे किस कंटेनर पर काम कर रहे हैं - और उन्हें केवल एक विशिष्ट प्रकार के इटरेटर की आवश्यकता होगी जिसे उन्हें करने की आवश्यकता होगी संचालन।

साथ ही, मुझे जेफ अटवुड द्वारा आपको कुछ अच्छी टिप्पणियों पर रीडायरेक्ट करने दें।


हां यह तब तक सुरक्षित है जब तक आप सावधान रहें जो सुरक्षित नहीं हैं ... मुझे नहीं लगता कि मैंने कभी भी किसी को वेक्टर का उपयोग करने के लिए देखा है, इसलिए अभ्यास में आप ठीक होंगे। हालांकि, यह सी ++ में सामान्य मुहावरे नहीं है ....

क्या आप एल्गोरिदम क्या हैं इस बारे में अधिक जानकारी दे सकते हैं?

कभी-कभी आप डिज़ाइन के साथ एक सड़क पर उतरते हैं और फिर आपके द्वारा उठाए गए अन्य पथ नहीं देख सकते हैं - तथ्य यह है कि आप 10 नए एल्गोरिदम के साथ सदिश की आवश्यकता के लिए दावा करते हैं कि मेरे लिए अलार्म घंटी बजती है - क्या वास्तव में 10 सामान्य उद्देश्य हैं एल्गोरिदम जो एक वेक्टर लागू कर सकता है, या आप एक ऑब्जेक्ट बनाने की कोशिश कर रहे हैं जो एक सामान्य उद्देश्य वेक्टर है और जिसमें अनुप्रयोग विशिष्ट कार्य शामिल हैं?

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


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

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





vector