2013-07-16 5 views
10

में उप-वर्ग की कक्षा को जानें, मैंने कम से कम 7 वर्षों में सी ++ नहीं किया है और अचानक सी ++ प्रोजेक्ट में घुटने टेक रहा हूं। मुझे निम्नलिखित के साथ कुछ मार्गदर्शन चाहिए:सी ++

मेरे पास पशु नामक एक वर्ग है, और मेरे पास 3 कक्षाएं हैं जो पशु: बिल्ली, कुत्ते और पक्षी से प्राप्त होती हैं। मैंने एक सूची वस्तु बनाई है और पशु प्रकार को स्टोर करने के लिए इसका उपयोग कर रहा हूं।

इस सूची में बिल्लियों के कुत्ते और पक्षी शामिल हो सकते हैं, जब मैं जानवरों की इस सूची के माध्यम से पुनरावृत्ति कर रहा हूं, तो मैं प्रत्येक जानवर के तत्काल प्रकार (चाहे वह बिल्ली, कुत्ता या पक्षी हो) जानना चाहें।

जब मैं कहता हूं typeid(animal).name(); यह मुझे पशु देता है, जो सच है, लेकिन मैं जानना चाहता हूं कि किस तरह का पशु।

कोई विचार ?? क्या मुझे enums का उपयोग करना चाहिए ??

+20

यदि संभव हो तो ऐसा करने की कोशिश न करें। अपना 'पशु' अमूर्त इंटरफ़ेस बनाएं ताकि ठोस प्रकार कोई फर्क नहीं पड़ता। –

+1

यदि आपकी सूची std :: list आपको पॉलिमॉर्फिज्म नहीं मिलेगी, तो आपको स्मार्ट पॉइंटर्स – doctorlove

+0

@MarkB का उपयोग करने की आवश्यकता है, इसे उत्तर में लिखें ताकि मैं इसे –

उत्तर

21

आप लगभग निश्चित रूप से जानना नहीं चाहते हैं। आपको इन जानवरों के साथ बातचीत करने के लिए वर्चुअल उचित विधियों के रूप में घोषित करना चाहिए।

यदि आपको विशेष रूप से उन पर काम करने की आवश्यकता है, तो आप विज़िटर ऑब्जेक्ट को पास करने या प्रत्येक कंक्रीट क्लास में सही डेटा को फ़ंक्शन करने के लिए विज़िटर पैटर्न का उपयोग कर सकते हैं। यदि आप टैग करने पर जोर देते हैं (और मैं जोर देता हूं कि यह तीसरा विकल्प है - अन्य दो समाधान आपके कोड को अधिक क्लीनर छोड़ देंगे), classname नामक वर्चुअल विधि है जो प्रकार पहचानकर्ता (चाहे स्ट्रिंग या int या जो भी हो) ।

पॉइंटर प्रकार के विपरीत, यदि आपके पास ऑब्जेक्ट प्रकार की सरणी है, तो स्लाइसिंग के बारे में भी ध्यान दें। यदि आपने 7 वर्षों में सी ++ का उपयोग नहीं किया है, तो हो सकता है कि आप भाषा को काफी बेहतर बनाने के लिए टेम्पलेट उपयोग के विकास से अवगत न हों। क्या किया जा सकता है यह देखने के लिए boost जैसे पुस्तकालयों की जांच करें, और कैसे टेम्पलेटिंग आपको टाइप-अवरक्त जेनेरिक कोड लिखने की अनुमति देता है।

+0

मुझे पता है कि सच बहुरूपता का मतलब ठोस वर्ग को जानने की आवश्यकता नहीं है, लेकिन अन्य उद्देश्यों के लिए यह जानना अच्छा होगा, मुझे आपकी आभासी टाइपनाम विधि पसंद है, यह मेरी आवश्यकताओं के लिए काम कर सकता है। – PaulG

+6

