Post

C++의 형변환(캐스팅, Casting)에 대하여

캐스팅의 종류

1. 암시적(Implicit) 캐스팅

  • 컴파일러가 자동으로 형 변환을 수행

    합니다.

    • 단, 변환이 허용되는 범위 내에서만 가능합니다.
    • 프로그래머가 명시적으로 형 변환을 작성하지 않은 경우 발생합니다.

2. 명시적(Explicit) 캐스팅

  • 프로그래머가 직접 형 변환 코드를 작성합니다.
  • C++에서 제공하는 명시적 캐스팅:
    1. static_cast
    2. const_cast
    3. dynamic_cast (C++98 이후 도입)
    4. reinterpret_cast

C 스타일 캐스팅

1
2
double a = 1.354;
int b = (int)a;
  • C 스타일 캐스팅은 C++의 네 가지 캐스팅 중 하나를 수행합니다.
    • 하지만 어떤 캐스팅이 수행될지 명확하지 않습니다.
  • 컴파일러가 명백한 실수를 잡아내지 못할 가능성이 있습니다.
  • 이러한 문제를 해결하기 위해 C++ 스타일 캐스팅이 도입되었습니다.
    • 실행 성능에는 C/C++ 모두 차이가 없습니다. (기계어 수준에서는 동일)

C++ 캐스팅의 종류

1. static_cast

용도

  • 두 숫자 형 간 변환:
    • 값을 유지하나, 반올림 오차가 발생할 수 있습니다.
    • 이진수 표기가 달라질 수 있습니다.
      • (예: floatint)
  • 포인터 간 변환:
    • 변수형 체크 후 베이스 클래스를 파생 클래스로 변환
    • 형식적 문법만 검사합니다.
      • 변환하려는 형(Type)과 변환 하려는 포인터 변수의 형(Type) 간의 상속 관계만 검사한다.
      • 변환 하려는 포인터가 실제로 가리키는 객체에 대한 형에 대해서는 검사하지 않습니다.

주의점

  • 런타임 타입 검사를 수행하지 않으며, 변환된 포인터가 실제로 올바른 객체를 가리키는지 확인하지 않습니다.
  • 잘못된 변환으로 인해 정의되지 않은 동작(예: 메모리 접근 오류, 프로그램 크래시)이 발생할 수 있습니다.

2. reinterpret_cast

용도

  • 포인터와 비포인터 간 변환:
    • 예: Cat*unsigned int.
  • 연관이 없는 두 포인터 간 변환:
    • 예: Cat*House*.
    • 예: char*int*
  • 이진수 표기를 그대로 유지하며, 단순히 형식을 바꾸는 작업입니다.

주의점

  • 변환 후 데이터가 실제로 의미를 가지는지는 프로그래머가 보장해야 합니다.
  • 잘못된 사용 시, 심각한 버그와 프로그램 크래시가 발생할 수 있습니다.

3. const_cast

용도

  • const 또는 volatile 속성을 제거합니다.
    • 예: const int*int*.
  • 주로 포인터 타입에 사용하는 것이 권장됩니다.

주의점

  • const_cast로 형을 변경할 수는 없습니다.

  • 값 타입에는 권장되지 않습니다. 값이 복사되기 때문에 const 제거가 필요하지 않습니다.

  • 일반적으로 const_cast써드파티 라이브러리가 const를 잘못 사용하는 경우에만 사용됩니다.

    • const_cast 사용이 필요하다면 설계 자체를 다시 검토해보아야 합니다.

4. dynamic_cast

용도

  • 런타임에 타입 검사를 수행하며, RTTI(Run-Time Type Information)를 사용합니다.
  • 포인터 또는 참조 타입 간 캐스팅에만 사용 가능합니다.

  • 변환이 올바르지 않은 경우:
    • 포인터 변환: nullptr 반환.
    • 참조 변환: std::bad_cast 예외 발생.

주의점

  1. RTTI가 활성화되어야 합니다.
    • RTTI는 런타임 성능에 영향을 미칠 수 있어 일반적으로는 비활성화 합니다.
    • RTTI가 비활성화된 경우, dynamic_caststatic_cast처럼 동작합니다.
  2. 가상 함수가 정의된 클래스에서만 동작합니다.
    • 클래스가 가상 함수 테이블(vtable)을 포함해야 하며, 이를 위해 가상 소멸자나 기타 가상 함수를 명시해야 합니다.

캐스팅 가이드라인

  1. 기본적으로 staitc_cast를 쓸 것
    • reinterpret_cast<Cat*> 대신 static_cast<Cat*>
      • 만약 CatAnimal이 아니라면 컴파일러가 에러를 뱉음
  2. 필요한 경우 reinterpret_cast를 쓸것
    • 포인터와 비포인터 사이의 변환
      • 이걸 정말 해야 할 때가 있음 (ex. 포인터 주소의 저장)
    • 서로 연관이 없는 포인터 사이의 변환은 그 데이터형이 맞다고 정말 확신할 때만 할 것
  3. 내가 변경 권한이 없는 외부 라이브러리를 호출할 때만 const_cast를 쓸 것
This post is licensed under CC BY 4.0 by the author.