सवाल Static_cast, dynamic_cast, const_cast और reinterpret_cast का उपयोग कब किया जाना चाहिए?


के उचित उपयोग क्या हैं:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • सी शैली कास्ट (type)value
  • फंक्शन-स्टाइल कास्ट type(value)

एक निर्णय कैसे तय करता है कि किस विशिष्ट मामलों में उपयोग करना है?


2052
2017-12-01 20:11


मूल


शायद यहां एक अच्छा संदर्भ है:Static_cast, reinterpret_cast, const_cast, और dynamic_cast के बीच एक नए C ++ प्रोग्रामर में अंतरों को आप कैसे समझाते हैं?। - Nan Xiao
विभिन्न प्रकार के कास्टों का उपयोग करने के कुछ उपयोगी ठोस उदाहरणों के लिए, आप एक समान प्रश्न पर पहला उत्तर देख सकते हैं यह अन्य विषय। - TeaMonkie


जवाब:


static_cast पहली कलाकार है जिसका उपयोग करने का प्रयास करना चाहिए। यह चीजों के बीच अंतर्निहित रूपांतरण जैसे चीजें करता है (जैसे int सेवा मेरे float, या सूचक के लिए void*), और यह स्पष्ट रूपांतरण कार्यों (या निहित) को भी कॉल कर सकता है। कई मामलों में, स्पष्ट रूप से बताते हुए static_cast आवश्यक नहीं है, लेकिन यह ध्यान रखना महत्वपूर्ण है कि T(something) वाक्यविन्यास बराबर है (T)something और इससे बचा जाना चाहिए (उस पर और अधिक)। ए T(something, something_else) हालांकि, सुरक्षित है और कन्स्ट्रक्टर को कॉल करने की गारंटी है।

static_cast विरासत पदानुक्रमों के माध्यम से भी जा सकते हैं। जब ऊपर कास्टिंग (बेस क्लास की ओर) कास्टिंग करते समय अनावश्यक होता है, लेकिन जब नीचे कास्टिंग किया जाता है तब तक इसका उपयोग तब तक किया जा सकता है जब तक यह नहीं डाला जाता virtual विरासत। यह जांच नहीं करता है, हालांकि, और यह अपरिभाषित व्यवहार है static_cast एक पदानुक्रम को एक प्रकार के नीचे जो वास्तव में वस्तु का प्रकार नहीं है।


const_cast निकालने या जोड़ने के लिए इस्तेमाल किया जा सकता है const एक चर के लिए; कोई अन्य सी ++ कास्ट इसे हटाने में सक्षम नहीं है (यहां तक ​​कि नहीं reinterpret_cast)। यह ध्यान रखना महत्वपूर्ण है कि पूर्व में संशोधन करना const मूल वैरिएबल है तो मान केवल अपरिभाषित है const; यदि आप इसे लेने के लिए उपयोग करते हैं const किसी ऐसे संदर्भ के संदर्भ में जिसे घोषित नहीं किया गया था const, यह सुरक्षित है। सदस्य के कार्यों को ओवरलोड करते समय यह उपयोगी हो सकता है const, उदाहरण के लिए। इसे जोड़ने के लिए भी इस्तेमाल किया जा सकता है const किसी ऑब्जेक्ट पर, जैसे कि सदस्य फ़ंक्शन ओवरलोड को कॉल करना।

const_cast इसी तरह काम करता है volatileहालांकि, यह कम आम है।


dynamic_cast लगभग पूरी तरह से बहुरूपता को संभालने के लिए प्रयोग किया जाता है। आप किसी भी अन्य प्रकार के किसी भी प्रकार के पॉलीमोर्फिक प्रकार के पॉइंटर या संदर्भ को कास्ट कर सकते हैं (एक पॉलिमॉर्फिक प्रकार में कम से कम एक वर्चुअल फ़ंक्शन, घोषित या विरासत में मिला है)। आप इसे नीचे कास्टिंग करने से अधिक के लिए उपयोग कर सकते हैं - आप किनारे या यहां तक ​​कि एक और श्रृंखला भी डाल सकते हैं। dynamic_cast वांछित वस्तु की तलाश करेंगे और यदि संभव हो तो इसे वापस कर देंगे। यदि यह नहीं कर सकता है, तो यह वापस आ जाएगा nullptr एक सूचक के मामले में, या फेंक दें std::bad_cast एक संदर्भ के मामले में।

