2009-06-16 15 views
6

मेरे पास प्रकारों का पदानुक्रम है - जेनेरिक क्लास और कई व्युत्पन्न कक्षाएं, दिलचस्प DerivedClass शामिल है, जेनेरिक क्लास पॉलिमॉर्फिक है। एक इंटरफेसक्या गतिशील_कास्ट का उपयोग करने से रनटाइम पर ऑब्जेक्ट प्रकार का पता लगाने का कोई तेज़ तरीका है?

interface ICallback { 
    virtual void DoStuff(GenericClass*) = 0; 
}; 

जो मुझे लागू करने की आवश्यकता है। तब मैं जब GenericClass * सूचक ICallback में पारित मामले का पता लगाने के लिए चाहते हैं :: DoStuff() वास्तव में InterestingDerivedClass के लिए सूचक है:

class CallbackImpl : public ICallback { 
    void DoStuff(GenericClass* param) { 
     if(dynamic_cast<InterestingDerivedClass*>(param) != 0) { 
      return; //nothing to do here 
     } 
     //do generic stuff 
    } 
} 

GenericClass और व्युत्पन्न वर्ग मेरे नियंत्रण से बाहर है, मैं केवल CallbackImpl को नियंत्रित कर रहे हैं ।

मैं dynamic_cast बयान का समय समाप्त हो - यह 1400 चक्र जो पल के लिए स्वीकार्य है लेता है, लेकिन बहुत तेजी से नहीं की तरह दिखता है। मैंने डीबगर में गतिशील_कास्ट के दौरान निष्पादित किए गए सामानों को हटाने की कोशिश की और देखा कि इसमें बहुत सारे निर्देश हैं।

के बाद से मैं वास्तव में व्युत्पन्न वर्ग के लिए सूचक की ज़रूरत नहीं है वहाँ केवल RTTI का उपयोग कर कार्यावधि में ऑब्जेक्ट प्रकार का पता लगाने के एक तेज़ तरीका है? हो सकता है कि कुछ कार्यान्वयन-विशिष्ट विधि जो केवल "एक" संबंध जांचती है लेकिन सूचक को पुनर्प्राप्त नहीं करती है?

+0

http://stackoverflow.com/questions/500493/c-equivalent-of-instanceof –

उत्तर

12

मैं हमेशा कोड गंध के रूप में dynamic_cast के उपयोग को देखता हूं। आप इसे सभी परिस्थितियों में बहुरूप व्यवहार के साथ प्रतिस्थापित कर सकते हैं और अपनी कोड गुणवत्ता में सुधार कर सकते हैं। अपने उदाहरण में मैं कुछ इस तरह करना होगा:

class GenericClass 
{ 
    virtual void DoStuff() 
    { 
    // do interesting stuff here 
    } 
}; 

class InterestingDerivedClass : public GenericClass 
{ 
    void DoStuff() 
    { 
    // do nothing 
    } 
}; 

class CallbackImpl : public ICallback { 
    void DoStuff(GenericClass* param) { 
     param->DoStuff(); 
    } 
} 

आपके मामले में, आप लक्ष्य वर्गों संशोधित नहीं कर सकते, तो आप एक अनुबंध GenericClass प्रकार की घोषणा से गर्भित करने के लिए प्रोग्रामिंग कर रहे हैं। इसलिए, ऐसा कुछ भी होने की संभावना नहीं है जो आप कर सकते हैं dynamic_cast से तेज़ होगा, क्योंकि किसी और को क्लाइंट कोड को संशोधित करने की आवश्यकता होगी।

1

type_info की तुलना किसी भी तेजी से की जाएगी? (पैरामीटर पर typeid पर कॉल करें)

+2

के समान, हाँ, यह तेज़ है लेकिन यह विरासत का परीक्षण नहीं करता है, केवल सटीक मिलान। – Macke

+1

यह तेज़ हो सकता है। लेकिन यह एक अच्छा विचार नहीं है (ऊपर मूल कोड की तरह)। –

+0

मुझे लगता है कि उसे अन्य उत्तरों में पर्याप्त रूप से व्याख्यान दिया गया है। उन्होंने जो किया है वह करने का एक तेज़ तरीका पूछा। (यह एक उचित बिंदु है कि type_infos की तुलना में केवल * बिल्कुल * दिलचस्प DerivedClass को पकड़ लिया जाएगा, इससे प्राप्त कुछ भी नहीं)। –

1

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

मूल प्रश्न के लिए, GetRuntimeType() फ़ंक्शन को ICallback पर प्रस्तुत करना काफी अच्छी तरह से होगा: एमएफसी देखें कि यह कैसे किया जा सकता है।

5

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

क्योंकि ऐसी असमानता है, तो यह आपके स्वयं के विरासत पदानुक्रम बनाने के लायक हो सकता है उस कोड को लपेटता है जिसे आप नियंत्रित नहीं करते हैं। आप गतिशील_कास्ट (एक बार) का उपयोग करके रैपर के उदाहरण बनाएंगे कि यह निर्धारित करने के लिए कि किस प्रकार का व्युत्पन्न प्रकार बनाना है, और फिर वहां से वर्चुअल फ़ंक्शंस का उपयोग करें।

+1

+1 – ralphtheninja

1

आपके ठोस उपयोग मामले में, उत्तर वर्चुअल फ़ंक्शंस का उपयोग करना है।

