C++ 4대 캐스팅 방법

mingu Lee·2025년 11월 26일

CS

목록 보기
6/21

1. static_cast


가장 일반적이고 안전한 캐스팅 방법이다.

  • 용도:
    • 서로 관련된 타입 간의 변화 (int \leftrightarrow float, 열거형 \leftrightarrow 정수)
    • 상속 관계 내에서 업캐스팅 (파생 클래스 \to 기본 클래스)은 안전하며, 명시적 캐스팅 없이도 가능
    • 다운캐스팅 (기본 클래스 \to 파생 클래스)은 컴파일 시점에 타입 체크를 하지 않기 때문에 안전하지 않으며 사용에 주의가 필요 (런타임에 잘못된 객체를 가리킬 수 있음)
  • 특징:
    • 컴파일 타임에 변환을 수행하며, 런타임 검사는 수행하지 않음
  • 예시:
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는 캐스팅을 강제하는 것과 같기 때문에, 실제 객체 타입과 요청한 타입이 일치하지 않는 다운캐스팅 상황을 조심해야 한다.

2. dynamic_cast


상속 관계에서 안전한 다운캐스팅을 수행할 때 사용한다.

가상 함수를 하나라도 가진 클래스에서만 사용할 수 있다.

왜냐하면 dynamic_cast런타임 타입 정보(RTTI)를 사용해야 하는데, C++ 표준 구현체들은 이 RTTI 정보를 가상 함수 테이블(vtable)에 저장한다.

따라서 vtable을 가지지 않는 클래스(가상 함수가 없는 클래스)에서는 dynamic_cast를 사용할 수 없다.

  • 용도:
    • 다운캐스팅 (기본 클래스 \to 파생 클래스)을 런타임에 안전하게 수행
    • 변환이 성공적인지 확인하기 위해 런타임 타입 정보(RTTI)를 사용
  • 특징:
    • 변환이 성공하면 올바른 포인터/참조를 반환
    • 변환이 실패하면 포인터의 경우 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
}

3. const_cast


변수의 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이므로 이는 위험한 동작

4. reinterpret_cast


가장 위험하고 특정 용도에만 사용되는 캐스팅이다.

주로 서로 관련 없는 타입 간에 포인터 비트를 그대로 복사할 때 사용된다.

  • 용도:
    • 포인터 타입 \leftrightarrow 정수 타입 변환 (예: 메모리 주소 \leftrightarrow int / long)
    • 서로 완전히 다른 타입의 포인터 간 변환 (예: int \to char)
    • Byte 데이터를 다루거나 하드웨어 인터페이스를 직접 제어하는 등 저수준(low-level) 프로그래밍에서 사용
  • 특징:
    • 변환 과정에서 어떤 타입 검사나 데이터 변환도 수행하지 않고, 단순히 비트 패턴을 재해석
  • 예시:
int i = 65;
void* vptr = &i;

// void* 포인터를 char* 포인터로 재해석
char* cptr = reinterpret_cast<char*>(vptr);

// 포인터 주소를 정수 타입으로 변환
long address = reinterpret_cast<long>(cptr);
profile
Github: https://github.com/dlalsrn

0개의 댓글