dynamic_cast हालांकि, कुछ सीमाएं हैं। यह काम नहीं करता है अगर विरासत पदानुक्रम (तथाकथित 'डरावना हीरा') में एक ही प्रकार की कई वस्तुएं हैं और आप इसका उपयोग नहीं कर रहे हैं virtual विरासत। यह केवल सार्वजनिक विरासत के माध्यम से जा सकता है - यह हमेशा यात्रा करने में असफल रहेगा protected या private विरासत। यह शायद ही कभी एक मुद्दा है, हालांकि, विरासत के इस तरह के रूप दुर्लभ हैं।


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


सी शैली कास्ट तथा समारोह शैली कास्ट उपयोग कर रहे हैं (type)object या type(object)क्रमशः। एक सी-शैली कास्ट निम्नलिखित में से पहला के रूप में परिभाषित किया जाता है जो सफल होता है:

  • const_cast
  • static_cast (हालांकि पहुंच प्रतिबंधों को अनदेखा कर रहा है)
  • static_cast (ऊपर देखें), फिर const_cast
  • reinterpret_cast
  • reinterpret_cast, फिर const_cast

इसलिए इसे कुछ मामलों में अन्य जानवरों के प्रतिस्थापन के रूप में उपयोग किया जा सकता है, लेकिन एक में भंग करने की क्षमता के कारण यह बेहद खतरनाक हो सकता है reinterpret_cast, और जब तक आप निश्चित नहीं हैं, तब तक बाद वाले कास्टिंग की आवश्यकता होने पर उत्तरार्द्ध को प्राथमिकता दी जानी चाहिए static_cast सफल होगा या reinterpret_cast असफल हो जायेगी। फिर भी, लंबे, अधिक स्पष्ट विकल्प पर विचार करें।

एक प्रदर्शन करते समय सी-स्टाइल कास्ट एक्सेस नियंत्रण को अनदेखा करता है static_cast, जिसका अर्थ है कि उनके पास एक ऐसा ऑपरेशन करने की क्षमता है जो कोई अन्य कलाकार नहीं कर सकता है। यह ज्यादातर क्लेज है, हालांकि, और मेरे दिमाग में सी-स्टाइल कास्ट से बचने का एक और कारण है।


2211
2017-12-01 20:22



गतिशील_कास्ट केवल पॉलिमॉर्फिक प्रकारों के लिए है। जब आप व्युत्पन्न कक्षा में कास्टिंग कर रहे हों तो आपको केवल इसका उपयोग करने की आवश्यकता होगी। static_cast निश्चित रूप से पहला विकल्प है जब तक कि आपको विशेष रूप से गतिशील_कास्ट की कार्यक्षमता की आवश्यकता न हो। यह सामान्य रूप से कुछ चमत्कारी चांदी-बुलेट "टाइप-चेकिंग कास्ट" नहीं है। - jalf
बहुत बढ़िया जवाब! एक त्वरित टिप्पणी: यदि आपके पास व्युत्पन्न * है और बेस * में डालने के लिए पदानुक्रम को डालने के लिए static_cast आवश्यक हो सकता है, क्योंकि डबल पॉइंटर्स / संदर्भ स्वचालित रूप से पदानुक्रम को नहीं डालते हैं। मैं दो मिनट पहले इस तरह (स्पष्ट रूप से, सामान्य नहीं) स्थिति में आया था। ;-) - bartgol
* "कोई अन्य सी ++ कास्ट हटाने में सक्षम है const (इतना भी नहीं reinterpret_cast) "... वास्तव में? किस बारे में reinterpret_cast<int *>(reinterpret_cast<uintptr_t>(static_cast<int const *>(0)))? - Mehrdad
मुझे लगता है कि ऊपर लापता एक महत्वपूर्ण विवरण यह है कि गतिशील_कास्ट में स्थिर या reinterpret_cast की तुलना में रन-टाइम प्रदर्शन जुर्माना है। यह महत्वपूर्ण है, उदा। रीयल-टाइम सॉफ़्टवेयर में। - jfritz42
इसका उल्लेख करने लायक हो सकता है reinterpret_cast एपीआई के अपारदर्शी डेटा प्रकारों के सेट से निपटने पर अक्सर पसंद का हथियार होता है - camelCase


