가장 일반적이고 안전한 캐스팅 방법이다.
int float, 열거형 정수)int i = 10;
double d = static_cast<double>(i); // int -> double 변환
class Base {};
class Derived : public Base {};
Derived* dp = new Derived();
Base* bp = static_cast<Base*>(dp); // 안전한 업캐스팅
반면 다운캐스팅의 경우 런타임에 클래스 타입을 확인하지 않기 때문에 다음과 같은 상황에서 문제가 발생한다.
class Base {};
class Derived : public Base {};
Base* bp = new Base();
Derived* dp = static_cast<Derived*>(bp); // 타입이 맞지 않는 다운캐스팅
if (dp) {
dp->...
}
cast가 되어 dp가 유효한 포인터처럼 보이지만, 실제로는 Derived 타입이 아니기 때문에 dp->로 접근하여 Derived 클래스의 멤버 함수/변수를 사용하면 잘못된 값이 출력되거나 에러가 발생한다.
즉, static_cast는 캐스팅을 강제하는 것과 같기 때문에, 실제 객체 타입과 요청한 타입이 일치하지 않는 다운캐스팅 상황을 조심해야 한다.
상속 관계에서 안전한 다운캐스팅을 수행할 때 사용한다.
가상 함수를 하나라도 가진 클래스에서만 사용할 수 있다.
왜냐하면 dynamic_cast는 런타임 타입 정보(RTTI)를 사용해야 하는데, C++ 표준 구현체들은 이 RTTI 정보를 가상 함수 테이블(vtable)에 저장한다.
따라서 vtable을 가지지 않는 클래스(가상 함수가 없는 클래스)에서는 dynamic_cast를 사용할 수 없다.
nullptr을 반환하고, 참조의 경우 std::bad_cast 예외를 발생class Base { public: virtual ~Base() {} };
class Derived : public Base {};
Base* bp = new Derived();
// 안전한 다운캐스팅 시도
Derived* dp = dynamic_cast<Derived*>(bp);
if (dp) {
// 성공적으로 변환됨
}
반면 다음과 같은 상황에는 객체의 실제 타입이 요청한 파생 클래스가 아니기 때문에 nullptr이 반환된다.
class Base { public: virtual ~Base() {} };
class Derived : public Base {};
Base* bp = new Base();
// 타입이 맞지 않는 다운캐스팅 시도
Derived* dp = dynamic_cast<Derived*>(bp);
if (dp) {
// nullptr이 반환되어 조건문 실행 X
}
변수의 const 또는 volatile 속성을 제거하거나 추가하는 방법이다.
const 객체를 인수로 받지 않는 외부 레거시 함수에 const 객체를 전달해야 할 때 사용const로 선언된 원래 객체의 값을 const_cast를 사용하여 수정하는 것은 예상치 못한 일을 유발할 수 있으므로, 일반적으로 읽기 전용 액세스 권한을 얻는 용도로만 사용해야 함const int value = 10;
const int* ptr = &value;
// const 속성 제거
int* mutable_ptr = const_cast<int*>(ptr);
// *mutable_ptr = 20; // 원래 변수 'value'는 const이므로 이는 위험한 동작
가장 위험하고 특정 용도에만 사용되는 캐스팅이다.
주로 서로 관련 없는 타입 간에 포인터 비트를 그대로 복사할 때 사용된다.
int i = 65;
void* vptr = &i;
// void* 포인터를 char* 포인터로 재해석
char* cptr = reinterpret_cast<char*>(vptr);
// 포인터 주소를 정수 타입으로 변환
long address = reinterpret_cast<long>(cptr);