C++는 C 스타일 캐스트 대신 목적에 따라 네 가지 명시적 캐스트 연산자를 제공합니다. 각 연산자는 서로 다른 상황에서 사용되도록 설계되었으며, 적절한 캐스트를 선택하면 코드의 의도가 명확해지고 컴파일러가 오류를 더 잘 잡아낼 수 있습니다.
const_cast — const 속성의 추가 및 제거
const_cast는 변수에서 const 또는 volatile 속성을 제거하거나 추가할 때 사용하는 유일한 캐스트입니다. 예를 들어, const로 선언된 객체를 받아야 하는 레거시 API에 non-const 포인터를 전달해야 하는 경우 등, const성(constness)을 조정해야 할 때 유용합니다.
다만 주의할 점이 있습니다. 원본 객체 자체가 const로 선언된 경우 이를 통해 값을 수정하는 것은 미정의 동작(undefined behavior)을 유발합니다. 따라서 const_cast는 실제로 수정 가능한 객체를 다룰 때만 신중하게 사용해야 합니다.
static_cast — 일반적인 타입 변환
static_cast는 가장 일상적으로 사용되는 캐스트로, 컴파일 시점에 검증 가능한 정상적인 타입 변환을 담당합니다. 암묵적 형 변환(implicit coercion)과 동일한 변환을 명시적으로 수행할 때도 활용됩니다.
대표적인 사용 사례는 다음과 같습니다.
float→int,double→float같은 산술 타입 변환char→int,enum→ 정수형 변환void*→ 구체적인 포인터 타입으로의 변환- 기본 클래스 → 파생 클래스로의 업캐스트(upcast)
static_cast는 컴파일러가 변환의 유효성을 검사하기 때문에, C 스타일 캐스트보다 훨씬 안전하고 의도가 분명하게 드러납니다.
dynamic_cast — 다형성 클래스 계층에서의 안전한 다운캐스트
dynamic_cast는 다형적(polymorphic) 타입, 즉 최소 하나 이상의 가상 함수를 가진 클래스 계층에서 사용됩니다. 특히 기본 클래스 포인터나 참조를 파생 클래스로 변환하는 다운캐스트(downcast)에만 필요합니다.
dynamic_cast의 핵심 장점은 런타임 타입 검사입니다. 포인터 캐스트가 실패하면 nullptr을 반환하고, 참조 캐스트가 실패하면 std::bad_cast 예외를 던지므로 잘못된 변환을 안전하게 처리할 수 있습니다. 반면 static_cast로 다운캐스트하면 실제 객체 타입이 맞는지 검증되지 않아 위험합니다.
단, 런타임 타입 정보(RTTI) 조회 비용이 발생하므로 성능이 중요한 코드에서는 남용하지 않는 것이 좋습니다.
reinterpret_cast — 저수준 비트 재해석
reinterpret_cast는 네 가지 캐스트 중 가장 까다롭고 위험한 연산자입니다. 이름 그대로 비트 패턴(bit pattern)을 그대로 다른 타입으로 재해석하며, 거의 모든 타입 검사를 우회하는 극히 저수준(low-level) 도구입니다.
주요 용도는 다음과 같습니다.
- 원시(raw) 데이터 비트 스트림을 실제 데이터 타입으로 변환
- 정렬된(aligned) 포인터의 하위 비트에 메타데이터 저장
- 포인터와 정수형 간의 변환 등 하드웨어/네트워크 프로그래밍 작업
잘못 사용하면 즉시 미정의 동작으로 이어질 수 있으므로, 시스템 프로그래밍이나 직렬화(serialization)처럼 불가피한 경우에만 사용하고, 그 외에는 static_cast나 다른 안전한 방법을 먼저 고려해야 합니다.
정리: 어떤 캐스트를 선택해야 할까?
- const_cast: const/volatile 속성을 추가하거나 제거할 때
- static_cast: float→int 변환처럼 컴파일 시점에 검증 가능한 일반적인 타입 변환
- dynamic_cast: 다형적 기본 클래스에서 파생 클래스로 안전하게 다운캐스트할 때
- reinterpret_cast: 비트 패턴 재해석 등 극히 저수준의 작업이 필요할 때
기본 원칙은 가장 좁은 범위의 캐스트를 선택하는 것입니다. 대부분의 경우 static_cast로 충분하며, dynamic_cast는 상속 계층에서만, reinterpret_cast는 정말 필요할 때만 사용하는 것이 좋은 C++ 코드의 첫걸음입니다.