उपयोग dynamic_cast विरासत पदानुक्रम के भीतर पॉइंटर्स / संदर्भों को परिवर्तित करने के लिए।

उपयोग static_cast सामान्य प्रकार के रूपांतरणों के लिए।

उपयोग reinterpret_cast बिट पैटर्न के निम्न स्तर के पुनर्वितरण के लिए। अत्यधिक सावधानी के साथ प्रयोग करें।

उपयोग const_cast दूर कास्टिंग के लिए const/volatile। तब तक इससे बचें जब तक कि आप एक कॉन्स्ट-गलत API का उपयोग करके फंस गए हों।


284
2018-01-21 04:53





(उपरोक्त सैद्धांतिक और वैचारिक स्पष्टीकरण दिया गया है) 

नीचे कुछ हैं व्यावहारिक उदाहरण जब मैंने इस्तेमाल किया static_cast, dynamic_cast, const_cast, reinterpret_cast

(व्याख्या को समझने के लिए इसे भी रेफर करता है: http://www.cplusplus.com/doc/tutorial/typecasting/)

static_cast:

OnEventData(void* pData)

{
  ......

  //  pData is a void* pData, 

  //  EventData is a structure e.g. 
  //  typedef struct _EventData {
  //  std::string id;
  //  std:: string remote_id;
  //  } EventData;

  // On Some Situation a void pointer *pData
  // has been static_casted as 
  // EventData* pointer 

  EventData *evtdata = static_cast<EventData*>(pData);
  .....
}

गतिशील_कास्ट:

void DebugLog::OnMessage(Message *msg)
{
    static DebugMsgData *debug;
    static XYZMsgData *xyz;

    if(debug = dynamic_cast<DebugMsgData*>(msg->pdata)){
        // debug message
    }
    else if(xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){
        // xyz message
    }
    else/* if( ... )*/{
        // ...
    }
}

const_cast:

// *Passwd declared as a const

const unsigned char *Passwd


// on some situation it require to remove its constness

const_cast<unsigned char*>(Passwd)

reinterpret_cast:

typedef unsigned short uint16;

// Read Bytes returns that 2 bytes got read. 

bool ByteBuffer::ReadUInt16(uint16& val) {
  return ReadBytes(reinterpret_cast<char*>(&val), 2);
}

152
2017-12-11 02:05



कुछ अन्य उत्तरों का सिद्धांत अच्छा है, लेकिन फिर भी भ्रमित है, अन्य उत्तरों को पढ़ने के बाद इन उदाहरणों को देखकर वास्तव में उन्हें सभी समझ में आता है। यह उदाहरणों के बिना है, मैं अभी भी अनिश्चित था, लेकिन उनके साथ, अब मुझे यकीन है कि अन्य उत्तरों का क्या अर्थ है। - Solx
Reinterpret_cast के अंतिम उपयोग के बारे में: यह उपयोग के समान नहीं है static_cast<char*>(&val) ? - Lorenzo Belli
@LorenzoBelli बिल्कुल नहीं। क्या तुमने कोशिश की? उत्तरार्द्ध मान्य सी ++ और संकलन ब्लॉक नहीं है। static_cast केवल परिभाषित रूपांतरणों के प्रकार, विरासत द्वारा दृश्यमान संबंध, या से / के बीच काम करता है void *। बाकी सब कुछ के लिए, अन्य जानवर हैं। reinterpret cast किसी को char * किसी ऑब्जेक्ट के प्रतिनिधित्व को पढ़ने की अनुमति देने के लिए प्रकार की अनुमति है - और एकमात्र ऐसे मामलों में से एक जहां यह कीवर्ड उपयोगी है, कार्यान्वयन के एक प्रचलित जनरेटर- / अपरिभाषित व्यवहार नहीं। लेकिन इसे 'सामान्य' रूपांतरण नहीं माना जाता है, इसलिए (आमतौर पर) बहुत रूढ़िवादी द्वारा इसकी अनुमति नहीं है static_cast। - underscore_d
जब आप डेटाबेस जैसे सिस्टम सॉफ़्टवेयर के साथ काम कर रहे हों तो reinterpret_cast बहुत आम है। ज्यादातर मामलों में आप अपना खुद का पेज मैनेजर लिखते हैं, जिसके बारे में कोई जानकारी नहीं है कि पेज में संग्रहीत डेटा प्रकार क्या है और केवल एक शून्य पॉइंटर देता है। इसे उच्च स्तर तक कास्ट करने के लिए उच्च स्तर तक पहुंचें और जो भी चाहें उतना अनुमान लगाएं। - Sohaib


यदि आप आंतरिक रूप से कुछ जानते हैं तो यह मदद कर सकता है ...

static_cast

  • सी ++ कंपाइलर पहले से ही जानता है कि स्केलर प्रकारों को कैसे घुमाएं जैसे कि फ्लोट टू इंट। उनके लिए static_cast का प्रयोग करें।
  • आम तौर पर, टाइप ए से बी को परिवर्तित करते समय, static_cast बी को इसके निर्माता को पास कर देगा। यदि बी में ऐसे कंस्ट्रक्टर नहीं हैं तो आपको संकलन समय त्रुटि मिलती है।
  • से कास्ट A* सेवा मेरे B* हमेशा सफल होता है यदि ए और बी विरासत पदानुक्रम (या शून्य) में हैं अन्यथा आप संकलन त्रुटि प्राप्त करते हैं।
  • पकड़ लिया: यदि आप मूल पॉइंटर को व्युत्पन्न सूचक में डालते हैं, लेकिन यदि वास्तविक ऑब्जेक्ट है तो टाइप नहीं किया गया है तो आप नहीं त्रुटि प्राप्त करें। आपको खराब पॉइंटर मिलता है और जैसे ही आप व्युत्पन्न पॉइंटर के सदस्यों तक पहुंचने का प्रयास करते हैं, आपको रनटाइम पर segfault मिलता है।
  • वही जाता है A& सेवा मेरे B&
  • पकड़ लिया: व्युत्पन्न से बेस या उपाध्यक्ष से कास्ट नई प्रतिलिपि बनाता है! सी # / जावा से आने वाले लोगों के लिए, ऊपर से कई लोग एक आश्चर्यचकित हो सकते हैं।

dynamic_cast

  • डायनामिक_कास्ट रनटाइम प्रकार की जानकारी का उपयोग यह पता लगाने के लिए करता है कि क्या कास्ट वैध है या नहीं। उदाहरण के लिए, (Base*) सेवा मेरे (Derived*)अगर सूचक वास्तव में व्युत्पन्न प्रकार का नहीं है तो असफल हो सकता है।
  • इसका मतलब है, static_cast की तुलना में गतिशील_कास्ट बहुत महंगा है!
  • के लिये A* सेवा मेरे B*, अगर कास्ट अमान्य है तो dynamic_cast nullptr लौटाएगा।
  • के लिये A& सेवा मेरे B& यदि कास्ट अमान्य है तो dynamic_cast bad_cast अपवाद फेंक देगा।
  • अन्य जानवरों के विपरीत, रनटाइम ओवरहेड है।

const_cast

  • जबकि static_cast गैर-आधार को कॉन्स्ट करने के लिए कर सकता है, यह अन्य तरीकों से नहीं जा सकता है। Const_cast दोनों तरीकों से कर सकता है।
  • एक उदाहरण जहां यह आसान आता है जैसे कुछ कंटेनर के माध्यम से पुनरावृत्ति set<T> जो यह सुनिश्चित करने के लिए केवल आपके तत्वों को कॉन्स्ट के रूप में लौटाता है कि आप इसकी कुंजी नहीं बदलते हैं। हालांकि यदि आपका इरादा ऑब्जेक्ट के गैर-कुंजी सदस्यों को संशोधित करना है तो यह ठीक होना चाहिए। आप स्थिरता को हटाने के लिए const_cast का उपयोग कर सकते हैं।
  • एक और उदाहरण है जब आप कार्यान्वित करना चाहते हैं T& foo() साथ ही साथ const T& foo()। कोड डुप्लिकेशन से बचने के लिए, आप एक समारोह से दूसरे फ़ंक्शन के मूल्य को वापस करने के लिए const_cast लागू कर सकते हैं।

reinterpret_cast

  • यह मूल रूप से कहता है कि इस स्मृति स्थान पर इन बाइट्स को लें और इसे दिए गए ऑब्जेक्ट के रूप में सोचें।
  • उदाहरण के लिए, आप फ्लोट में बिट्स की तरह दिखने के लिए 4 बाइट्स फ्लोट को 4 बाइट्स तक लोड कर सकते हैं।
  • जाहिर है, यदि डेटा इस प्रकार के लिए सही नहीं है, तो आप segfault प्राप्त कर सकते हैं।
  • इस कलाकार के लिए कोई रनटाइम ओवरहेड नहीं है।

52
2017-12-01 20:20



के बारे में अंतिम बिंदु const_cast गलत है: केवल dynamic_cast वास्तव में रनटाइम ओवरहेड है। ऐसा लगता है कि आपने ऑर्डर को बदल दिया होगा और उसे स्थानांतरित करने और उसे दोबारा भूलना भूल गया था। - rubenvb
तुम सही हो फिक्स्ड। - ShitalShah


कर देता है इस अपने प्रश्न का उत्तर दें?

मैंने कभी नहीं इस्तेमाल किया है reinterpret_cast, और आश्चर्य कीजिए कि किसी मामले में चलने की आवश्यकता है, जो खराब डिजाइन की गंध नहीं है। कोड बेस में मैं काम करता हूं dynamic_cast बहुत उपयोग किया जाता है। के साथ अंतर static_cast ऐसा है कि एक dynamic_cast रनटाइम जांच करता है जो (सुरक्षित) हो सकता है या नहीं (अधिक ओवरहेड) जो आप चाहते हैं (देखें MSDN)।


11
2018-05-31 14:16



मैंने एक उद्देश्य के लिए reintrepret_cast का उपयोग किया है - बिट्स को डबल से बाहर प्राप्त करना (मेरे प्लेटफ़ॉर्म पर लंबे समय तक एक ही आकार)। - Joshua
reinterpret_cast की आवश्यकता है उदा। COM वस्तुओं के साथ काम करने के लिए। CoCreateInstance () में टाइप शून्य ** (अंतिम पैरामीटर) का आउटपुट पैरामीटर है, जिसमें आप अपने पॉइंटर को घोषित कर देंगे। "INetFwPolicy2 * pNetFwPolicy2"। ऐसा करने के लिए, आपको reinterpret_cast <void **> (और pNetFwPolicy2) जैसे कुछ लिखने की आवश्यकता है। - Serge Rogatch


अब तक अन्य उत्तरों के अलावा, यहां अनजान उदाहरण है static_cast इतना पर्याप्त नहीं है reinterpret_cast जरूरत है। मान लीजिए कि एक ऐसा फ़ंक्शन है जो आउटपुट पैरामीटर में पॉइंटर्स को विभिन्न वर्गों की ऑब्जेक्ट देता है (जो एक सामान्य बेस क्लास साझा नहीं करते हैं)। इस तरह के समारोह का एक वास्तविक उदाहरण है CoCreateInstance() (अंतिम पैरामीटर देखें, जो वास्तव में है void**)। मान लीजिए कि आप इस फ़ंक्शन से ऑब्जेक्ट की विशेष श्रेणी का अनुरोध करते हैं, इसलिए आप पॉइंटर के लिए अग्रिम रूप से जानते हैं (जिसे आप अक्सर COM ऑब्जेक्ट्स के लिए करते हैं)। इस मामले में आप पॉइंटर को अपने पॉइंटर में नहीं डाल सकते हैं void** साथ में static_cast: आप की जरूरत है reinterpret_cast<void**>(&yourPointer)

कोड में:

#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    //static_cast<void**>(&pNetFwPolicy2) would give a compile error
    reinterpret_cast<void**>(&pNetFwPolicy2) );

तथापि, static_cast सरल पॉइंटर्स के लिए काम करता है (प्वाइंटर्स को पॉइंटर्स नहीं), इसलिए उपरोक्त कोड को टालने के लिए फिर से लिखा जा सकता है reinterpret_cast (एक अतिरिक्त चर के मूल्य पर) निम्न तरीके से:

#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
void* tmp = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    &tmp );
pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp);

9