2012-03-03 17 views
11

मैंने सुना है कि बहुत से लोग कहते हैं कि typeid का कोई भी उपयोग खराब डिज़ाइन है, फिर भी मेरे लिए ऐसा लगता है कि यह बहुत अच्छी उपयोगिता प्रदान करता है।टाइपिड कीवर्ड खराब डिज़ाइन का उपयोग क्यों किया जाता है?

  1. जब (और क्यों) typeid "खराब डिज़ाइन" का उपयोग होता है?
  2. typeid का उपयोग कब स्वीकार्य है?
  3. जब यह स्वीकार्य नहीं है, लेकिन आपको अभी भी कुछ समान की आवश्यकता है, तो क्या कोई विकल्प होगा जिसमें अच्छी डिजाइन होगी?
+7

यह कहां कहता है कि यह खराब डिजाइन है? –

+0

@ सेठ कार्नेगी मैंने कुछ लोगों को एसओ पर यह कहते हुए सुना है, और इसे एक पुस्तक में भी पढ़ा है जो जांच प्रकार खराब डिजाइन है, फिर भी कोई कारण नहीं दिया गया है। – xcrypt

+3

कि उन्होंने कोई कारण नहीं दिया है शायद उनके दावों की वैधता का संकेत है। कुछ लोग कहते हैं कि यदि आप बहुत से प्रकार की जांच कर रहे हैं, तो आपको अपने कोड को पॉलिमॉर्फिक फ़ंक्शन कॉल में दोबारा प्रतिक्रिया देना चाहिए। उदाहरण के लिए, 'if (typeid (a) == atype) करने के बजाय doa(); अन्यथा अगर (टाइपिड (ए) == बिट प्रकार) डॉब(); अन्यथा अगर (टाइपिड (ए) == सीटीपीई) दस्तावेज़(); 'आप केवल' a-> doafunc(); 'कर सकते हैं और उचित वर्चुअल फ़ंक्शन को' ए' के रनटाइम प्रकार के लिए बुलाया जाएगा। –

उत्तर

18

समस्या typeid के साथ नहीं है।

PolymorphicType *pType = ...; 
if(typeid(*pType) == typeid(Derived1)) 
    pType->Func1(); 
else if(typeid(*pType) == typeid(Derived2)) 
    pType->Func2(); 
else if(typeid(*pType) == typeid(Derived3)) 
    pType->Func3(); 

यह है कि हम क्या कॉल "वास्तव में बेवकूफ" है: समस्या यह है कि typeid देखकर यह लिखने के लिए प्रोत्साहित करते हैं है। यह एक वर्चुअल फ़ंक्शन कॉल है जो कम से कम उचित तरीके से संभव है। typeid में dynamic_cast और virtual फ़ंक्शंस को प्रतिस्थापित करने के लिए उपयोग किए जाने पर दुरुपयोग की संभावना है।

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

typeidकी अंतिम रिज़ॉर्ट की बहुलक प्रकार की कटौती विधि है।

क्या typeid का सभी उपयोग गलत है? बिलकूल नही। boost::any इसके बिना संभव नहीं होगा। वैसे यह संभव होगा, लेकिन यह void* से अधिक सुरक्षित नहीं होगा। typeid क्या टाइप-सुरक्षित boost::any प्रकार मिटा सकता है। इसके अन्य वैध उपयोग भी हैं।

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

टाइपिंग धीमा है?

सामान्य तौर पर, typeid कॉल करने के लिए मुख्य कारण या तो (boost::any के रूप में) टेम्प्लेटेड कोड या जब आप एक बहुरूपी प्रकार की उम्मीद कर रहे है। यदि प्रकार स्थिर रूप से निर्धारित होता है (यानी: एक टाइपनाम या गैर-पॉलीमोर्फिक प्रकार का मान दिया जाता है), तो आप संकलन-समय पर इसे करने की उम्मीद कर सकते हैं।

यह पॉलीमोर्फिक मान है जिसके बारे में आपको चिंतित होना चाहिए। मैंने एक प्रदर्शन परीक्षण देखा है जो दिखाता है कि कुछ typeid कार्यान्वयन वास्तव में कक्षा पदानुक्रम चलते हैं, इसलिए उनके लिए प्रकार ढूंढने में लगने वाला समय वास्तविक प्रकार और दिए गए प्रकार के बीच कक्षाओं की संख्या के समान होता है। प्रत्येक कार्यान्वयन अलग होगा, लेकिन यह एक बहुत अच्छा संकेत है कि शायद आपको इसे प्रदर्शन-महत्वपूर्ण कोड में नहीं डालना चाहिए।

+2

'टाइपिड (एक्स) .नाम()' डिबगिंग/लॉग स्टेटमेंट लिखने के लिए भी काफी आसान है। –

+0

क्या आप इतने दयालु होंगे कि 'बूस्ट :: कोई भी' टाइपिड 'का उपयोग करने के लिए एक लिंक प्रदान करने के लिए? –

+0

@BenVoigt: मुझे नहीं पता कि 'boost :: any' का स्रोत कोड ऑनलाइन है, लेकिन संस्करण 1.47 में 'boost/any.hpp' की पंक्ति 180 है। दरअसल, बस उस फाइल को खोजना इसके कई प्रयोग दिखाएगा। –

6

मुझे नहीं लगता कि कोई भी कहता है कि typeid का उपयोग स्वयं खराब डिजाइन है; बल्कि, आप जो सुनेंगे वह यह है कि typeid का उपयोग खराब डिजाइन के संकेत है। विचार यह है कि से Square को में उन वर्गों में अंतर करने वाले किसी तर्क को वर्चुअल फ़ंक्शन (पॉलिमॉर्फिज्म) द्वारा व्यक्त किया जाना चाहिए।

