CLOSE

Type Conversion

Type Conversion (also known as typecasting) is the process of converting a variable from one data type to another.

Types of Type Conversion

C++ supports two major forms of type conversion:

TypePerformed BySafetyExample Syntax
ImplicitCompilerSafefloatVar = intVar;
ExplicitProgrammerNeeds caution(int)floatVar or static_cast

1️⃣ Implicit Conversion (Type Promotion or Coercion):

Implicit conversion, also known as automatic conversion, occurs when the compiler automatically converts one data type to another without any explicit instruction from the programmer. This conversion is performed to avoid data loss and to promote compatibility between different data types.

  • Done automatically by the compiler
  • Converts form a lower to higher precision type (e.g., int → float)

Example:

int intValue = 10;
float floatValue = intValue;  // Implicit conversion from int to float

In this example, the integer value intValue is implicitly converted to a floating-point number floatValue during the assignment.

Example in Expression:

int x = 5;
double y = 2.5;
double result = x + y; // x is promoted to double

2️⃣ Explicit Conversion (Type Casting):

Explicit conversion, also called type casting, is performed by the programmer using casting operators.

There are two types of explicit conversion: C-style casting and functional casting.

C-Style Casting:

In standard C programming, casts are done vis the () operator, with the name of the type to convert the value placed inside the parentheses.

float floatValue = 10.5;
int intValue = (int) floatValue;  // C-style casting

While C-style casting is concise, it can lead to potential issues if used improperly. It can perform dangerous conversions and may not be easily recognized in the code.

Functional Casting (Since C++11):

int value = int(3.75);  // Function-style cast — converts to 3

C++ Cast Operators (Safer and more specific):

C++ introduces four casting operators for more clarity and type safety:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
float floatValue = 10.5;
int intValue = static_cast<int>(floatValue); // C++ static_cast from float to int

Using static_cast is generally preferred as it performs checks at compile-time and is more specific about the intended conversion.

static_cast

PurposeCompile-time type conversion
Use Case ExampleConvert float to int, void* to specific pointer

C++ introduces a casting operator called static_cast, which can be used to convert a value of one type to a value of another type.

  • Performs basic conversions between related types.
  • Works at compile time (no runtime overhead).
  • Used when the types are compatible or there's known relationship between them.
  • Can be used for:
    • Numeric conversions: double → int, int → char
    • Converting pointers up the inheritance hierarchy (Derived* → Base*)
    • void* → actual pointer type
    • Enum ↔ int conversions
#include <iostream>

int main()
{
    char c { 'a' };
    std::cout << c << ' ' << static_cast<int>(c) << '\n'; // prints a 97

    return 0;
}

Example:

float f = 3.14;
int i = static_cast<int>(f);  // i = 3 (truncates decimal)
void* ptr = malloc(sizeof(int));
int* iptr = static_cast<int*>(ptr);  // from void* to typed pointer

⚠️ Caution:

  • No runtime type check.
  • Safe only when you're certain the conversion is valid.

dynamic_cast

PurposeSafe downcasting for polymorphic types
Use Case ExampleConvert Base* to Derived* with runtime check

Description:

  • Used for safe downcasting in an inheritance hierarchy.
  • Requires the base class to have at least one virtual function (i.e., polymorphic).
  • Performs a runtime check and returns nullptr if the cast is invalid (for pointers).
  • Works only with pointers or references to class types.

Example:

class Base { virtual void func() {} };
class Derived : public Base {};

Base* b = new Derived();
Derived* d = dynamic_cast<Derived*>(b);  // Safe cast: b actually points to Derived

Base* b2 = new Base();
Derived* d2 = dynamic_cast<Derived*>(b2);  // Invalid: returns nullptr

⚠️ Caution:

  • Adds runtime overhead.
  • Only use when type-safety is critical and polymorphism is involved.

const_cast

PurposeAdd or remove const or volatile
Use Case ExampleRemove const from a pointer

Description:

  • Used to cast awayconst or volatile qualifiers.
  • Allows modifying something declared as const (not safe unless you're sure the object is non-const in reality).

Example:

void print(char* str) {
    std::cout << str;
}

const char* msg = "Hello";
print(const_cast<char*>(msg));  // Removes const, may be unsafe!

⚠️ Caution:

  • Undefined behavior if you modify truly const data.
  • Only use when you're confident the data wasn't originally declared const.

reinterpret_cast

PurposeReinterpret bit pattern (very unsafe)
Use Case ExampleCast between unrelated pointer types

Description:

  • Performs a bit-level reinterpretation of a value.
  • Use to convert between unrelated pointer types, int to pointer, etc.
  • Does no type safety checking — purely syntactic conversion.

Example:

int x = 42;
char* p = reinterpret_cast<char*>(&x);  // Treat int as char array
void* vptr = malloc(8);
long* lptr = reinterpret_cast<long*>(vptr);  // From void* to unrelated type

⚠️ Caution:

  • Can lead to undefined behavior if misused.
  • Often used in low-level code, device drivers, or serialization/deserialization.

Summary Table

OperatorSafe?Runtime Checked?Use Case
static_cast✔️ Yes❌ NoBasic conversions between related types
dynamic_cast✔️ Yes✔️ YesDowncasting in polymorphic hierarchies
const_cast✔️/⚠️❌ NoRemove const, use cautiously
reinterpret_cast⚠️ No❌ NoRaw, low-level bit reinterpretation