static_cast

Jaemyeong Lee·2024년 11월 7일
0

FastCampusC++

목록 보기
75/78

코드를 한 줄 한 줄 자세히 분석하여 설명드리겠습니다. 이 예제는 static_cast를 활용한 다양한 형변환을 다루고 있습니다.

클래스 및 열거형 정의

class ClassA {};
class ClassB {};
  • ClassAClassB는 변환 테스트용 빈 클래스를 정의한 것입니다.
enum class TypeA
{
    A, B, C
};

enum class TypeB
{
    A, B, C
};
  • 두 개의 열거형 클래스 TypeATypeB를 정의했습니다. 각각 A, B, C라는 값이 있으며, 열거형 간 변환을 static_cast로 수행해 볼 수 있습니다.

Test 클래스

class Test
{
public:
    Test(int num) {}
    explicit Test(int num0, int num1) {}

    operator bool() const
    {
        return true;
    }

    explicit operator double() const
    {
        return 1.2;
    }
};
  • Test 클래스는 다양한 변환을 테스트하기 위해 두 개의 생성자와 형변환 연산자(operator bool()operator double())를 정의합니다.
  • explicit 키워드를 통해 두 번째 생성자와 operator double()명시적 변환으로 제한하여, 직접 호출하지 않으면 암시적 변환이 일어나지 않도록 했습니다.

클래스 계층 구조

class Parent {};
class Child : public Parent {};
  • Parent와 이를 상속받는 Child 클래스를 정의했습니다. 이를 통해 상속 관계에서의 다운캐스팅을 시도할 수 있습니다.

main 함수 분석

C 스타일 캐스트와 static_cast 비교

float f = 1.1f;
int* i0 = (int*)&f; // C 스타일 캐스트: float 포인터를 int 포인터로 변환 (위험할 수 있음)
int* i1 = static_cast<int*>(&f); // 컴파일 오류 발생
  • float 타입 변수 f의 주소를 int* 타입으로 변환하려고 합니다.
  • C 스타일 캐스트 (int*)&f는 이 변환을 허용하지만, 위험한 방식입니다. 이는 원래 타입이 아닌 int*로 접근하는 동작이기 때문입니다.
  • static_cast<int*>(&f)컴파일러에서 허용되지 않습니다. static_cast는 호환되지 않는 포인터 타입 간 변환을 막아주기 때문에 컴파일 오류가 발생합니다.

ClassA a;
ClassB* b = (ClassB*)&a; // C 스타일 캐스트는 허용됨
//ClassB* b = static_cast<ClassB*>(&a);  // 컴파일 타임에 오류
  • ClassA의 인스턴스를 ClassB*로 변환하려고 합니다.
  • C 스타일 캐스트 (ClassB*)&a는 허용하지만, 메모리 안전성을 보장하지 않는 위험한 변환입니다.
  • static_cast<ClassB*>(&a)는 호환되지 않는 타입 간 변환을 막기 때문에 컴파일 타임 오류가 발생합니다.

static_cast로 열거형과 정수 간 변환

TypeA type0 = static_cast<TypeA>(0); // 정수를 TypeA로 변환
TypeB type1 = static_cast<TypeB>(type0); // 다른 enum끼리 변환 가능
  • static_cast를 사용하여 int 값을 TypeA 열거형으로 변환합니다. 열거형 값과 정수는 호환되므로 가능합니다.
  • type0TypeB로 변환할 때도 static_cast를 사용하며, 열거형 간 변환도 가능합니다.

생성자를 통한 Test 객체 생성

Test t0 = static_cast<Test>(1); // 변환 생성자 호출
Test t1 = static_cast<Test>(1, 2); // 컴파일 에러: 명시적 생성자
  • static_cast<Test>(1)은 첫 번째 생성자 Test(int)를 호출하여 객체를 생성합니다.
  • static_cast<Test>(1, 2)explicit로 정의된 두 번째 생성자 Test(int, int)를 호출하려고 합니다. explicit 생성자는 암시적 형변환이 금지되어 있으므로, static_cast로는 호출할 수 없고 컴파일 에러가 발생합니다.

변환 연산자 호출

bool b0 = static_cast<bool>(t0); // bool 형변환 연산자 호출
double d0 = static_cast<double>(t1); // double 형변환 연산자 호출
  • static_cast<bool>(t0)operator bool()을 호출하여 bool 타입으로 변환합니다.
  • static_cast<double>(t1)explicit operator double()을 호출합니다. explicit이라도 static_cast를 통해 명시적 변환을 허용합니다.

상속 관계에서의 형변환

Child c;
Parent& p0 = c;
Child& c0 = static_cast<Child&>(p0); // 부모 -> 자식 다운캐스팅 (가능하지만 위험할 수 있음)
  • Parent& p0 = c;는 자식 Child 타입을 부모 Parent 타입 참조로 변환하는 암시적 업캐스팅입니다.
  • static_cast<Child&>(p0)는 부모를 자식으로 다운캐스팅하는 예로, 상속 관계가 성립하므로 컴파일되지만, 런타임 시 실제로 p0Child 객체를 가리키고 있지 않다면 정의되지 않은 동작을 일으킬 수 있습니다.

정의되지 않은 동작을 유발하는 다운캐스팅 예

Parent p1;
Child& c1 = static_cast<Child&>(p1); // 컴파일은 되지만 런타임에서 정의되지 않은 동작
  • 여기서는 Parent 객체 p1Child&로 다운캐스팅했습니다. p1은 실제로 Child 타입이 아니기 때문에, 런타임에서 심각한 오류가 발생할 수 있습니다.
  • 이러한 경우 dynamic_cast를 사용하는 것이 더 안전하며, 잘못된 캐스팅을 런타임에 잡아낼 수 있습니다. dynamic_cast는 타입 안전성을 검사하기 때문에 이런 상황에서 예외를 발생시킬 수 있습니다.
profile
李家네_공부방

0개의 댓글