कहने की जरूरत नहीं है, यह एक पूर्ण नियम नहीं है।

+0

और प्रदर्शन के अनुसार, क्या कोई कारण हैं? प्रकार की जांच धीमी है? – xcrypt

+3

@xcrypt जब तक कि 'टाइपिड' का ऑपरेशन एक पॉलिमॉर्फिक प्रकार नहीं है, 'टाइपिड' संकलन समय पर किया जाता है। यदि ऑपरेंड एक पॉलिमॉर्फिक प्रकार है, तो यह कितना तेज़ या धीमा है इस पर निर्भर करता है कि संकलक लेखकों ने इसे कैसे कार्यान्वित किया। यदि उन्होंने प्रोग्राम को अपने प्रोग्राम का टेक्स्ट कंपनी कर्मचारी को भेजकर लागू किया है और उसे कक्षा के प्रकार को प्रोग्राम में वापस टाइप किया है, तो यह धीमा हो जाएगा। –

+0

@ सेठ कार्नेगी जो ऐसी चीज करेगा? : पी – xcrypt

4

यह बहुत बुरा है कि जिन्होंने आपको यह अच्छी सलाह दी है, वे इसके कारण नहीं दे सकते। इसका मतलब है कि वे cargo cult प्रोग्रामर सरल हैं।

सभी अभिव्यक्तियों में एक स्थिर संकलन-समय प्रकार (टेम्पलेट विस्तार के बाद) होता है। सभी प्रकार या तो polymorphic हैं या नहीं।

मैं तुम्हारे लिए विस्तृत करने क्यों typeid (के निकटतम बात) बेकार दोनों ही मामलों में है की कोशिश करेंगे:

  1. typeid उपयोग करने के लिए जब अभिव्यक्ति की स्थिर प्रकार बहुरूपी नहीं है कोई कारण नहीं है। कंपाइलर स्थिर प्रकार का उपयोग करेगा, गतिशील प्रकार नहीं, इसलिए संकलन-समय फ़ंक्शन ओवरलोडिंग कार्य करता है। और is_same जैसे टेम्पलेट प्रकार की विशेषता का उपयोग करके पहचान टाइप करें और अधिक कुशलतापूर्वक जांच की जा सकती है।

  2. यदि अभिव्यक्ति का स्थिर प्रकार polymorphic है, तो typeid विफल रहता है। हां, यह वस्तु के गतिशील प्रकार पर जानकारी देगा। लेकिन केवल सबसे व्युत्पन्न गतिशील प्रकार। यह लिस्कोव प्रतिस्थापन सिद्धांत का उल्लंघन करता है, क्योंकि दिए गए प्रकार Base और Child, Child से व्युत्पन्न एक नया प्रकार Grandchild को Child के रूप में नहीं माना जाएगा। ओपन-क्लोज़ेड सिद्धांत का भी उल्लंघन किया जाता है, क्योंकि डिज़ाइन को सभी प्रकार के पुनर्लेखन के बिना नए प्रकारों के साथ बढ़ाया नहीं जा सकता है। कोई encapsulation नहीं है, क्योंकि कक्षा पदानुक्रम के बारे में जानकारी मजबूत युग्मन बनाने, कार्यक्रम भर में बिखरे हुए होना चाहिए। dynamic_cast कुछ पर विजय प्राप्त करता है लेकिन इन सभी समस्याओं में से कुछ नहीं।

संक्षेप में, typeid का उपयोग करने वाला एक प्रोग्राम बनाए रखने और परीक्षण करने में बहुत मुश्किल होगा।

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

+1

"टाइपिड का उपयोग करने का कोई कारण नहीं है जब अभिव्यक्ति का स्थिर प्रकार polymorphic नहीं है।" जब तक आप 'boost :: any' लिख रहे हों, और आप उपयोगकर्ता को आश्वासन प्रदान करना चाहते हैं कि वैरिएबल में वे स्थिर प्रकार को घुमाएंगे, वैसे ही वे इसे बाहर निकालने का प्रयास कर रहे हैं। आप जानते हैं, 'बूस्ट :: किसी भी' बिंदु के 99% बिंदु। –

+0

@ निकोल: आईएमओ, यह डिबगिंग उपयोगों में से एक है, और 'any_cast' शुरू करने के लिए सही तरीके से हैंडलिंग प्रकार भी नहीं है। 'टाइपिड' वाली सभी समस्याएं 'बूस्ट :: किसी भी' तक पहुंच जाती हैं, और परिणामस्वरूप 'बूस्ट :: किसी भी' का उपयोग करने वाले कार्यक्रमों को बनाए रखना और परीक्षण करना मुश्किल होता है। –

+0

यह समझ में नहीं आता है। 'boost :: any' एक प्रकार-सुरक्षित 'शून्य *' है। यह * नौकरी * यह सुनिश्चित करना है कि वह व्यक्ति जो 'किसी भी' में कुछ डालता है और जिस व्यक्ति ने 'किसी भी' से कुछ लिया है, उस पर सहमत होता है, ताकि सी ++ का उल्लंघन न किया जाए और अपरिभाषित व्यवहार का कारण न हो। इसके बारे में "बनाए रखने में कठिनाई और परीक्षण" कुछ भी नहीं है; जो आपने डाला है वह वह है जो आप बाहर निकलते हैं। इस संदर्भ में "लिस्कोव प्रतिस्थापन" और "खुले बंद" * अप्रासंगिक * हैं। निश्चित रूप से मजबूत युग्मन है, लेकिन * जब आपने टाइप एरर का उपयोग करने का निर्णय लिया है तो * यही वह है जिसे आपने पूछा था। कम से कम यह * सुरक्षित * मजबूत युग्मन है। –

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