
This post is an attempt to summarize everything I read or heard from various sources about type conversion operators in C ++. Information is focused mainly on those who study C ++ for a relatively short time and, it seems to me, should help to understand the specific use of these operators. Old-timers and C ++ gurus may help to complement or correct the picture I have described. I invite everyone interested under the cat.
')
Type casting in the C language style (C-style cast)
A type conversion in the C language style can result in the expression of any type to any other data type (the exception is casting custom types by value if the rules for casting are not defined, and also casting a real type to a pointer or vice versa). For example, an unsigned int can be converted to a pointer to a double. This type conversion method can be used in the C ++ language. However, the C-style type conversion method does not check type compatibility, as static_cast and dynamic_cast can do at the compilation stage and at the execution stage, respectively. In this case, all that const_cast and reinterpret_cast can do this type conversion method can do.
General view of the cast:
(new_type) expwhere
new_type is a new type to which we are
casting , and
exp is an expression that is being
cast to a new type.
Since This operator does not have a reserved keyword (for example, static_cast). It will not be very convenient to find all type conversions in the program text if it is required.
Show example#include <iostream> // // struct AAA{ }; struct BBB{ }; // BBB struct BBB_X:BBB{ }; struct BBB_Y:BBB{ }; int main() { // int i = 5; double d = 111.222; char c = 'a'; int* pi = &i; double * pd = &d; const int* cpi = &i; void* v = NULL; // AAA A; BBB B; BBB_X BX; BBB_Y BY; // AAA* pA = &A; BBB* pB = &B; BBB_X* pBX = &BX; BBB_Y* pBY = &BY; // double int i = (int)d; // d = (double)i; // int char c = (char)pi; //char void v = (void*)c; // void int pi = (int*)v; // const int* pi = (int *) cpi; // AAA BBB // pA = (AAA*) pB; // double double d = (double)pd;//!!! // ? pd = (double*)d;//!!! // pB = (BBB*)pBX; pBY = (BBB_Y*) pB; return 0; }
const_cast
The cast operator const_cast removes or adds const and volatile qualifiers from the original data type (simple types, custom types, pointers, references). For example, there was a const int, and after conversion it became an int or vice versa. The const and volatile qualifiers are called cv qualifiers (cv-qualifiers). These qualifiers are specified before type names. No matter how hard it is to guess the const qualifier sets constancy, i.e. protects a variable from change. The volatile qualifier says that the value of a variable can change without explicit assignment. This provides protection from compiler optimization of operations with this variable.
General view of the cast:
const_cast <new_type> (exp)Show example #include <iostream> // void test_func_X(const int* in1, const int& in2) { int *p; // 33 p = const_cast<int*>(in1); *p = 33; // 55 const_cast<int&>(in2) = 55; } // void test_func_Y(int* in1, int& in2) { const int *p; // // 33 p = const_cast<const int*>(in1); *p = 33;// !!! // // 33 const_cast<const int&>(in2) = 55;//!!! } // volatile void test_func_Z(volatile int* in1, volatile int& in2) { int *p; // volatile 33 p = const_cast<int*>(in1); *p = 33; // volatile 55 const_cast<int&>(in2) = 55; } // volatile void test_func_A(int* in1, int& in2) { volatile int *p; // volatile 33 p = const_cast<volatile int*>(in1); *p = 33; // volatile 55 const_cast<volatile int&>(in2) = 55; } int main() { int x=3,y=5; std::cout<<x<<" "<<y<<std::endl; // test_func_X(&x,y); std::cout<<x<<" "<<y<<std::endl; x=3; y=5; // test_func_Y(&x,y);//!!! std::cout<<x<<" "<<y<<std::endl; // volatile test_func_Z(&x,y); std::cout<<x<<" "<<y<<std::endl; x=3; y=5; std::cout<<x<<" "<<y<<std::endl; // volatile test_func_A(&x,y); std::cout<<x<<" "<<y<<std::endl; system("pause"); return 0; }
An additional example from
5nwShow example #include <iostream> using namespace std; void f(int *x) { cout << __PRETTY_FUNCTION__ << endl; } void f(const int *x) { cout << __PRETTY_FUNCTION__ << endl; } int main() { int x = 5; int *px = &x; f(px); f(const_cast<const int*>(px)); return 0; }
The const and volatile qualifiers can be removed or added only using the cast operator const_cast and type-C casting. Other type casting operators do not affect the const and volatile qualifiers (reinterpret_cast, static_cast, dynamic_cast).
reinterpret_cast
The cast operator reinterpret_cast is used to cast incompatible types. It can result in an integer to a pointer, a pointer to an integer, a pointer to a pointer (the same applies to links). It is a functionally truncated analogue of type conversion in the C language style. The difference is that the reinterpret_cast cannot remove const and volatile qualifiers, and also cannot make unsafe type conversion not directly via pointers, but directly by value. For example, a variable of type int to a variable of type double cannot be cast using reinterpret_cast.
General view of the cast:
reinterpret_cast <new_type> (exp)Show example #include <iostream> // // struct AAA{ }; struct BBB{ }; // BBB struct BBB_X:BBB{ }; struct BBB_Y:BBB{ }; int main() { // int i = 5; double d = 111.222; char c = 'a'; int* pi = &i; double * pd = &d; const int* cpi = &i; void* v = NULL; // AAA A; BBB B; BBB_X BX; BBB_Y BY; // AAA* pA = &A; BBB* pB = &B; BBB_X* pBX = &BX; BBB_Y* pBY = &BY; // double int i = reinterpret_cast<int>(d);//!!! // /d = reinterpret_cast<int>(i);//!!! // int char c = reinterpret_cast<char>(pi); //char void v = reinterpret_cast<void*>(c); // void int pi = reinterpret_cast<int*>(v); // const int* pi = reinterpret_cast<int *>(cpi);//!!! // AAA BBB // pA = reinterpret_cast<AAA*>(pB); // double double d = reinterpret_cast<double>(pd);//!!! // ? pd = reinterpret_cast<double*>(d0;//!!! // pB = reinterpret_cast<BBB*>(pBX); pBY = reinterpret_cast<BBB_Y*>(pB); return 0; }
static_cast
The cast operator static_cast is used for non-polymorphic type casting at the compilation stage of a program. The difference between static_cast and C-style type casting is that this cast operator can track invalid conversions, such as casting a pointer to a value or vice versa (unsigned int to a pointer to a double will not result), and casting pointers and links of different types is considered only valid if it is a coercion of up or down one class inheritance hierarchy, or it is a pointer to void. In case of fixing deviations from these restrictions, an error will be generated when compiling the program. In case of multiple inheritance, static_cast can return a pointer not to the source object, but to its sub-object.
General view of the cast:
static _cast <new_type> (exp)Show example #include <iostream> // // struct AAA{ }; struct BBB{ }; // BBB struct BBB_X:BBB{ }; struct BBB_Y:BBB{ }; int main() { // int i = 5; double d = 111.222; char c = 'a'; int* pi = &i; double * pd = &d; const int* cpi = &i; void* v = NULL; // AAA A; BBB B; BBB_X BX; BBB_Y BY; // AAA* pA = &A; BBB* pB = &B; BBB_X* pBX = &BX; BBB_Y* pBY = &BY; // double int i = static_cast<int>(d); // d = static_cast<int>(i); // int char c = static_cast<char>(pi);//!!! //char void v = static_cast<void*>(c);//!!! // void int pi = static_cast<int*>(v); // const int* pi = static_cast<int *>(cpi);//!!! // AAA BBB // pA = static_cast<AAA*>(pB);//!!! // double double d = static_cast<double>(pd);//!!! // ? pd = static_cast<double*>(d0);//!!! // pB = static_cast<BBB*>(pBX); pBY = static_cast<BBB_Y*>(pB); return 0; }
dynamic_cast
The cast operator dynamic_cast is used for polymorphic type casting at the program execution stage (a class is considered polymorphic if it contains at least one virtual function). If the pointer to be cast refers to an object of the resulting class or an object of the class derived from the resulting one, then the cast is considered successful. Same for links. If casting is not possible, then at the program execution stage, NULL will be returned if pointers are given. If casting over links, an exception std :: bad_cast will be generated. Despite the fact that dynamic_cast is intended to bring polymorphic types according to the inheritance hierarchy, it can also be used for ordinary non-polymorphic types up through the hierarchy. In this case, the error will be received at the compilation stage. The dynamic_cast cast operator will result in a pointer to void, but it cannot cast a pointer to void to another type. The ability dynamic_cast lead polymorphic types provided by the system RTTI (Run-Time Type Identification), which allows you to identify the type of object during program execution. With multiple inheritance, dynamic_cast can return a pointer not to the source object, but to its sub-object.
General view of the cast:
dynamic_cast <new_type> (exp)Show example #include <iostream> // // struct AAA{ // virtual void do_some(){}; }; struct BBB{ // virtual void do_some(){}; }; // BBB struct BBB_X:BBB{ }; struct BBB_Y:BBB{ }; int main() { // void* v = NULL; // AAA A; BBB B; BBB_X BX; BBB_Y BY; // AAA* pA = &A; BBB* pB = &B; BBB_X* pBX = &BX; BBB_Y* pBY = &BY; // AAA BBB // pA = dynamic_cast<AAA*>(pB); if (pA == NULL) { std::cout<<"FAIL"<<std::endl;// !!! } // void BBB pB = dynamic_cast<AAA*>(v); // !!! // BBB void v = dynamic_cast<void*>(pB); // pB = dynamic_cast<BBB*>(pBX); pBY = dynamic_cast<BBB_Y*>(pB); if (pBY == NULL) { std::cout<<"FAIL"<<std::endl;// !!! } system("pause"); return 0; }
Sources:
Video lecture by Evgeny Linsky from the project LectoriumBlog Alena C + +This post @dreary_eyes"A complete guide to C ++" Herbert Shildt“Design and evolution of the C ++ language” by Bjorn Straustrup
Source:
C ++ Standard ($ 212 price)Free working draft of the C ++ N3337 standard
Additionally:
Image taken from post @ SOLON7