जबकि मैं पूरी तरह से आपके उत्तर से सहमत हूं, मैं अभी भी बताउंगा कि 'टाइपनाम' सी ++ में एक आरक्षित कीवर्ड है। – Aesthete

+0

@Aesthete 2002 के बाद से नया है? वह आखिरी मानक था जिसका इस्तेमाल मैंने किया था। – Marcin

14
Dog* dog = dynamic_cast<Dog*>(myAnimalPointer); 
if (dog == NULL) 
{ 
    // This animal is not a dog. 
} 
+2

अब तक सवाल का यह एकमात्र वास्तविक "उत्तर" है, मैं कहूंगा। हालांकि वर्चुअल फ़ंक्शन विचार भी काम करते हैं। +1 –

+1

या अनूठा रूप से सुव्यवस्थित रूप ... 'अगर (कुत्ता * कुत्ता = गतिशील_कास्ट (myAnimalPointer)) ... '। लेकिन, यह सामान्य रूप से * दाएं * उत्तर में जरूरी नहीं है - अगर बाद में 'डोबर्मन' और 'पूडल' कक्षाएं आगे बढ़ी हैं, तो यह कोड संकलित और सबसे अधिक व्युत्पन्न नाम बताए बिना चलाएगा। यद्यपि प्रश्न में बहुत सीमित पदानुक्रम के लिए ठीक है। –

+0

@RickyMutschlechner: दरअसल ... – alecov

1

प्रत्येक उपclass में फ़ंक्शन नाम() कार्यान्वित करें।

+0

एक वर्चुअल फ़ंक्शन ?? मुझे इस कार्य को अपने पशु वस्तु से कॉल करने में सक्षम होना चाहिए। – PaulG

+0

हां, लेकिन यह नहीं सोचें कि यह सबसे अच्छा तरीका होगा। नाम एक स्ट्रिंग है, जहां आपको स्ट्रिंग की तुलना करना है ... – RvdK

+0

यही कारण है कि मैं enums के बारे में सोच रहा था, लेकिन यह सुनिश्चित नहीं है कि इसे सबक्लासिंग के साथ कैसे काम करना है। – PaulG

11

एक विशिष्ट ठोस ऑब्जेक्ट प्रकार को जानने की आवश्यकता आमतौर पर सी ++ में एक डिजाइन गंध है, इसलिए मैं यह सुझाव देने जा रहा हूं कि आप ऐसा करने का प्रयास नहीं करते हैं।

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

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

और @Marcin ने बताया कि डबल प्रेषण के लिए विज़िटर पैटर्न का उपयोग करके एक बेहतर दृष्टिकोण हो सकता है यदि आपको वास्तव में विशिष्ट बाल वर्गों पर विशिष्ट विधियों को कॉल करने की आवश्यकता होती है।

1

चूंकि सूची में किसी भी प्रकार का जानवर हो सकता है, मुझे लगता है कि यह पॉइंटर्स की एक सूची है। In such case typeid will consider the most derived type of the object if you pass it the dereferenced pointer.

typeid(*animal).name(); 

जो आप ढूंढ रहे हैं वह है।

+2

काम कर सकता है, लेकिन 'name()' की पाठ्य सामग्री को परिभाषित किया गया है और खाली होने की अनुमति है, इसलिए यह विश्वसनीय/पोर्टेबल नहीं है। –

3

कंक्रीट कोड typeid पर निर्भर करता है अलग-अलग चीजें देता है।इसके अतिरिक्त name() कुछ भी लौटा सकता है (पहला अक्षर अपरकेस या हटाने * सहित), यह केवल डीबगिंग के लिए है। अब मेरे पास कुछ अलग सकारात्मक उत्तर हैं typeid(animal).name() वापस आ सकते हैं। 2 animalAnimal करने के लिए एक typedef है

struct animal { 
    virtual ~animal() {} 
}; 

struct dog 
    : animal 
{}; 

