개인 공부/c++

C++ Type Casting

Sanyo 2024. 6. 5. 13:39

type casting 종류

 

묵시적 형 변환

자동 변환을 말한다. 예를 들어

int main(){
    float a = 3.4f;
    int b;

    b = a;

    cout << b << endl;
}

위 코드를 실행하면 3이 출력된다.

 

위 코드에서 3.4가 3으로 자동 변환되었다.

 

명시적 형 변환

직접 형변환을 지정해 주는 것을 말한다.

(int), (float)등으로 지정해 준다.

int main(){
    float a = 3.4f;
    int b;

    b = (int) a;

    cout << b << endl;
}

 

 

c++ 에는 Cast Operator라고 하는 형변환이 따로 있다.

1. static_cast

2. const_cast

3. reinterpret_cast

4. dynamic_cast

 

 

 

static_cast

사용법: static_cast<type>(expression)

 

int main(){
    float a = 3.4f;
    int b;

    b = static_cast<int>(a);

    cout << b << endl;
}

정수 외에도 많은 것을 변환 가능하다.

 

논리적으로 변경이 가능하면 거의 모든 경우에서 변경해준다.

 

하지만 서로 다른 타입의 포인터 끼리는 타입 변환이 불가능하다.

 

Reinterpret Casting

사용법: reinterpret_cast<type>(expression)

Reinterpret : 재해석

- 값에 대한 type casting은 불가능하고,

- Pointer에 대한 type casting을 위한 것이다.

예를 들면 int*를 char*로 변경할 수 있다.

 

#include <iostream>
using namespace std;

int main(){
    int number = 12345;
    int* intPointer = &number;

    cout << *intPointer << endl;

    // int* to char*
    char* charPointer = reinterpret_cast<char*>(intPointer);

    // 변환된 포인터를 이용한 메모리 접근
    for (int i = 0; i < sizeof(int); ++i) {
        std::cout << "Byte " << i << ": " << static_cast<int>(charPointer[i]) << std::endl;
    }

    int* intPointerAgain = reinterpret_cast<int*>(charPointer);

    cout << *intPointer << endl;
    
}

 

위 코드에서는 12345로 테스트를 진행한다. int가 char로 변경될때는 바이트 단위로 나누어지게 된다. int는 4바이트, char는 1바이트이다. 

12345를 16진수로 나타내면, 4바이트이므로 8자리가 나오게 되고, 0x00003039이다. 이걸 1바이트씩 나누면 0x30, 0x39이므로 위 코드 실행결과는 

12345
Byte 0: 57
Byte 1: 48
Byte 2: 0
Byte 3: 0
12345

와 같이 나오게 된다.

 

Const casting

const casting은 객체의 상수성을 제거 또는 추가하는데 사용된다.

 

#include <iostream>

void modifyValue(const int* ptr) {
    // const_cast를 사용하여 const를 제거
    int* nonConstPtr = const_cast<int*>(ptr);
    *nonConstPtr = 20; // 이제 값을 수정할 수 있습니다.
}

int main() {
    int x = 10;
    const int* ptr = &x;
    
    std::cout << "Before modifyValue: " << x << std::endl;
    modifyValue(ptr);
    std::cout << "After modifyValue: " << x << std::endl;
    
    return 0;
}

위 코드는 const_cast를 통해 객체의 상수성을 제거하는 과정을 나타낸다. 

또는 상수성을 추가할 수도 있는데, 이는 좀 일반적이지 않기에 여기서는 다루지 않겠다.

 

dynamic casting

dynamic casting은 객체의 형 변환에서 사용된다.

 

다음 예제를 살펴보자.

 

#include <iostream>
#include <typeinfo>  // for 'std::bad_cast'

class Base {
public:
    virtual ~Base() {}  // 다형성을 위해 가상 소멸자 선언
};

class Derived : public Base {
public:
    void sayHello() const {
        std::cout << "Hello from Derived!" << std::endl;
    }
};

위 예제에는 Base 클래스와 이를 상속하는 Derived 클래스가 있다.

 

int main() {
    Base* basePtr = new Derived();  // 업캐스팅 (Derived* -> Base*)

    // 다운캐스팅 (Base* -> Derived*)
    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);

    if (derivedPtr != nullptr) {
        derivedPtr->sayHello();  // 다운캐스팅 성공 시 메서드 호출
    } else {
        std::cout << "dynamic_cast 실패: basePtr을 Derived*로 변환할 수 없습니다." << std::endl;
    }

    delete basePtr;
    return 0;
}

위 예제는 성공적으로 작동하게 된다.

 

주의할 점이 있다. 위 코드에서 basePtr은 원래 Derived 객체를 가르켰기에 basePtr이 Derived*타입으로 변환될 수 있었던 것이다.

다음 코드에서는 에러가 발생한다.

int main() {
    Base baseObj;
    Base& baseRef = baseObj;

    try {
        Derived& derivedRef = dynamic_cast<Derived&>(baseRef);
        derivedRef.sayHello();
    } catch (const std::bad_cast& e) {
        std::cout << "dynamic_cast 실패: " << e.what() << std::endl;
    }

    return 0;
}

변환에 실패하게 되면 std::bad_cast 예외를 생성한다.