C++
स्पष्ट प्रकार के रूपांतरण
खोज…
परिचय
एक अभिव्यक्ति स्पष्ट रूप से परिवर्तित किया जा सकता या डाली टाइप करने के लिए T
का उपयोग कर dynamic_cast<T>
, static_cast<T>
, reinterpret_cast<T>
, या const_cast<T>
, क्या कलाकारों के प्रकार करना है पर निर्भर करता है।
C ++ फ़ंक्शन-स्टाइल कास्ट नोटेशन, T(expr)
, और C-स्टाइल कास्ट नोटेशन, (T)expr
का भी समर्थन करता है।
वाक्य - विन्यास
- सरल-प्रकार-निर्दिष्ट
(
)
- सरल-प्रकार-निर्दिष्ट
(
अभिव्यक्ति-सूची)
- सरल-प्रकार-निर्दिष्ट ब्रेडेड-इनिट-सूची
- टाइपनेम-स्पेसियर
(
)
- टाइपनेम-स्पेसियर
(
अभिव्यक्ति-सूची)
- टाइपनेम-स्पेसियर ब्रेडेड-इनिट- सूची
-
dynamic_cast
<
टाइप-आईडी>
(
अभिव्यक्ति)
-
static_cast
<
टाइप-आईडी>
(
अभिव्यक्ति)
-
reinterpret_cast
<
टाइप-आईडी>
(
अभिव्यक्ति)
-
const_cast
<
टाइप-आईडी>
(
अभिव्यक्ति)
-
(
type-id)
कास्ट-एक्सप्रेशन
टिप्पणियों
सभी छह कलाकारों की सूचनाओं में एक बात समान है:
- एक लैवल्यू रेफरेंस टाइप पर कास्टिंग करना, जैसा कि
dynamic_cast<Derived&>(base)
, एक लैवल्यू की पैदावार देता है। इसलिए, जब आप एक ही वस्तु के साथ कुछ करना चाहते हैं, लेकिन इसे एक अलग प्रकार के रूप में मानते हैं, तो आप एक लैवल्यू रेफरेंस प्रकार में डाल देंगे। - एक रैवल्यू संदर्भ प्रकार पर कास्टिंग करना, जैसा कि
static_cast<string&&>(s)
, एक रिवेल्यू की पैदावार देता है। - एक गैर-संदर्भ प्रकार के लिए कास्टिंग, जैसे
(int)x
, एक पैदावार मिलती है, जिसे मूल्य की प्रतिलिपि के रूप में सोचा जा सकता है, लेकिन मूल से भिन्न प्रकार के साथ।
"असुरक्षित" रूपांतरणों के दो अलग-अलग प्रकारों के प्रदर्शन के लिए reinterpret_cast
कीवर्ड जिम्मेदार है:
- "टाइप पाइंटिंग" रूपांतरण, जिसका उपयोग एक प्रकार की मेमोरी को एक्सेस करने के लिए किया जा सकता है, हालांकि यह एक अलग प्रकार का है।
- पूर्णांक प्रकारों और सूचक प्रकारों के बीच वार्तालाप , दोनों दिशा में।
static_cast
कीवर्ड विभिन्न रूपांतरणों की एक किस्म का प्रदर्शन कर सकता है:
व्युत्पन्न रूपांतरणों का आधार
कोई भी रूपांतरण जो प्रत्यक्ष इनिशियलाइज़ेशन द्वारा किया जा सकता है, जिसमें निहित रूपांतरण और रूपांतरण दोनों शामिल हैं जो एक स्पष्ट कंस्ट्रक्टर या रूपांतरण फ़ंक्शन कहते हैं। अधिक जानकारी के लिए यहां और यहां देखें।
void
करने के लिए, जो अभिव्यक्ति का मूल्य बताता है।// on some compilers, suppresses warning about x being unused static_cast<void>(x);
अंकगणित और गणना प्रकार के बीच, और विभिन्न गणना प्रकार के बीच। Enum रूपांतरण देखें
सूचक से व्युत्पन्न वर्ग के सदस्य तक, सूचक से आधार वर्ग के सदस्य तक। मिलान करने के लिए इंगित किए गए प्रकार सदस्यों के लिए संकेत के आधार रूपांतरण के लिए व्युत्पन्न देखें
- Lvalue से xvalue तक, जैसा कि
std::move
। चाल शब्दार्थ देखें।
व्युत्पन्न रूपांतरण का आधार
static_cast
का उपयोग करके बेस क्लास के लिए एक पॉइंटर को पॉइंटर से व्युत्पन्न वर्ग में परिवर्तित किया जा सकता है। static_cast
कोई रन-टाइम जाँच नहीं करता है और अपरिभाषित व्यवहार को जन्म दे सकता है जब सूचक वास्तव में वांछित प्रकार को इंगित नहीं करता है।
struct Base {};
struct Derived : Base {};
Derived d;
Base* p1 = &d;
Derived* p2 = p1; // error; cast required
Derived* p3 = static_cast<Derived*>(p1); // OK; p2 now points to Derived object
Base b;
Base* p4 = &b;
Derived* p5 = static_cast<Derived*>(p4); // undefined behaviour since p4 does not
// point to a Derived object
इसी तरह, आधार वर्ग के संदर्भ को static_cast
का उपयोग करके व्युत्पन्न वर्ग के संदर्भ में परिवर्तित किया जा सकता है।
struct Base {};
struct Derived : Base {};
Derived d;
Base& r1 = d;
Derived& r2 = r1; // error; cast required
Derived& r3 = static_cast<Derived&>(r1); // OK; r3 now refers to Derived object
यदि स्रोत प्रकार बहुरूपी है, तो dynamic_cast
का उपयोग व्युत्पन्न रूपांतरण के लिए आधार बनाने के लिए किया जा सकता है। यह एक रन-टाइम जाँच करता है और अपरिभाषित व्यवहार उत्पन्न करने के बजाय विफलता ठीक होती है। सूचक मामले में, एक अशक्त सूचक विफलता पर वापस आ जाता है। संदर्भ मामले में, एक अपवाद प्रकार std::bad_cast
की विफलता पर फेंका जाता है std::bad_cast
(या std::bad_cast
से प्राप्त एक वर्ग std::bad_cast
)।
struct Base { virtual ~Base(); }; // Base is polymorphic
struct Derived : Base {};
Base* b1 = new Derived;
Derived* d1 = dynamic_cast<Derived*>(b1); // OK; d1 points to Derived object
Base* b2 = new Base;
Derived* d2 = dynamic_cast<Derived*>(b2); // d2 is a null pointer
कब्ज दूर करना
Const ऑब्जेक्ट के लिए एक पॉइंटर को const_cast
कीवर्ड का उपयोग करके पॉइंटर को नॉन- const_cast
ऑब्जेक्ट में परिवर्तित किया जा सकता है। यहां हम एक फ़ंक्शन को कॉल करने के लिए const_cast
का उपयोग करते हैं जो कि const_cast
सही नहीं है। यह केवल एक नॉन-कॉस्ट char*
तर्क को स्वीकार करता है, भले ही यह सूचक के माध्यम से कभी नहीं लिखता है:
void bad_strlen(char*);
const char* s = "hello, world!";
bad_strlen(s); // compile error
bad_strlen(const_cast<char*>(s)); // OK, but it's better to make bad_strlen accept const char*
const_cast
to reference type का उपयोग const_cast
योग्य लैवल्यू को नॉन-कास्ट-योग्य वैल्यू में बदलने के लिए किया जा सकता है।
const_cast
खतरनाक है क्योंकि यह C ++ प्रकार प्रणाली के लिए आपको एक कास्ट ऑब्जेक्ट को संशोधित करने से रोकने के लिए असंभव बनाता है। ऐसा करने से अपरिभाषित व्यवहार होता है।
const int x = 123;
int& mutable_x = const_cast<int&>(x);
mutable_x = 456; // may compile, but produces *undefined behavior*
धूर्त रूपांतरण टाइप करें
किसी ऑब्जेक्ट प्रकार के लिए एक पॉइंटर (सम्मान। संदर्भ) को reinterpret_cast
का उपयोग करके किसी अन्य ऑब्जेक्ट प्रकार के लिए पॉइंटर (सम्मान। संदर्भ) में परिवर्तित किया जा सकता है। यह किसी भी निर्माता या रूपांतरण कार्यों को नहीं कहता है।
int x = 42;
char* p = static_cast<char*>(&x); // error: static_cast cannot perform this conversion
char* p = reinterpret_cast<char*>(&x); // OK
*p = 'z'; // maybe this modifies x (see below)
reinterpret_cast
का परिणाम ऑपरेंड के समान पते का प्रतिनिधित्व करता है, बशर्ते कि पता गंतव्य स्थान के लिए उपयुक्त रूप से संरेखित हो। अन्यथा, परिणाम अनिर्दिष्ट है।
int x = 42;
char& r = reinterpret_cast<char&>(x);
const void* px = &x;
const void* pr = &r;
assert(px == pr); // should never fire
reinterpret_cast
का परिणाम अनिर्दिष्ट है, सिवाय इसके कि एक सूचक (प्रतिक्रिया। संदर्भ) स्रोत प्रकार से गंतव्य प्रकार और पीछे तक एक दौर की यात्रा से बचेगा, जब तक कि गंतव्य प्रकार की संरेखण आवश्यकता स्रोत प्रकार की तुलना में सख्त नहीं होती है।
int x = 123;
unsigned int& r1 = reinterpret_cast<unsigned int&>(x);
int& r2 = reinterpret_cast<int&>(r1);
r2 = 456; // sets x to 456
अधिकांश कार्यान्वयन पर, reinterpret_cast
पते को परिवर्तित नहीं करता है, लेकिन यह आवश्यकता C ++ 11 तक मानकीकृत नहीं की गई थी।
reinterpret_cast
उपयोग एक पॉइंटर-टू-डेटा-सदस्य प्रकार से दूसरे में बदलने के लिए, या एक पॉइंटर-टू-मेंबर-फ़ंक्शन प्रकार को दूसरे में बदलने के लिए भी किया जा सकता है।
reinterpret_cast
उपयोग करना खतरनाक माना जाता है क्योंकि reinterpret_cast
या संदर्भ के माध्यम से पढ़ने या लिखने के लिए reinterpret_cast
उपयोग करके प्राप्त स्रोत और गंतव्य प्रकार असंबंधित होने पर अपरिभाषित व्यवहार को ट्रिगर कर सकते हैं।
सूचक और पूर्णांक के बीच रूपांतरण
ऑब्जेक्ट पॉइंटर ( void*
सहित) या फ़ंक्शन पॉइंटर को reinterpret_cast
उपयोग करके पूर्णांक प्रकार में परिवर्तित किया जा सकता है। यह केवल तभी संकलित करेगा जब गंतव्य का प्रकार काफी लंबा हो। परिणाम कार्यान्वयन-परिभाषित है और आम तौर पर सूचक को इंगित करने वाले मेमोरी में बाइट का संख्यात्मक पता देता है।
आमतौर पर, long
या unsigned long
किसी भी पॉइंटर मान को रखने के लिए पर्याप्त होती है, लेकिन यह मानक द्वारा गारंटी नहीं है।
यदि प्रकार std::intptr_t
और std::uintptr_t
मौजूद हैं, तो वे पर्याप्त void*
होने की गारंटी देते हैं void*
(और इसलिए किसी भी सूचक को ऑब्जेक्ट प्रकार)। हालांकि, वे फ़ंक्शन पॉइंटर को रखने के लिए लंबे समय तक पर्याप्त होने की गारंटी नहीं देते हैं।
इसी प्रकार, पूर्णांक प्रकार को सूचक प्रकार में परिवर्तित करने के लिए reinterpret_cast
का उपयोग किया जा सकता है। फिर से परिणाम कार्यान्वयन-परिभाषित है, लेकिन पूर्णांक प्रकार के माध्यम से एक राउंड ट्रिप द्वारा अपरिवर्तित होने की गारंटी दी जाती है। मानक यह गारंटी नहीं देता है कि मान शून्य शून्य सूचक में परिवर्तित हो गया है।
void register_callback(void (*fp)(void*), void* arg); // probably a C API
void my_callback(void* x) {
std::cout << "the value is: " << reinterpret_cast<long>(x); // will probably compile
}
long x;
std::cin >> x;
register_callback(my_callback,
reinterpret_cast<void*>(x)); // hopefully this doesn't lose information...
स्पष्ट कंस्ट्रक्टर या स्पष्ट रूपांतरण फ़ंक्शन द्वारा रूपांतरण
एक रूपांतरण जिसमें एक स्पष्ट कंस्ट्रक्टर या रूपांतरण फ़ंक्शन शामिल होता है, वह अंतर्निहित रूप से नहीं किया जा सकता है। हम अनुरोध कर सकते हैं कि रूपांतरण static_cast
का उपयोग करके स्पष्ट रूप से किया जाए। इसका अर्थ प्रत्यक्ष आरंभीकरण के समान है, सिवाय इसके कि परिणाम एक अस्थायी है।
class C {
std::unique_ptr<int> p;
public:
explicit C(int* p) : p(p) {}
};
void f(C c);
void g(int* p) {
f(p); // error: C::C(int*) is explicit
f(static_cast<C>(p)); // ok
f(C(p)); // equivalent to previous line
C c(p); f(c); // error: C is not copyable
}
निष्प्राण रूपांतरण
static_cast
किसी भी अंतर्निहित रूपांतरण का प्रदर्शन कर सकता है। static_cast
का यह उपयोग कभी-कभी उपयोगी हो सकता है, जैसे कि निम्न उदाहरणों में:
एक दीर्घवृत्त के लिए तर्क पारित करते समय, "अपेक्षित" तर्क प्रकार सांख्यिकीय रूप से ज्ञात नहीं होता है, इसलिए कोई अंतर्निहित रूपांतरण नहीं होगा।
const double x = 3.14; printf("%d\n", static_cast<int>(x)); // prints 3 // printf("%d\n", x); // undefined behaviour; printf is expecting an int here // alternative: // const int y = x; printf("%d\n", y);
स्पष्ट प्रकार के रूपांतरण के बिना, एक
double
वस्तु को दीर्घवृत्त के पास भेजा जाएगा, और अपरिभाषित व्यवहार होगा।एक व्युत्पन्न वर्ग असाइनमेंट ऑपरेटर बेस क्लास असाइनमेंट ऑपरेटर को कॉल कर सकता है जैसे:
struct Base { /* ... */ }; struct Derived : Base { Derived& operator=(const Derived& other) { static_cast<Base&>(*this) = other; // alternative: // Base& this_base_ref = *this; this_base_ref = other; } };
एनम रूपांतरण
static_cast
एक पूर्णांक या फ्लोटिंग पॉइंट प्रकार से एन्यूमरेशन प्रकार (चाहे स्कोप या अनकैप्ड) में परिवर्तित हो सकता है, और इसके विपरीत। यह गणन प्रकारों के बीच भी परिवर्तित हो सकता है।
- एक अंकगणित प्रकार से एक अंकगणितीय प्रकार में रूपांतरण एक अंतर्निहित रूपांतरण है;
static_cast
का उपयोग करना संभव है, लेकिन आवश्यक नहीं है।
जब एक स्कोप किया हुआ संसेचन प्रकार एक अंकगणितीय प्रकार में बदल जाता है:
- अगर गंतव्य प्रकार में एनम के मूल्य का सही प्रतिनिधित्व किया जा सकता है, तो इसका परिणाम यह है कि मूल्य।
- अन्यथा, यदि गंतव्य प्रकार एक पूर्णांक प्रकार है, तो परिणाम अनिर्दिष्ट है।
- अन्यथा, यदि गंतव्य प्रकार एक फ़्लोटिंग पॉइंट प्रकार है, तो परिणाम उसी प्रकार है जो अंतर्निहित प्रकार और फिर फ़्लोटिंग प्रकार में कनवर्ट करने के लिए है।
उदाहरण:
enum class Format { TEXT = 0, PDF = 1000, OTHER = 2000, }; Format f = Format::PDF; int a = f; // error int b = static_cast<int>(f); // ok; b is 1000 char c = static_cast<char>(f); // unspecified, if 1000 doesn't fit into char double d = static_cast<double>(f); // d is 1000.0... probably
जब एक पूर्णांक या गणना प्रकार एक गणना प्रकार में परिवर्तित किया जाता है:
- यदि मूल मान गंतव्य एनम की सीमा के भीतर है, तो इसका परिणाम यह है कि मूल्य। ध्यान दें कि यह मान सभी प्रगणकों के लिए असमान हो सकता है।
- अन्यथा, परिणाम अनिर्दिष्ट है (<= C ++ 14) या अपरिभाषित (> = C ++ 17)।
उदाहरण:
enum Scale { SINGLE = 1, DOUBLE = 2, QUAD = 4 }; Scale s1 = 1; // error Scale s2 = static_cast<Scale>(2); // s2 is DOUBLE Scale s3 = static_cast<Scale>(3); // s3 has value 3, and is not equal to any enumerator Scale s9 = static_cast<Scale>(9); // unspecified value in C++14; UB in C++17
जब एक फ़्लोटिंग पॉइंट प्रकार को एन्यूमरेशन प्रकार में परिवर्तित किया जाता है, तो परिणाम एनुम के अंतर्निहित प्रकार और फिर एनम प्रकार में कनवर्ट करने के समान होता है।
enum Direction { UP = 0, LEFT = 1, DOWN = 2, RIGHT = 3, }; Direction d = static_cast<Direction>(3.14); // d is RIGHT
सदस्यों के लिए संकेत के आधार रूपांतरण के लिए व्युत्पन्न
व्युत्पन्न वर्ग के सदस्य के लिए एक सूचक को static_cast
का उपयोग करके आधार वर्ग के सदस्य के लिए एक सूचक में परिवर्तित किया जा सकता है। मिलान करने के लिए इंगित किए गए प्रकार
यदि ऑपरेंड सदस्य मान के लिए अशक्त सूचक है, तो परिणाम भी सदस्य मान के लिए एक अशक्त सूचक है।
अन्यथा, रूपांतरण केवल तभी मान्य होता है, जब ऑपरेटर द्वारा इंगित सदस्य वास्तव में गंतव्य वर्ग में मौजूद होता है, या यदि गंतव्य वर्ग एक आधार या व्युत्पन्न वर्ग होता है, जिसमें संचालक द्वारा इंगित किए गए सदस्य होते हैं। static_cast
वैधता के लिए जाँच नहीं करता है। यदि रूपांतरण मान्य नहीं है, तो व्यवहार अपरिभाषित है।
struct A {};
struct B { int x; };
struct C : A, B { int y; double z; };
int B::*p1 = &B::x;
int C::*p2 = p1; // ok; implicit conversion
int B::*p3 = p2; // error
int B::*p4 = static_cast<int B::*>(p2); // ok; p4 is equal to p1
int A::*p5 = static_cast<int A::*>(p2); // undefined; p2 points to x, which is a member
// of the unrelated class B
double C::*p6 = &C::z;
double A::*p7 = static_cast<double A::*>(p6); // ok, even though A doesn't contain z
int A::*p8 = static_cast<int A::*>(p6); // error: types don't match
शून्य * से T *
C ++ में, void*
को स्पष्ट रूप से T*
परिवर्तित नहीं किया जा सकता है, जहाँ T
एक ऑब्जेक्ट प्रकार है। इसके बजाय, static_cast
का उपयोग रूपांतरण को स्पष्ट रूप से करने के लिए किया जाना चाहिए। यदि ऑपरेंड वास्तव में एक T
ऑब्जेक्ट को इंगित करता है, तो परिणाम उस ऑब्जेक्ट को इंगित करता है। अन्यथा, परिणाम अनिर्दिष्ट है।
भले ही ऑपरेंड एक T
ऑब्जेक्ट को इंगित नहीं करता है, जब तक कि ऑपरेंड एक बाइट को इंगित करता है, जिसका पता टाइप T
लिए ठीक से संरेखित है, उसी बाइट में रूपांतरण बिंदुओं का परिणाम।
// allocating an array of 100 ints, the hard way
int* a = malloc(100*sizeof(*a)); // error; malloc returns void*
int* a = static_cast<int*>(malloc(100*sizeof(*a))); // ok
// int* a = new int[100]; // no cast needed
// std::vector<int> a(100); // better
const char c = '!';
const void* p1 = &c;
const char* p2 = p1; // error
const char* p3 = static_cast<const char*>(p1); // ok; p3 points to c
const int* p4 = static_cast<const int*>(p1); // unspecified in C++03;
// possibly unspecified in C++11 if
// alignof(int) > alignof(char)
char* p5 = static_cast<char*>(p1); // error: casting away constness
सी-स्टाइल कास्टिंग
सी-स्टाइल कास्टिंग को 'सर्वश्रेष्ठ प्रयास' कास्टिंग माना जा सकता है और इसे नाम दिया गया है क्योंकि यह एकमात्र कास्ट है जिसे सी में इस्तेमाल किया जा सकता है। इस कलाकारों के लिए वाक्यविन्यास (NewType)variable
।
जब भी इस कास्ट का उपयोग किया जाता है, यह निम्न में से एक c ++ का उपयोग करता है (क्रम में):
-
const_cast<NewType>(variable)
-
static_cast<NewType>(variable)
-
const_cast<NewType>(static_cast<const NewType>(variable))
-
reinterpret_cast<const NewType>(variable)
-
const_cast<NewType>(reinterpret_cast<const NewType>(variable))
कार्यात्मक कास्टिंग बहुत समान है, हालांकि इसके सिंटैक्स के परिणाम के रूप में कुछ प्रतिबंध: NewType(expression)
। नतीजतन, बिना रिक्त स्थान के केवल प्रकार डाले जा सकते हैं।
नए c ++ कास्ट का उपयोग करना बेहतर है, क्योंकि अधिक पठनीय है और C ++ स्रोत कोड के अंदर कहीं भी आसानी से देखा जा सकता है और संकलन-समय में त्रुटियों का पता लगाया जाएगा, बजाय रन-टाइम में।
चूंकि यह कलाकार अनपेक्षित reinterpret_cast
परिणामस्वरूप हो सकता है, इसलिए इसे अक्सर खतरनाक माना जाता है।