struct cat 
    : animal 
{}; 

struct bird 
    : animal 
{}; 

int main() { 
    std::cout << typeid(animal).name() << std::endl; // animal 
    return 0; 
} 

संस्करण::

struct Animal { 
}; 

struct Dog 
    : Animal 
{}; 

struct Cat 
    : Animal 
{}; 

struct Bird 
    : Animal 
{}; 

int main() { 
    typedef Animal animal; 
    std::cout << typeid(animal).name() << std::endl; // Animal 
    return 0; 
} 

वर्शन, 3 animal है एक सूचक:

struct Animal { 
}; 

struct Dog 
    : Animal 
{}; 

struct Cat 
    : Animal 
{}; 

struct Bird 
    : Animal 
{}; 

int main() { 
    Dog d; 
    Animal* animal=&d; 
    std::cout << typeid(animal).name() << std::endl; // Animal* 
    return 0; 
} 

संस्करण

संस्करण 1 animal एक वर्ग के नाम है 4 animal एओ है bject:

struct Animal { 
    ~virtual Animal() {} 
}; 

struct Dog 
    : Animal 
{}; 

struct Cat 
    : Animal 
{}; 

struct Bird 
    : Animal 
{}; 

int main() { 
    Dog d; 
    Animal& animal=d; 
    std::cout << typeid(animal).name() << std::endl; //Dog 
    return 0; 
} 
:

struct Animal { 
}; 

struct Dog 
    : Animal 
{}; 

struct Cat 
    : Animal 
{}; 

struct Bird 
    : Animal 
{}; 

int main() { 
    Dog d; 
    Animal& animal=d; 
    std::cout << typeid(animal).name() << std::endl; // Animal 
    return 0; 
} 

और संस्करण 7 animal एक बहुरूपी वस्तु के लिए एक संदर्भ है:

struct Animal { 
}; 

struct Dog 
    : Animal 
{}; 

struct Cat 
    : Animal 
{}; 

struct Bird 
    : Animal 
{}; 

int main() { 
    Animal animal; 
    std::cout << typeid(animal).name() << std::endl; // Animal 
    return 0; 
} 

संस्करण 6 animal एक गैर बहुरूपी objcet लिए एक संदर्भ है

जैसा कि अन्य ने लिखा है बेहतर है किपर भरोसा न करें 0। लेकिन कुछ कोड के बिना यह कहना आसान नहीं है कि क्या सही है।

+0

+1। यह कम से कम हमारे ओपी के प्रयासों को लोहे में मदद करने में मदद करता है .. – Macke

+0

संस्करण 6 और 7 में आपका कोड समान है। क्या कुछ याद आ रही है? –

+0

@DarrelHoffman ओह मेरी गलती धन्यवाद। मैं वर्चुअल विनाशक भूल गया जो मैंने जोड़ा। एसओ को कोड ट्रांसफर करने में एक कॉपी संपादन त्रुटि। –

0

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

#include <typeinfo> 
#include <string> 
#include <iostream> 


template <class T> 
class Animal { 
public: 
    virtual ~Animal() {}; // a base class 
    std::string name() { 
     return typeid(T).name(); 
    } 
}; 


class Cat: public Animal<Cat> { 

}; 

class Dog: public Animal<Dog> { 

}; 

int main(int argc, char* argv[]){ 
    Cat c; 
    Dog d; 

    std::cout << c.name() << std::endl; 
    std::cout << d.name() << std::endl; 

} 

परिणाम (छ ++):

3Cat 
3Dog 

परिणाम

हालांकि, अगर आप एक छोटे से अधिक सजावटी प्राप्त करना चाहते हैं, दिलचस्प आवर्ती टेम्पलेट parttern CRTP एक, और अधिक सुरुचिपूर्ण अगर गूढ़ समाधान उपलब्ध कराता है (बनाम 2008):

class Cat 
class Dog 

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