2011-08-09 13 views
5

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

उत्तर

6

यह निर्भर करता है कि हम के बारे में क्या बात कर रहे हैं:

  • लक्षण कक्षाओं के लिए (कोई डेटा) यह ठीक है खाली बेस से लाभ प्राप्त करने private विरासत (रचना के स्थान पर प्रयोग के लिए (std::unary_function मन में आता है)
  • अनुकूलन) यह भी ठीक है

समस्या तब होती है जब आप इस तरह के एक व्युत्पन्न वस्तु का इलाज शुरू करते हैं, इस बेस क्लास को पॉलिमॉर्फिक रूप से wrt। यदि आप कभी ऐसी स्थिति प्राप्त करते हैं, तो यह निश्चित कोड गंध है।

नोट: यहां तक ​​कि जब ऊपर ठीक के रूप में नोट किया गया है, तब भी आप कक्षा को बहुरूप रूप से उपयोग करने की क्षमता प्रदान कर रहे हैं, और इस प्रकार आप सूक्ष्म बगों के लिए स्वयं को बेनकाब करते हैं।

+0

पॉलिमॉर्फिक उपयोग के बारे में अच्छा बिंदु संभव है - यद्यपि, यदि आपकी कक्षा को उचित रूप से परिभाषित किया गया है, तो उपयोगकर्ता को इसकी बाधा डालने के लिए अतिरिक्त मील नहीं जाने की ज़िम्मेदारी है। –

+1

@ केन: समस्या इस उत्तरदायित्व के बारे में है। यहां तक ​​कि अगर अनपेक्षित, एक उपयोगकर्ता * गड़बड़ कर सकता है और कक्षा polymorphically का उपयोग कर सकते हैं। अनुमोदित, दोनों मामलों में यह असंभव है। पूर्व में क्योंकि लक्षणों में गैर स्थैतिक विधियां नहीं होती हैं, यह बेकार है और बाद में 'निजी' वर्ग और दोस्तों के तरीकों की त्रुटि संभावना को प्रतिबंधित करती है। फिर भी, ऐसा हो सकता है। समस्या (बड़े पैमाने पर) एक गायब विशेषता है: हम * प्रतिनिधिमंडल * यहां * विरासत * नहीं चाहते हैं। –

0

सी ++ में आभासी तरीकों के बिना विरासत कोड पुन: उपयोग से अधिक कुछ नहीं है। मैं पॉलिमॉर्फिज्म के बिना विरासत के बारे में नहीं सोच सकता।

2

कोड पुन: उपयोग के लिए कक्षा से प्राप्त करना हमेशा वैध विकल्प होता है।

कभी-कभी, हम पॉलिमॉर्फिक व्यवहार की तलाश नहीं कर रहे हैं। यह ठीक है - एक कारण है कि हमारे पास वह विकल्प है। यदि यह मामला है, तो, इसके बजाय निजी विरासत का उपयोग करने पर विचार करें - यदि आपकी कक्षा पॉलिमॉर्फिक नहीं है, तो किसी के लिए इसे polymorphically उपयोग करने का प्रयास करने का कोई कारण नहीं है।

+2

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

+0

@Matthieu: एक वैध तर्क, हालांकि अभी भी बहस योग्य है। यह सच है कि इसे निश्चित रूप से ध्यान देने की आवश्यकता है, साथ ही साथ उपयोगकर्ता के अंत में ज़िम्मेदारी भी चाहिए। मैं इस बात से सहमत हूं कि संरचना * आमतौर पर * बेहतर है, लेकिन निजी विरासत अभी भी एक विकल्प है (यद्यपि, सही तरीके से उपयोग करने के लिए और अधिक मुश्किल)। –

+2

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

0

यहाँ (ध्यान दें संरक्षित नाशक) नीतियों में फर्क पड़ता व्यवहार करने के लिए एक ठीक उदाहरण है,:

struct some_policy 
{ 
    // Some non-virtual interface here 
protected: 
    ~some_policy() { ... } 

private: 
    // Some state here 
}; 

struct some_class : some_policy, some_other_policy { ... }; 

एक और ठीक है उदाहरण के लिए, टेम्पलेट में कोड बचते हैं करने के लिए। संरक्षित विनाशक पर ध्यान दें:

struct base_vector 
{ 
    // Put everything which doesn't depend 
    // on a template parameter here 

protected: 
    ~base_vector() { ... } 
}; 

template <typename T> 
struct vector : base_vector 
{ ... }; 

एक और उदाहरण, जिसे सीआरटीपी कहा जाता है। संरक्षित विनाशक पर ध्यान दें:

template <typename Base> 
struct some_concept 
{ 
    void do_something { static_cast<Base*>(this)->do_some_other_thing(); } 

protected: 
    ~some_concept() { ... } 
}; 

struct some_class : some_concept<some_class> { ... }; 

एक और उदाहरण, जिसे खाली बेस अनुकूलन कहा जाता है। वास्तव में विरासत प्रति से नहीं है, क्योंकि यह बेस क्लास (जो एक निजी सदस्य के रूप में कार्य करता है) के लिए some_class में कोई स्थान आरक्षित करने की अनुमति देने के लिए अधिक चाल है।

template <typename T> 
struct some_state_which_can_be_empty { ... }; 

template <typename T> 
struct some_class : private some_state_which_can_be_empty<T> { ... }; 

अंगूठे के नियम के रूप में, आपके द्वारा प्राप्त कक्षाओं में वर्चुअल या संरक्षित विनाशक होना चाहिए।

+0

मुझे संबंधित 'सार्वजनिक' विरासत मिलती है। –

+0

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

+0

@Matthieu: कोड ब्लोट और नीति उदाहरण में आमतौर पर कुछ गैर-छोटे सार्वजनिक इंटरफ़ेस होते हैं। यदि आप उन्हें सदस्य बनाते हैं, तो आपको हाथ से रैपर लिखना होगा। जेनेरिक कोड और सी ++ 03 में बोझिल (सी ++ 0x और सही अग्रेषण के साथ आसान)। –

0

सी ++ मानक पुस्तकालय में कुछ कक्षाओं ने सदस्यों को संरक्षित किया है (जो व्युत्पन्न वर्ग के लिए केवल सार्थक हैं) लेकिन कोई वर्चुअल सदस्य फ़ंक्शन नहीं है। यानी, वे वर्चुअल के बिना व्युत्पन्न के लिए डिज़ाइन किए गए हैं। यह साबित करता है कि वर्चुअल के बिना कक्षा से प्राप्त होने के लिए यह आमतौर पर खराब डिज़ाइन होना चाहिए।

चीयर्स & एचएचटी।,

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