2010-03-01 20 views
6

के लिए जांचें यदि कोई ऑब्जेक्ट क्लासए या व्युत्पन्न प्रकार क्लासबी प्रकार है तो मैं रनटाइम पर कैसे जांच करूं? एक मामले में मैं दोनों मामलों में अलग सेव्युत्पन्न प्रकार (सी ++)

ClassA* SomeClass::doSomething (ClassA*) 
{ 
    if(/* parameter is of type base class */) { 

    } else if { /* derived class */) { 

    } 
} 

शायद मैं कह सकते हैं कि व्युत्पन्न वर्ग ClassB कुछ विशेष क्षमता है संभाल करने के लिए किया है। लेकिन मौजूदा क्लास क्लास को बदलने के बिना मैं ऐसा कैसे करूं?

+2

क्लास को कक्षाबी के बारे में कुछ भी जानने की आवश्यकता नहीं है। –

+0

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

उत्तर

20

आमतौर पर इस तरह के सटीक प्रकार को स्विच करना बहुत बुरा विचार है। ऐसा करके, आप ClassA के व्युत्पन्न कक्षाओं में अपनी विधि को कसकर जोड़ रहे हैं। आपको बहुरूपता का उपयोग करना चाहिए। कक्षा ए में virtual विधि का परिचय दें, इसे कक्षा बी में ओवरराइड करें और बस इसे अपनी विधि में कॉल करें।

class ClassA { 
    public: virtual bool hasSpecificFunctionality() { return false; } 
}; 

class ClassB : public ClassA { 
    public: virtual bool hasSpecificFunctionality() { return true; } 
}; 

ClassA* SomeClass::doSomething (ClassA* arg) 
{ 
    if (arg->hasSpecificFunctionality()) { 

    } else { 

    } 
} 
+0

+1 - लेकिन वह कहता है कि वह क्लासए को नहीं बदलना/नहीं बदल सकता है, इसलिए वर्चुअल फ़ंक्शन प्रश्न से बाहर है। –

+2

@Poita_: यदि आप बेस क्लास को नहीं बदल सकते हैं, तो शायद आपको पहले स्थान पर विरासत की बजाय संरचना के साथ जाना चाहिए था। –

+0

क्या होगा यदि उसे बेस क्लास से बहुरूपता की आवश्यकता है ...? –

4

क्लासबी पर अतिरिक्त कुछ() विधि क्यों नहीं है जो क्लासबी की अतिरिक्त क्षमताओं को संभालती है? यह बहुरूपता का सार है।

+2

नहीं, बहुरूपता के लिए आपको 'कक्षा' (संभवतः एक नोप के रूप में) ''कुछ' विधि की आवश्यकता है, इसे 'कक्षाबी' में ओवरराइड करना। उदाहरण यह भी दिखाता है कि क्यों: आप 'कक्षा * * पर 'कक्षाबी :: doSomething()' को कॉल नहीं कर सकते हैं। – MSalters

2

slighlty अलग आप के लिए

ClassB* b; 
if ((b = dynamic_cast<ClassB*>(ptr)) == 0) { 
    // not a classB* 
} else { 
    // a classB* in b 
} 
3

क्या पूछा वाक्य रचना यह है कि:

ClassA* SomeClass::doSomething (ClassA* pa) 
{ 
    ClassB* pb = dynamic_cast<ClassB*>(pa); 
    if(pb) ... 

(नोट बहुरूपी वर्ग पदानुक्रम के भीतर यह केवल काम करता है यही है, वहाँ आभासी कार्यों होना जरूरी है। शामिल।)

हालांकि, आपको इससे बचने की कोशिश करनी चाहिए। वर्चुअल फ़ंक्शंस को लागू करके इसे हल करने के लिए आपको इसकी क्या आवश्यकता नहीं है?

12

उपयोग एक dynamic_cast इस प्रकार है::

यहां तक ​​कि अगर मैं किसी कारण से बाहरी समारोह अपने आप में कार्यक्षमता को संभालने के लिए मजबूर किया गया था, मैं की तरह कुछ करना होगा

ClassA* SomeClass::doSomething(ClassA *a) 
{ 
    if (dynamic_cast<DerivedClass *>(a)) { 
     .... 
    } else if (dynamic_cast<BaseClass *>(a)) { 
     .... 
    } 
} 

dynamic_cast<T *>(ptr) होगा 0ptrT के सूचक का सूचक नहीं है, और अन्यथा T प्रकार का सूचक लौटाएगा।

dynamic_cast आमतौर पर टाला जा सकता है और खराब डिजाइन/कोड का संकेतक है। यदि आप इससे बच सकते हैं, तो ऐसा करने का प्रयास करें, क्योंकि इसे आपके अंतिम निष्पादन योग्य में RTTI की आवश्यकता है।

+4

लेकिन याद रखें, गतिशील_कास्ट के लिए यह तर्क एक पॉलीमॉर्फिक वर्ग (यानी कम से कम एक आभासी विधि वाले वर्ग) के लिए एक सूचक (या संदर्भ) होना चाहिए। अन्यथा गतिशील_कास्ट विफल हो जाएगा। –

+2

आपको 'बेसक्लास' पर कास्ट करने से पहले 'DerivedClass' पर कास्ट करने की आवश्यकता होगी, क्योंकि' बेस क्लास 'कास्ट किसी भी प्रकार के लिए सफल होगा। –

+0

अच्छा बिंदु :) मैंने जवाब संपादित किया है। –

2

अन्य ने इंगित किया है कि प्रकारों पर स्विचिंग आमतौर पर एक बुरा विचार है, इसलिए मैं नहीं करूँगा। क्या तुम सच में यह करने के लिए है, तो आप एक वस्तु की गतिशील प्रकार पर स्विच करने के लिए typeid ऑपरेटर का उपयोग कर सकते हैं:

ClassA* SomeClass::doSomething (ClassA* a) 
{ 
    if (ClassB *b = dynamic_cast<classB*>(a)) { 
     /* parameter is, or is derived from, ClassB */ 
    } else { 
     /* parameter is, or is derived from, ClassA but not ClassB */ 
    } 
} 

:

ClassA* SomeClass::doSomething (ClassA* a) 
{ 
    if (typeid(*a) == typeid(ClassA)) { 
     /* parameter is of type base class */ 
    } else if (typeid(*a) == typeid(ClassB)) { 
     /* a specific derived class */ 
    } else { 
     /* some other derived class */ 
    } 
} 

dynamic_cast समान है, लेकिन परिवर्तनीयता, नहीं समानता के लिए परीक्षण ये केवल काम करते हैं यदि ClassA पॉलिमॉर्फिक है (यानी, इसमें कम से कम एक वर्चुअल फ़ंक्शन है)।

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