हालाँकि, हालात हैं, जहां आपको गतिशील रूप से डाउनकास्ट करने की आवश्यकता है। इस ऑपरेशन को तेज़ी से बनाने के लिए कुछ तकनीकें हैं (या आपके कंपाइलर को dynamic_cast लागू करने के तरीके के आधार पर बहुत तेज है), विशेष रूप से, यदि आप स्वयं को एकल विरासत तक सीमित करते हैं।समस्या अब (isInstanceOfB की एक तेजी से कार्यान्वयन) दे रहा है,

f(A* pA) 
{ 
    if (isInstanceOfB(pA)) 
    { 
    B* pB = static_cast<B*>(pA); 
    // do B stuff... 
    } 
} 
बेशक

: मुख्य विचार यह है कि अगर आप किसी भी तरह सही प्रकार जानते हैं, एक static_cast बहुत तेजी से होता है।

उदाहरण के लिए boost::type_traits देखें।

2

मुझे एक सुंदर हैकिश डिज़ाइन की तरह दिखता है। (जैसा कि अन्य ने उल्लेख किया है, dynamic_cast का उपयोग करना आमतौर पर एक संकेत है कि आपके पास एक डिज़ाइन समस्या है।)। लेकिन अगर अधिकांश कोड आपके नियंत्रण से बाहर है, तो मुझे लगता है कि आप इसके बारे में ज्यादा कुछ नहीं कर सकते हैं।

लेकिन नहीं, मुझे पता है कि एकमात्र सामान्य समाधान dynamic_Cast है। typeid केवल सबसे अधिक व्युत्पन्न प्रकार से मेल खाता है, जो आपके मामले में काम कर सकता है।

एक तरफ ध्यान दें, कारण dynamic_cast इतना महंगा हो सकता है कि इसे पूरे वर्ग पदानुक्रम को पार करना होगा। यदि आपके पास गहरा पदानुक्रम है, तो यह महंगा हो जाता है (दूसरे शब्दों में, सामान्य रूप से गहरा पदानुक्रम नहीं है, लेकिन विशेष रूप से सी ++ में)।

0

आप http://www.boost.org/doc/libs/1_39_0/boost/type_traits/is_convertible.hpp उपयोग कर सकते हैं (बेशक पहली बार जब आप डाली प्रदर्शन, सबसे वर्ग वर्णनकर्ता लुकअप शायद कैश छूट जाए, जो अपने बेंच मार्किंग विषम हो सकता है और इसे और अधिक महंगा की तुलना में यह है देखने के लिए किया जाता हो जाएगा) और सीपीयू प्रदर्शन की जांच करें?

.. तुम भी कार्यान्वयन चेकआउट कर सकते हैं

संदर्भ: http://www.boost.org/doc/libs/1_39_0/libs/type_traits/doc/html/boost_typetraits/reference/is_convertible.html

1

स्टैंडर्ड dynamic_cast, बहुत लचीला है, लेकिन आम तौर पर बहुत धीमी है क्योंकि यह कई कोनों मामलों आप शायद के बारे में कोई दिलचस्पी नहीं कर रहे हैं संभालती है। यदि आप एकल विरासत का उपयोग करते हैं, तो आप वर्चुअल फ़ंक्शंस के आधार पर इसे सरल कार्यान्वयन के साथ प्रतिस्थापित कर सकते हैं।

उदाहरण कार्यान्वयन:

// fast dynamic cast 
//! Fast dynamic cast declaration 
/*! 
Place USE_CASTING to class that should be recnognized by dynamic casting. 
Do not forget do use DEFINE_CASTING near class definition. 
*\note Function dyn_cast is fast and robust when used correctly. 
Each class that should be used as target for dyn_cast 
must use USE_CASTING and DEFINE_CASTING macros.\n 
Forgetting to do so may lead to incorrect program execution, 
because class may be sharing _classId with its parent and IsClassId 
will return true for both parent and derived class, making impossible' 
to distinguish between them. 
*/ 
#define USE_CASTING(baseType) \ 
    public: \ 
    static int _classId; \ 
    virtual size_t dyn_sizeof() const {return sizeof(*this);} \ 
    bool IsClassId(const int *t) const \ 
    { \ 
    if(&_classId==t) return true; \ 
    return baseType::IsClassId(t); \ 
    } 

//! Fast dynamic cast root declaration 
/*! 
Place USE_CASTING_ROOT to class that should act as 
root of dynamic casting hierarchy 
*/ 

#define USE_CASTING_ROOT \ 
    public: \ 
    static int _classId; \ 
    virtual size_t dyn_sizeof() const {return sizeof(*this);} \ 
    virtual bool IsClassId(const int *t) const { return (&_classId==t); } 

//! Fast dynamic cast definition 
#define DEFINE_CASTING(Type) \ 
    int Type::_classId; 

template <class To,class From> 
To *dyn_cast(From *from) 
{ 
    if(!from) return NULL; 
    if(from->IsClassId(&To::_classId)) 
    { 
    assert(dynamic_cast<To *>(from)); 
    return static_cast<To *>(from); 
    } 
    return NULL; 
} 

जिसके अनुसार, मैं दूसरों के साथ सहमत सम्पूर्ण dynamic_cast संदेहास्पद है और आप सबसे अधिक बार एक बहुत क्लीनर रास्ते में एक ही लक्ष्य को प्राप्त करने में सक्षम हो जाएगा। उस ने कहा, गोटो के समान, कुछ ऐसे मामले हो सकते हैं जहां यह वास्तव में उपयोगी और अधिक पठनीय हो सकता है।

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

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