2009-10-27 15 views
9

मैं खुद को सी ++ सिखाने की कोशिश कर रहा हूं, और पारंपरिक "नई भाषा" अभ्यासों में से एक जो मैंने हमेशा उपयोग किया है, कुछ बाइनरी पेड़ या एक लिंक्ड सूची की तरह कुछ डेटा संरचना को लागू करना है। जावा में, यह अपेक्षाकृत सरल था: मैं कुछ वर्ग नोड को परिभाषित कर सकता था जो एक आवृत्ति परिवर्तनीय Object data बनाए रखता था, ताकि कोई सूची या पेड़ के प्रत्येक नोड में किसी भी प्रकार की वस्तु को स्टोर कर सके। (बाद में मैंने जेनेरिकों का उपयोग करके इसे संशोधित करने पर काम किया; यह सवाल इस बारे में नहीं है।)सी ++ में किसी ऑब्जेक्ट प्रकार के संदर्भ को बनाए रखें?

मुझे "किसी भी प्रकार की ऑब्जेक्ट" को संग्रहीत करने का एक समान, बेवकूफ सी ++ तरीका नहीं मिल रहा है। सी में मैं void पॉइंटर का उपयोग करूंगा; वही बात सी ++ के लिए काम करती है, जाहिर है, लेकिन जब मैं std::string का उदाहरण बनाता हूं और इसे सूची/पेड़ में संग्रहीत करने की कोशिश करता हूं (std::string& से void* पर अमान्य कास्ट के बारे में कुछ) तो मैं समस्याओं में भाग लेता हूं। क्या ऐसा कोई रास्ता है? क्या सी ++ जावा के ऑब्जेक्ट (या ऑब्जेक्टिव-सी के एनएसओब्जेक्ट) के बराबर है?

बोनस प्रश्न: यदि ऐसा नहीं होता है, और मुझे शून्य पॉइंटर्स का उपयोग करना जारी रखना है, तो std::string को void* में स्टोर करने का "सही" तरीका क्या है? मैं static_cast<char*>(str.c_str()) पर ठोकर खाई, लेकिन ऐसा लगता है कि मैं जो करने की कोशिश कर रहा हूं उसके लिए वर्बोज़ लगता है। क्या कोई बेहतर तरीका है?

+3

यह सवाल क्यों कम किया गया था? –

+0

मुझे भी जानना रूचि है - मुझे डुप्ली या कुछ भी नहीं मिला ... – Tim

+2

यह पुराने मजाक की तरह है। रोगी: जब मैं ऐसा करता हूं तो दर्द होता है। डॉक्टर: ऐसा मत करो। सी ++ में, "कुछ भी" का संग्रह न करें। –

उत्तर

11

सी ++ में मूल ऑब्जेक्ट नहीं है जो जावा के विपरीत, सभी ऑब्जेक्ट्स से प्राप्त होता है। आप जो करना चाहते हैं उसके लिए सामान्य दृष्टिकोण templates का उपयोग करना होगा। मानक सी ++ लाइब्रेरी में सभी कंटेनर इस दृष्टिकोण का उपयोग करते हैं।

जावा के विपरीत, सी ++ जेनेरिक कंटेनरों को लागू करने के लिए बहुरूपता/विरासत पर निर्भर नहीं है। जावा में, सभी ऑब्जेक्ट्स Object से प्राप्त होते हैं, और इसलिए किसी भी वर्ग को एक कंटेनर में डाला जा सकता है जो Object लेता है। सी ++ टेम्पलेट्स, हालांकि, समय संरचना संकलित कर रहे हैं जो संकलक को वास्तव में आपके द्वारा उपयोग किए जाने वाले प्रत्येक प्रकार के लिए एक अलग वर्ग उत्पन्न करने का निर्देश देते हैं। तो, उदाहरण के लिए, यदि आपके पास:

template <typename T> 
class MyContainer { ... }; 

फिर आप एक MyContainer कि std::string वस्तुओं लेता है बना सकते हैं, और एक अन्य MyContainer कि int रों लेता है।

MyContainer<std::string> stringContainer; 
stringContainer.insert("Blah"); 

MyContainer<int> intContainer; 
intContainer.insert(3342); 
+0

क्या मेरे लिए जावा जेनेरिक में मानसिक रूप से टेम्पलेट्स को अनुरूप बनाना सुरक्षित है? – Tim

+2

वास्तव में नहीं। वे काफी अलग हैं, भले ही वाक्यविन्यास सतही रूप से वही है। –

+3

विस्तृत करने के लिए, जावा जेनेरिक एक रनटाइम तंत्र है जो विरासत और बहुरूपता पर निर्भर करता है। सी ++ टेम्पलेट संकलित-समय संरचनाएं हैं जो प्रत्येक पैरामीटर प्रकार के लिए कोड उत्पन्न करने के लिए कंपाइलर को निर्देश देते हैं। अधिक जानकारी के लिए मेरा संपादित उत्तर देखें। –

