Type Casting in C++
Type casting means converting a value from one data type to another. Think of it like pouring water from a wide jug into a narrow bottle — the liquid changes its container but it is still the same water. In C++, you sometimes need to treat an integer as a decimal number, or a large number as a smaller one. Type casting makes this possible.
C++ supports two broad categories of type casting: implicit casting (done automatically by the compiler) and explicit casting (done manually by the programmer).
Implicit Type Casting
Implicit casting happens automatically when the compiler converts one type to a compatible, wider type. No extra code is needed. This is also called type promotion.
#include <iostream>
using namespace std;
int main() {
int a = 5;
double b = a; // int automatically becomes double
cout << b << endl;
return 0;
}
Output:
5
The compiler moved from a smaller type (int) to a larger type (double) without losing any information. This is always safe.
Implicit Promotion Order
char → int → long → float → double
Data always promotes from left to right automatically. Going right to left can lose data — that requires explicit casting.
Explicit Type Casting
When you want to convert from a larger type to a smaller one (or between unrelated types), you must cast explicitly. There are two ways to do this in C++.
C-Style Cast
#include <iostream>
using namespace std;
int main() {
double price = 9.99;
int rounded = (int)price; // C-style cast
cout << rounded << endl;
return 0;
}
Output:
9
The decimal part is cut off. The value is not rounded — it is truncated (chopped). This is important to remember.
Functional Cast (C++ Style)
int rounded = int(price); // same result, C++ notation
C++ Named Cast Operators
C++ introduced four special cast operators that are safer and clearer than the old C-style cast. Each one has a specific purpose.
Diagram: Cast Operator Purposes
┌─────────────────────┬──────────────────────────────────────────┐
│ Cast Operator │ Use Case │
├─────────────────────┼──────────────────────────────────────────┤
│ static_cast │ Safe conversions between related types │
│ dynamic_cast │ Safe downcast in class hierarchies (OOP) │
│ const_cast │ Add or remove const qualifier │
│ reinterpret_cast │ Reinterpret raw bits — low-level casting │
└─────────────────────┴──────────────────────────────────────────┘
static_cast
static_cast is the most commonly used cast. It handles conversions between numeric types, and between related class pointers.
#include <iostream>
using namespace std;
int main() {
double score = 95.7;
int marks = static_cast<int>(score);
cout << "Marks: " << marks << endl;
int total = 7;
int got = 3;
double ratio = static_cast<double>(got) / total;
cout << "Ratio: " << ratio << endl;
return 0;
}
Output:
Marks: 95
Ratio: 0.428571
Without the cast in the ratio line, integer division would give 0 because 3 / 7 rounds down to zero in integer math.
dynamic_cast
dynamic_cast is used in object-oriented programming when you work with base and derived class pointers. It checks at runtime whether the conversion is valid.
#include <iostream>
using namespace std;
class Animal {
public:
virtual void speak() {}
};
class Dog : public Animal {
public:
void fetch() { cout << "Dog fetches!" << endl; }
};
int main() {
Animal* a = new Dog();
Dog* d = dynamic_cast<Dog*>(a);
if (d != nullptr) {
d->fetch();
}
delete a;
return 0;
}
Output:
Dog fetches!
const_cast
const_cast removes or adds the const qualifier from a variable. This is useful when you need to pass a constant value to a function that does not accept const parameters.
#include <iostream>
using namespace std;
void printValue(int* p) {
cout << *p << endl;
}
int main() {
const int val = 42;
printValue(const_cast<int*>(&val));
return 0;
}
Output:
42
reinterpret_cast
reinterpret_cast is the most powerful and most dangerous cast. It reinterprets the raw bit pattern of a value as a different type. Use it only in low-level system programming.
#include <iostream>
using namespace std;
int main() {
int num = 65;
char* ch = reinterpret_cast<char*>(&num);
cout << *ch << endl; // prints 'A' (ASCII 65)
return 0;
}
Output:
A
Data Loss During Casting
Casting from a larger type to a smaller one can cause data loss. Always be aware of this risk.
#include <iostream>
using namespace std;
int main() {
double pi = 3.14159;
int truncated = static_cast<int>(pi);
cout << "Original: " << pi << endl;
cout << "After cast: " << truncated << endl;
return 0;
}
Output:
Original: 3.14159
After cast: 3
Diagram: What Happens to Data
double → int
3.14159 → 3 (decimal part LOST)
int → char
300 → 44 (only last 8 bits kept, overflow!)
Casting Characters and Integers
Characters in C++ are stored as their ASCII numeric values. You can cast between char and int freely.
#include <iostream>
using namespace std;
int main() {
char letter = 'A';
int ascii = static_cast<int>(letter);
cout << "ASCII of A: " << ascii << endl;
int code = 98;
char ch = static_cast<char>(code);
cout << "Char for 98: " << ch << endl;
return 0;
}
Output:
ASCII of A: 65
Char for 98: b
When to Use Which Cast
| Situation | Recommended Cast |
|---|---|
| int to double or double to int | static_cast |
| Base class pointer to derived class pointer | dynamic_cast |
| Remove const from a pointer | const_cast |
| Pointer to integer address or bit-level work | reinterpret_cast |
Key Takeaways
- Implicit casting happens automatically from smaller to larger types.
- Explicit casting must be done manually when converting from larger to smaller types.
static_castis the safest and most common explicit cast for numeric types.- Casting from a wider type to a narrower type can cause data loss.
- C++ named casts are more readable and safer than the old C-style cast.
