C++ Casting | 'static_cast/dynamic_cast' Complete Guide to 4 Types
이 글의 핵심
C++ casting complete guide: static_cast, dynamic_cast, const_cast, reinterpret_cast with principles and practical examples.
1. static_cast
Purpose: Compile-time type conversion
Here is the Base implementation:
// Basic type conversion
int x = 10;
double y = static_cast<double>(x);
// Pointer upcasting (safe)
class Base {};
class Derived : public Base {};
Derived* d = new Derived();
Base* b = static_cast<Base*>(d); // OK
// Pointer downcasting (dangerous)
Base* b2 = new Base();
Derived* d2 = static_cast<Derived*>(b2); // Compiles but dangerous!
When to Use:
- Basic type conversion
- Explicit type conversion
- Upcasting
2. dynamic_cast
Purpose: Runtime safe downcasting
Here is the derivedMethod implementation:
class Base {
public:
virtual ~Base() {} // Virtual function required!
};
class Derived : public Base {
public:
void derivedMethod() {
cout << "Derived method" << endl;
}
};
int main() {
Base* b = new Derived();
// Safe downcasting
Derived* d = dynamic_cast<Derived*>(b);
if (d) {
d->derivedMethod(); // Success
} else {
cout << "Cast failed" << endl;
}
// Failure example
Base* b2 = new Base();
Derived* d2 = dynamic_cast<Derived*>(b2);
if (!d2) {
cout << "Cast failed" << endl; // Printed
}
}
When to Use:
- Downcasting
- Type checking needed
- RTTI (Run-Time Type Information) required
3. const_cast
Purpose: Remove/add const qualifier
Here is the legacyFunction implementation:
void legacyFunction(char* str) {
// Legacy function without const
}
void modernFunction(const char* str) {
// Remove const (dangerous!)
legacyFunction(const_cast<char*>(str));
}
// Add const
int main() {
int x = 10;
const int* ptr = const_cast<const int*>(&x);
}
Warning: Modifying originally const object is undefined behavior!
4. reinterpret_cast
Purpose: Reinterpret pointer as different type
The following example demonstrates the concept in cpp:
int x = 42;
int* ptr = &x;
// Pointer to integer
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
cout << "Address: " << addr << endl;
// Integer to pointer
int* ptr2 = reinterpret_cast<int*>(addr);
// Pointer type conversion (dangerous!)
double* dptr = reinterpret_cast<double*>(ptr);
When to Use:
- Low-level programming
- Hardware access
- Serialization/deserialization
C-style Cast vs C++ Cast
The following example demonstrates the concept in cpp:
// ❌ C-style (dangerous)
int x = 10;
double y = (double)x;
Base* b = new Derived();
Derived* d = (Derived*)b; // Unclear which cast
// ✅ C++ style (clear)
double y2 = static_cast<double>(x);
Derived* d2 = dynamic_cast<Derived*>(b);
Practical Examples
Example 1: Polymorphism and dynamic_cast
Here is the draw implementation:
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() {}
};
class Circle : public Shape {
public:
void draw() override { cout << "Circle" << endl; }
double getRadius() { return 5.0; }
};
class Rectangle : public Shape {
public:
void draw() override { cout << "Rectangle" << endl; }
double getWidth() { return 10.0; }
};
void processShape(Shape* shape) {
shape->draw();
// Check if Circle
if (Circle* circle = dynamic_cast<Circle*>(shape)) {
cout << "Radius: " << circle->getRadius() << endl;
}
// Check if Rectangle
if (Rectangle* rect = dynamic_cast<Rectangle*>(shape)) {
cout << "Width: " << rect->getWidth() << endl;
}
}
int main() {
Shape* shapes[] = {
new Circle(),
new Rectangle()
};
for (Shape* shape : shapes) {
processShape(shape);
delete shape;
}
}
Example 2: Serialization
Here is the serialize implementation:
#include <cstring>
struct Data {
int id;
double value;
};
void serialize(const Data& data, char* buffer) {
// Struct to byte array
memcpy(buffer, &data, sizeof(Data));
}
Data deserialize(const char* buffer) {
Data data;
memcpy(&data, buffer, sizeof(Data));
return data;
}
int main() {
Data original = {42, 3.14};
char buffer[sizeof(Data)];
serialize(original, buffer);
Data restored = deserialize(buffer);
cout << restored.id << ", " << restored.value << endl;
}
Example 3: Plugin System
Here is the execute implementation:
class Plugin {
public:
virtual void execute() = 0;
virtual ~Plugin() {}
};
class AudioPlugin : public Plugin {
public:
void execute() override { cout << "Audio processing" << endl; }
void setVolume(int v) { volume = v; }
private:
int volume = 100;
};
void configurePlugin(Plugin* plugin) {
// Check if AudioPlugin and set volume
if (AudioPlugin* audio = dynamic_cast<AudioPlugin*>(plugin)) {
audio->setVolume(80);
}
}
Common Problems
Problem 1: Ignoring dynamic_cast Failure
The following example demonstrates the concept in cpp:
// ❌ Dangerous
Base* b = new Base();
Derived* d = dynamic_cast<Derived*>(b);
d->derivedMethod(); // Crash! (d is nullptr)
// ✅ Check
if (Derived* d = dynamic_cast<Derived*>(b)) {
d->derivedMethod();
} else {
cout << "Cast failed" << endl;
}
Problem 2: const_cast Abuse
The following example demonstrates the concept in cpp:
// ❌ Undefined behavior
const int x = 10;
int* ptr = const_cast<int*>(&x);
*ptr = 20; // Dangerous!
// ✅ Only when originally non-const
int y = 10;
const int* cptr = &y;
int* ptr2 = const_cast<int*>(cptr);
*ptr2 = 20; // OK
Problem 3: reinterpret_cast Misuse
The following example demonstrates the concept in cpp:
// ❌ Alignment issue
int x = 42;
double* dptr = reinterpret_cast<double*>(&x);
// *dptr; // Possible crash!
// ✅ Same size, same alignment
uint32_t u = 42;
int32_t* iptr = reinterpret_cast<int32_t*>(&u); // OK
Casting Selection Guide
Need type conversion?
├─ Basic type conversion? → static_cast
├─ Downcasting?
│ ├─ Safety needed? → dynamic_cast
│ └─ Performance critical? → static_cast (careful!)
├─ Remove const? → const_cast (careful!)
└─ Pointer reinterpretation? → reinterpret_cast (dangerous!)
Performance Comparison
// static_cast: Compile-time, no overhead
Derived* d1 = static_cast<Derived*>(base);
// dynamic_cast: Runtime type check, slightly slower
Derived* d2 = dynamic_cast<Derived*>(base);
FAQ
Q1: Which cast should I use?
A:
- First try without cast
- static_cast (most common)
- dynamic_cast (downcasting)
- const_cast (legacy code)
- reinterpret_cast (low-level)
Q2: Why is C-style cast bad?
A:
- Unclear which cast type
- Hard to search
- Unintended conversions possible
Q3: Why is dynamic_cast slow?
A: Uses RTTI to check type at runtime.
Q4: dynamic_cast without virtual function?
A: Impossible. Virtual function needed to enable RTTI.
Q5: How to avoid casting?
A:
- Use virtual functions
- Use templates
- Good design
Q6: Debugging casts?
A:
- Check dynamic_cast return value
- Use assert
- Add logging
Related Posts
- C++ Type Conversion Guide
- C++ constexpr Lambda Guide
- C++ Extern Linkage Guide
- C++ Adapter Pattern Complete Guide