3

जो आप ढूंढ रहे हैं वह टेम्पलेट्स हैं। वे आपको कक्षाएं और कार्य करने की अनुमति देते हैं जो आपको किसी भी डेटाटाइप को लेने की अनुमति देता है।

1

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

लेकिन, जैसा कि अन्य लोगों ने कहा, यह करने के लिए एक बेहतर तरीका टेम्पलेट्स के साथ है

+1

सी-शैली कास्ट सी ++ में निराश होना चाहिए। –

2

टेम्पलेट्स यह करने के लिए स्थिर तरीका है। वे जावा और सी # जेनेरिक की तरह व्यवहार करते हैं लेकिन 100% स्थैतिक (संकलन समय) हैं। यदि आपको एक ही कंटेनर में विभिन्न प्रकार के objetcs को स्टोर करने की आवश्यकता नहीं है, तो इसका उपयोग करें (अन्य उत्तरों इसका वर्णन बहुत अच्छी तरह से करते हैं)।

हालांकि, यदि आपको एक ही कंटेनर में विभिन्न प्रकार की वस्तुओं को स्टोर करने की आवश्यकता है, तो आप बेस क्लास पर पॉइंटर्स संग्रहीत करके गतिशील तरीके से कर सकते हैं।

#include <list> 

class Animal { 
public: 
    virtual ~Animal() {} 
}; 

class Dog : public Animal { 
public: 
    virtual ~Dog() {} 
}; 

class Cat : public Animal { 
public: 
    virtual ~Cat() {} 
}; 

int main() { 
    std::list<Animal*> l; 
    l.push_back(new Dog); 
    l.push_back(new Cat); 

    for (std::list<Animal*>::iterator i = l.begin(); i!= l.end(); ++i) 
     delete *i; 

    l.clear(); 

    return 0; 
} 

एक स्मार्ट सूचक का उपयोग करना आसान है: बेशक, आप के बाद से वहाँ C++ ऐसी कोई "ऑब्जेक्ट" वर्ग है अपनी खुद की वस्तुओं पदानुक्रम परिभाषित करने के लिए किया है। boost::smart_ptr साथ उदाहरण:

std::list< boost::smart_ptr<Animal> > List; 
List.push_back(boost::smart_ptr<Animal>(new Dog)); 
List.push_back(boost::smart_ptr<Animal>(new Cat)); 
List.clear(); // automatically call delete on each stored pointer 
9

आप :: बढ़ावा पर किसी भी वर्ग एक बार देख ले सकते हैं। यह सुरक्षित है, आप इसे मानक संग्रह में डाल सकते हैं और आपको किसी भी लाइब्रेरी से लिंक करने की आवश्यकता नहीं है, कक्षा हेडर फ़ाइल में लागू की गई है।

यह आप इस तरह कोड लिखने की अनुमति देता है:

#include <list> 
#include <boost/any.hpp> 

typedef std::list<boost::any> collection_type; 

void foo() 
{ 
    collection_type coll; 
    coll.push_back(boost::any(10)); 
    coll.push_back(boost::any("test")); 
    coll.push_back(boost::any(1.1)); 
} 

सभी दस्तावेज़ यहाँ है: http://www.boost.org/doc/libs/1_40_0/doc/html/any.html

1
static_cast<char*>(str.c_str()) 

मेरे लिए अजीब लग रहा है। str.c_str() सी-जैसी स्ट्रिंग को पुनर्प्राप्त करता है, लेकिन const char * टाइप करके, और char * में कनवर्ट करने के लिए आप आमतौर पर const_cast<char *>(str.c_str()) का उपयोग करेंगे। सिवाय इसके कि यह करना अच्छा नहीं है, क्योंकि आप string के आंतरिक के साथ दखल दे रहे हैं। क्या आपको यकीन है कि आपको उस पर कोई चेतावनी नहीं मिली है?

आपको static_cast<void *>(&str) का उपयोग करने में सक्षम होना चाहिए। आपके द्वारा प्राप्त त्रुटि संदेश से मुझे पता चलता है कि आपको कुछ और गलत मिला है, इसलिए यदि आप कोड पोस्ट कर सकते हैं तो हम इसे देख सकते हैं। (डेटा प्रकार std::string&string का संदर्भ है, एक पॉइंटर नहीं, इसलिए त्रुटि संदेश सही है। मुझे नहीं पता कि आपको पॉइंटर के बजाय संदर्भ कैसे मिला।)

और, हाँ , यह verbose है। इसका इरादा है। आमतौर पर कास्टिंग को सी ++ प्रोग्राम में खराब गंध माना जाता है, और स्ट्रॉस्ट्रप को ढूंढना आसान होता था। जैसा कि अन्य उत्तरों में चर्चा की गई है, मनमानी आधार प्रकार की डेटा संरचना बनाने का सही तरीका टेम्पलेट्स का उपयोग करके, कास्ट और पॉइंटर्स नहीं है।

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

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