मैंने सुना है कि static_cast
फ़ंक्शन को सी-स्टाइल या साधारण फ़ंक्शन-स्टाइल कास्टिंग के लिए प्राथमिकता दी जानी चाहिए। क्या ये सच है? क्यों?
मैंने सुना है कि static_cast
फ़ंक्शन को सी-स्टाइल या साधारण फ़ंक्शन-स्टाइल कास्टिंग के लिए प्राथमिकता दी जानी चाहिए। क्या ये सच है? क्यों?
जवाबों:
मुख्य कारण यह है कि क्लासिक सी डाले जिसे हम दोनों के बीच कोई भेद नहीं करते है static_cast<>()
, reinterpret_cast<>()
, const_cast<>()
, और dynamic_cast<>()
। ये चार चीजें पूरी तरह से अलग हैं।
A static_cast<>()
आमतौर पर सुरक्षित है। भाषा में एक वैध रूपांतरण, या एक उपयुक्त निर्माता है जो इसे संभव बनाता है। जब आप विरासत में किसी वर्ग में जाते हैं, तो यह थोड़ा जोखिम भरा होता है; आपको यह सुनिश्चित करना चाहिए कि वस्तु वास्तव में वह वंशज है जिस पर आप दावा करते हैं कि इसका मतलब भाषा से बाहरी है (जैसे कि ऑब्जेक्ट में झंडा)। एक dynamic_cast<>()
के रूप में लंबे समय के रूप परिणाम चेक किया गया है (सूचक) या एक संभावित अपवाद के खाते (संदर्भ) में रखा जाता है सुरक्षित है।
दूसरी ओर A reinterpret_cast<>()
(या a const_cast<>()
) हमेशा खतरनाक होता है। आप संकलक को बताते हैं: "मुझ पर भरोसा करें: मुझे पता है कि यह ऐसा नहीं दिखता है foo
(ऐसा लगता है जैसे कि यह परस्पर नहीं है), लेकिन यह है"।
पहली समस्या यह है कि यह बताना लगभग असंभव है कि कोड के बड़े और फैलाने वाले टुकड़ों को देखने और सभी नियमों को जानने के बिना सी-स्टाइल कास्ट में कौन सा होगा।
आइए मान लेते हैं ये:
class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase *pSomething; // filled somewhere
अब, इन दोनों को उसी तरह संकलित किया गया है:
CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked
pMyObject = (CDerivedClass*)(pSomething); // Same as static_cast<>
// Safe; as long as we checked
// but harder to read
हालाँकि, आइए इसे लगभग समान कोड देखें:
CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert
pOther = (CMyOtherStuff*)(pSomething); // No compiler error.
// Same as reinterpret_cast<>
// and it's wrong!!!
जैसा कि आप देख सकते हैं, इसमें शामिल सभी वर्गों के बारे में बहुत कुछ जाने बिना दो स्थितियों के बीच अंतर करने का कोई आसान तरीका नहीं है।
दूसरी समस्या यह है कि सी-स्टाइल कास्ट का पता लगाना बहुत मुश्किल है। जटिल अभिव्यक्तियों में सी-स्टाइल कास्ट को देखना बहुत कठिन हो सकता है। एक पूर्ण उपकरण को लिखना लगभग असंभव है जिसे सी-स्टाइल कास्ट (उदाहरण के लिए एक खोज उपकरण) का पता लगाने की आवश्यकता है, बिना पूर्ण उड़ा सी ++ संकलक फ्रंट-एंड के। दूसरी ओर, "static_cast <" या "reinterpret_cast <" के लिए खोज करना आसान है।
pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
// No compiler error.
// but the presence of a reinterpret_cast<> is
// like a Siren with Red Flashing Lights in your code.
// The mere typing of it should cause you to feel VERY uncomfortable.
इसका मतलब है कि, न केवल सी-शैली की जातियां अधिक खतरनाक हैं, बल्कि उन सभी को खोजने के लिए यह सुनिश्चित करना बहुत कठिन है कि वे सही हैं।
static_cast
एक वंशानुगत पदानुक्रम नीचे कास्टिंग के लिए उपयोग नहीं करना चाहिए , बल्कि dynamic_cast
। कि या तो अशक्त सूचक या एक वैध सूचक लौटेगा।
static_cast
उस स्थिति में उपयोग करने के लिए चेतावनी दी । dynamic_cast
सुरक्षित हो सकता है, लेकिन यह हमेशा सबसे अच्छा विकल्प नहीं है। कभी-कभी आप जानते हैं कि एक सूचक किसी दिए गए उपप्रकार की ओर इशारा करता है, इसका मतलब संकलक से अपारदर्शी है, और एक static_cast
तेजी से है। कम से कम कुछ वातावरणों में, dynamic_cast
वैकल्पिक संकलक समर्थन और रनटाइम लागत (आरटीटीआई को सक्षम करना) की आवश्यकता होती है, और आप इसे केवल कुछ चेकों के लिए सक्षम नहीं करना चाहते हैं जो आप स्वयं कर सकते हैं। C ++ की RTTI समस्या का केवल एक संभावित समाधान है।
static_cast
। C का समतुल्य reinterpret_cast
है *(destination_type *)&
, अर्थात वस्तु का पता लेना, उस पते को एक अलग प्रकार के लिए सूचक को कास्टिंग करना, और फिर dereferencing। चरित्र प्रकार या कुछ विशेष प्रकार के मामले को छोड़कर, जिसके लिए C इस निर्माण के व्यवहार को परिभाषित करता है, यह आम तौर पर C.
int
(और int
अकेले), का उपयोग क्यों static_cast<int>
बनाम के (int)
रूप में एकमात्र लाभ वर्ग चर और संकेत के साथ लगता है। निवेदन है कि आप इस बारे में विस्तार से बताएं।
int
dynamic_cast
लागू नहीं होता है, लेकिन अन्य सभी कारण खड़े होते हैं। उदाहरण के लिए: मान लीजिए v
कि एक फंक्शन पैरामीटर घोषित किया गया है float
, फिर (int)v
है static_cast<int>(v)
। लेकिन अगर आप पैरामीटर को बदलते हैं float*
, तो (int)v
चुपचाप हो जाता है reinterpret_cast<int>(v)
जबकि static_cast<int>(v)
अवैध और सही ढंग से कंपाइलर द्वारा पकड़ा जाता है।
एक व्यावहारिक टिप: यदि आप प्रोजेक्ट को व्यवस्थित करने की योजना बनाते हैं, तो आप अपने स्रोत कोड में static_cast कीवर्ड के लिए आसानी से खोज सकते हैं।
int
पैरामीटर के साथ एक फ़ंक्शन घोषणा ।
संक्षेप में :
static_cast<>()
आपको एक संकलित समय की जाँच करने की क्षमता देता है, सी-स्टाइल कास्ट नहीं करता है।static_cast<>()
C ++ स्रोत कोड के अंदर कहीं भी आसानी से देखा जा सकता है; इसके विपरीत, C_Style कास्ट स्पॉट करना कठिन है।- इरादों को C ++ जातियों का उपयोग करके बेहतर ढंग से व्यक्त किया जाता है।
अधिक स्पष्टीकरण :
स्थिर कलाकार संगत प्रकारों के बीच रूपांतरण करता है । यह सी-स्टाइल कास्ट के समान है, लेकिन अधिक प्रतिबंधक है। उदाहरण के लिए, सी-स्टाइल कास्ट एक पूर्णांक सूचक को एक चार को इंगित करने की अनुमति देगा।
char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes
चूंकि यह 4-बाइट पॉइंटर में आवंटित मेमोरी के 1 बाइट की ओर इशारा करता है, इसलिए इस पॉइंटर पर लिखने से या तो रन-टाइम त्रुटि होगी या कुछ आसन्न मेमोरी को अधिलेखित कर देगा।
*p = 5; // run-time error: stack corruption
सी-स्टाइल कास्ट के विपरीत, स्टेटिक कास्ट कंपाइलर को यह जांचने की अनुमति देगा कि पॉइंटर और पॉइंटी डेटा प्रकार संगत हैं, जो प्रोग्रामर को संकलन के दौरान इस गलत पॉइंटर असाइनमेंट को पकड़ने की अनुमति देता है।
int *q = static_cast<int*>(&c); // compile-time error
आगे पढ़ें:
static_cast <> और C स्टाइल कास्टिंग
और रेगुलर कास्ट बनाम static_cast बनाम डायनामिक_कास्ट में क्या अंतर है
static_cast<>()
अधिक पठनीय है। मेरा मतलब है, कभी-कभी यह होता है, लेकिन ज्यादातर समय - विशेष रूप से मूल पूर्णांक प्रकारों पर - यह सिर्फ बुरी तरह से और अनावश्यक रूप से क्रिया है। उदाहरण के लिए: यह एक फ़ंक्शन है जो 32-बिट शब्द के बाइट्स को स्वैप करता है। static_cast<uint##>()
जातियों का उपयोग करना पढ़ना लगभग असंभव होगा , लेकिन जातियों का उपयोग करना समझना काफी आसान है (uint##)
। कोड की तस्वीर: imgur.com/NoHbGve
always
या तो नहीं कहा । (लेकिन अधिकांश बार हाँ) ऐसे मामले हैं जहां सी शैली डाली अधिक पठनीय है। C शैली कास्टिंग के कारणों में से एक है कि अभी भी रहते हैं और c ++ imho में किकिंग करते हैं। :) वैसे यह एक बहुत अच्छा उदाहरण था
(uint32_t)(uint8_t)
उन बाइट्स को प्राप्त करने के लिए जंजीर ( ) को प्राप्त करने के लिए दो कास्ट का उपयोग करता है इसके अलावा सबसे कम रीसेट किए जाते हैं। उसके लिए बिटवाइस और ( 0xFF &
) है। जातियों का उपयोग इरादे को बाधित कर रहा है।
सवाल सिर्फ स्टैटर static_cast या C स्टाइल कास्टिंग का उपयोग करने से बड़ा है क्योंकि C स्टाइल कास्ट का उपयोग करते समय अलग-अलग चीजें होती हैं। C ++ कास्टिंग ऑपरेटर्स का उद्देश्य इन ऑपरेशनों को अधिक स्पष्ट करना है।
सतह पर static_cast और C शैली की कास्ट एक ही चीज़ के लिए दिखाई देते हैं, उदाहरण के लिए जब एक मान को दूसरे में रखते हैं:
int i;
double d = (double)i; //C-style cast
double d2 = static_cast<double>( i ); //C++ cast
इन दोनों ने पूर्णांक मान को दोगुना कर दिया। हालाँकि जब पॉइंटर्स के साथ काम किया जाता है तो चीजें अधिक जटिल हो जाती हैं। कुछ उदाहरण:
class A {};
class B : public A {};
A* a = new B;
B* b = (B*)a; //(1) what is this supposed to do?
char* c = (char*)new int( 5 ); //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error
इस उदाहरण में (1) शायद ठीक है क्योंकि ए द्वारा बताई गई वस्तु वास्तव में बी का उदाहरण है लेकिन क्या होगा यदि आप उस बिंदु पर कोड में नहीं जानते हैं कि वास्तव में क्या इंगित करता है? (2) शायद पूरी तरह से कानूनी (आप केवल पूर्णांक के एक बाइट को देखना चाहते हैं), लेकिन यह भी एक गलती हो सकती है जिस स्थिति में एक त्रुटि अच्छी होगी, जैसे (3)। C ++ कास्टिंग ऑपरेटर्स का उद्देश्य है कि जब संभव हो संकलन-समय या रन-टाइम त्रुटियों को प्रदान करके इन मुद्दों को कोड में उजागर किया जाए।
तो, सख्त "मूल्य कास्टिंग" के लिए आप static_cast का उपयोग कर सकते हैं। यदि आप चाहते हैं कि रन-टाइम पॉलीमोर्फिक कास्टिंग पॉइंटर्स डायनामिक_कास्ट का उपयोग करें। यदि आप वास्तव में प्रकारों के बारे में भूलना चाहते हैं, तो आप reintrepret_cast का उपयोग कर सकते हैं। और बस खिड़की से बाहर फेंक वहाँ const_cast है।
वे कोड को अधिक स्पष्ट करते हैं ताकि यह ऐसा लगे जैसे आप जानते हैं कि आप क्या कर रहे थे।
static_cast
इसका मतलब है कि आप गलती से const_cast
या reinterpret_cast
, जो कि एक अच्छी बात नहीं है।
प्रभावी C ++ परिचय देखें
यह इस बारे में है कि आप कितने प्रकार की सुरक्षा थोपना चाहते हैं।
जब आप लिखते हैं (bar) foo
(जो कि reinterpret_cast<bar> foo
यदि आपने एक प्रकार का रूपांतरण ऑपरेटर प्रदान नहीं किया है तो बराबर है ) आप कंपाइलर को सुरक्षा की अनदेखी करने के लिए कह रहे हैं, और जैसा बताया गया है वैसा ही करें।
जब आप लिखते हैं static_cast<bar> foo
तो आप संकलक से कम से कम यह जांचने के लिए पूछ रहे हैं कि प्रकार रूपांतरण कुछ अर्थ कोड को सम्मिलित करने के लिए अभिन्न प्रकार के लिए समझ में आता है।
EDIT 2014-02-26
मैंने यह उत्तर 5 साल पहले लिखा था, और मुझे यह गलत लगा। (टिप्पणियाँ देखें।) लेकिन यह अभी भी बढ़ जाता है!
static_cast<bar>(foo)
कोष्ठक के साथ है। उसी के लिए reinterpret_cast<bar>(foo)
।
C स्टाइल कास्ट कोड के एक ब्लॉक में याद करना आसान है। सी ++ स्टाइल कास्ट न केवल बेहतर अभ्यास है; वे लचीलेपन का अधिक से अधिक डिग्री प्रदान करते हैं।
reinterpret_cast सूचक प्रकार के रूपांतरणों के लिए अभिन्न अनुमति देता है, हालांकि यदि दुरुपयोग किया जाता है तो असुरक्षित हो सकता है।
static_cast सांख्यिक प्रकारों के लिए अच्छा रूपांतरण प्रदान करता है, जैसे कि enums से ints या ints से फ़्लोट्स या किसी भी प्रकार के डेटा पर, जो आपके प्रकार के बारे में आश्वस्त हैं। यह कोई रन टाइम चेक नहीं करता है।
दूसरी ओर डायनेमिक_कास्ट किसी भी अस्पष्ट असाइनमेंट या रूपांतरण को चिह्नित करने वाले इन चेक को करेगा। यह केवल पॉइंटर्स और रेफरेंस पर काम करता है और एक ओवरहेड को इम्प्रेस करता है।
दूसरों के एक जोड़े हैं, लेकिन ये मुख्य हैं जो आप भर में आएंगे।
स्थिर_कास्ट, अलग-अलग बिंदुओं से लेकर कक्षाओं तक, का उपयोग कक्षाओं में स्पष्ट रूप से परिभाषित रूपांतरणों को करने के लिए, साथ ही साथ मूलभूत प्रकारों के बीच मानक रूपांतरण करने के लिए भी किया जा सकता है:
double d = 3.14159265;
int i = static_cast<int>(d);
static_cast<int>(d)
, हालांकि, (int)d
इतना अधिक संक्षिप्त और पठनीय है? (मैं मूल प्रकार के मामले में हूं, वस्तु सूचक नहीं।)
(int)d
होने पर कोई क्यों लिखेगा int{d}
? कंस्ट्रक्टर, या फंक्शन की तरह यदि आपके पास है ()
, तो सिंटैक्स जटिल अभिव्यक्तियों में कोष्ठक के बुरे सपने में विचलित करने के लिए लगभग इतना तेज़ नहीं है। इस मामले में, यह int i{d}
इसके बजाय होगा int i = (int)d
। बेहतर आईएमओ है। उस ने कहा, जब मुझे बस एक अभिव्यक्ति में एक अस्थायी की आवश्यकता होती है, तो मैं static_cast
निर्माण करता हूं और कभी भी निर्माण कलाकारों का उपयोग नहीं किया है, मुझे नहीं लगता। मैं केवल (C)casts
तब उपयोग करता हूं जब जल्दी से डिबग cout
एस लिख रहा हूं ...