The typecasting is the feature which makes C++ more type-safe, robust & may convince you to use it over C. But this is also a more underrated topic when you are a newbie or moving from C background. Hence, I come up with an article on it. Here, we will not only see the C++ type casting with example for C developers but we will also cover & to remember & employ it easily. Why do we need typecasting? C++ type casting cheat codes for C developers Although I am not an expert but this is what I have learned so far from various sources & 5+ yrs of industry experience. In C++, there are 5 different types of casts: C-style casts, static_cast, const_cast, dynamic_cast, and reinterpret_cast. I usually start with “Why we need it?”, but this time first we quickly go through some jargons & I will end this article with . some of CPP core guidelines on typecasting Jargons you need to face where the compiler automatically typecast. Like float f = 3;, here compiler will not complain but directly transform 3 which is of type integer into float & assign to f. Implicit conversion: : where the developer uses a casting operator to direct the conversion. All types of manual casting fall under the explicit type conversions category. Like int * p = (int*)std::malloc(10);, here we explicitly casting void* to int*. Explicit conversions : an identifier which represents memory location. For example, variable name, *ptr where ptr points to a memory location, etc. l-value : a value which is not l-value, r-value appear on the right-hand side of the assignment(=) operator. Like r-value a = ; q = p + ; int 5 // 5 = r-value, 5 // p + 5 is r-value Note: Although there are some exceptions & more to learn on . lvalue, rvalue and their references in C++ Why do we need typecasting? Data is a representation of the bits(0s & 1s) in memory. Data-type is compiler directive which tells the compiler how to store & process particular data.uint32_t a = 5; by this statement you can presume that 4 bytes will be reserved in your memory & upon execution, it will store 0000 0000 0000 0000 0000 0000 0000 0101 data bits in that memory location. This was plain & simple. Let's go a bit further, float f = 3.0; this statement will also reserve 4 bytes in memory & store data bits in the form of 1). the sign bit, 2). exponent & 3). mantissa. Recall . how floating-point numbers are stored in memory But when you write like float f = 3;, the compiler will be confused that how to store an integer value in float type of memory. So it will here) that you want to store 3.0 rather than 3 which is technically same from the human point of view but it's different when you think from cause they stored differently. automatically presume(Implicit conversion computer memory perspective There are many such scenarios where you provide data to store in memory which used to represent different data type. For example, in the following example, you are trying to assign an object of type B into an object of type A }; }; { B b; A a = b; ; } { class A { class B int main () return 0 In such scenario compiler can not presume anything & simply throws a compilation error: status error: no viable conversion from to A a = b; ^ ~ note: {}; ^ note: {}; ^ error generated. exit 1 'B' 'A' candidate viable: no known conversion from 'B' to ' A &' 1st argument class A constructor (the implicit copy constructor) not const for candidate viable: no known conversion from 'B' to 'A &&' 1st argument class A constructor (the implicit move constructor) not for 1 But when you define a conversion operator as follows: : { << ; A(); } }; { class B public operator A () cout "CONVERSION OPERATOR\n" return The compiler will simply call this member function & won’t throw any error because programmer explicitly mentioning that this is how he/she wants to convert. 5 C++ type casting with example for C developers 1️ C-style casts { res = / ; <<res<< ; ; } int main () float 10 4 cout endl return 0 When you will try to run the above code, you will get 2 as output which we didn’t expect. To initialize res variable correctly we need to typecast using float as follows: res = ( ) / ; float float 10 4 Now your answer will be 2.5. This type of casting is very simple & straight forward as it appears. You can also write above casting in C++ as: res = ( ) / ; float float 10 4 C-style casts can change a data type without changing the underlying memory representation which may lead to garbage results. 2️ static_cast If you are C developer like me, then this will be your best goto C++ cast which fits in most of the example like: * p = :: ( ); int std malloc 10 When you try to compile above code using C compiler it works fine. But C++ compiler is not kind enough. It will throw an error as follows : status error: cannot initialize a variable of type with an rvalue of type * p = :: ( ); ^ ~~~~~~~~~~ error generated. exit 1 'int *' 'void *' int std malloc 10 1 The first thing that comes to your mind is the C-style cast: * p = ( *) :: ( ); int int std malloc 10 This will work, but this style of the cast is not recommended in C++. static_cast handles implicit conversions like this. We will primarily use it for converting in places where implicit conversions fail, such as std::malloc. * p = < *>( :: ( )); int static_cast int std malloc 10 The main advantage of static_cast is that it provides compile-time type checking, making it harder to make an inadvertent error. Let's understand this with C++ example: }; B {}; }; { D* d = D; B* b = <B*>(d); X* x = <X*>(d); ; } { class B : class D public { class X int main () new static_cast // this works static_cast // ERROR - Won't compile return 0 As you can see, there is no easy way to distinguish between the two situations without knowing a lot about all the classes involved. Another problem with the C-style casts is that it is too hard to locate. In complex expressions, it can be very hard to see C-style casts e.g. T(something) syntax is equivalent to (T)something. 3️ const_cast Now we will directly jump to example. No theory> can explain this better than example. 1. Ignore constness i = ; & ref = i; * ptr = &i; *ptr = ; < &>(ref) = ; * < *>(ptr) = ; int 0 const int const int 3 // Not OK const_cast int 3 //OK const_cast int 3 //OK You are allowed to modify i, because of the object(i here) being assigned to, is not const. If you add const qualifier to i, code will compile, but its behaviour will be undefined (which can mean anything from "it works just fine" to "the program will crash>".) 2. Modifying data member using const this pointer const_cast can be used to change non-const class members by a method in which this pointer declared as const. - This can also be useful when overloading member functions based on const, for instance: : var; { ->var = temp; ( <X *>( ))->var = temp; } { } }; { a = ; X x; x.changeAndPrint(&a); x.changeAndPrint( ); << x.var << ; ; } { class X public int void changeAndPrint ( temp) int const this // Throw compilation error const_cast this // Works fine void changeAndPrint ( *temp) int // Do some stuff int main () int 4 5 cout endl return 0 3. Pass const argument to a function which accepts only non-const argument const_cast can also be used to pass const data to a function that doesn’t receive const argument. See the following code: { (*ptr + ); } { val = ; << fun( < *>(&val)); ; } int fun ( * ptr) int return 10 int main ( ) void const int 10 cout const_cast int return 0 4. Castaway volatile attribute const_cast can also be used to cast away volatile attribute. Whatever we discussed above in const_cast is also valid for volatile keyword. 4️ dynamic_cast dynamic_cast uses the type checking at runtime in contrary to static_cast which does it at compile time. dynamic_cast is more useful when you don't know the type of input which it represents. Let assume: { ( (rand()% ) == ) Derived1; Derived2; } Base* base = CreateRandom(); Base* CreateRandom () if 2 0 return new else return new As you can see, we don't know which object will be returned by CreateRandom() at run time but you want to execute Method1() of Derived1 if it returns Derived1. So in this scenario, you can use dynamic_cast as follows Derived1 *pD1 = <Derived1 *>(base); (pD1){ pD1->Method1(); } dynamic_cast if In case, if input of dynamic_cast does not point to valid data, it will return nullptr for pointers or throw a std::bad_cast exception for references. In order to work with dynamic_cast, your classes must be polymorphic type i.e. must include at least one virtual methods. dynamic_cast take advantage of RTTI( ) mechanism. Run Time Type Identification 5️ reinterpret_cast reinterpret_cast is a compiler directive which tells the compiler to treat the current type as a new type. You can use reinterpret_cast to cast any pointer or integral type to any other pointer or integral type. This can lead to dangerous situations: nothing will stop you from converting an int to an std::string*. You will use reinterpret_cast in your embedded systems. A common scenario where reinterpret_cast applies is converting between uintptr_t and an actual pointer or between: error: from to (aka ) is allowed ptr = < >(p); ^~~~~~~~~~~~~~~~~~~~~~~~~ error generated. static_cast 'int *' 'uintptr_t' 'unsigned long' not uintptr_t static_cast uintptr_t 1 Instead, use this: ptr = < >(p); uintptr_t reinterpret_cast uintptr_t I have tried to cover most of the intricacies to clear the main concept behind different typecasting, but still, there might be a chance that I may miss some. So, this is it for C++ type casting with an example for C developers. Let's quickly recap: Cheat code for C developers moving to C++ on type casting After reading all this you may confuse on what to use & when! That's why I have created this cheat code Avoid C-style casts. Be sure about what you want while casting. Use static_cast wherever you were using C-style cast. Use dynamic_cast with polymorphic classes. Keep in mind that only use dynamic_cast on classes with at least one virtual member in the inheritance hierarchy. Use when you need to remove or qualifiers. const_cast const volatile Use reinterpret_cast when you have no options. Note: and should generally be avoided because they can be harmful if used incorrectly. Don't use it unless you have a very good reason to use them. const_cast reinterpret_cast Some of C++ core guidelines P.4: Ideally, a program should be statically (compile-time) type safe ES.48: Avoid casts ES.49: If you must use a cast, use a named cast ES.50: Don’t cast away const C.146: Use dynamic_cast where class hierarchy navigation is unavoidable C.147: Use dynamic_cast to a reference type when failure to find the required class is considered an error C.148: Use dynamic_cast to a pointer type when failure to find the required class is considered a valid alternative