<aside> <img src="/icons/list_gray.svg" alt="/icons/list_gray.svg" width="40px" />

목차

</aside>

타입 변환


타입 변환? 갑자기 타입 변환을 살펴봐야 할까 싶다. 그러나, 우리 앞서 살펴봤듯이, 포인터는 동적 할당에서 메모리 주소를 다루는 핵심 도구인데, 이 포인터를 제대로 활용하려면 타입 변환을 이해하는 것이 필수적이다.

예를 들어서, 위 코드에서 살펴봤듯이 void* 포인터를 특정 타입의 포인터로 바꾸거나, 상속 관계에 있는 클래스들의 포인터를 서로 변환해야 할 때가 많다. 이런 변환 과정에서 문제가 생기지 않도록 타입 변환의 개념과 규칙을 잘 알아두어야 한다.

그리고 메모리를 관리할 때 타입 변환은 데이터를 다르게 해석하거나 재사용하는 데 매우 중요한 역할을 한다. 따라서 동적 할당과 타입 변환은 서로 뗄 수 없는 관계라고 할 수 있다.

종류


크게 두 가지 타입의 변환이 존재한다.

값 타입 변환

참조 타입 변환

참조 타입 변환

int main()
{
    int a = 123456789;
    float b = (float&)a;

    cout << b << endl;
}

image.png

위 코드를 실행하면 123456789라는 정수가 float 타입으로 재해석되어 출력된다. 이때 실제 메모리의 비트 패턴은 변경되지 않고, 단지 float의 관점에서 해석되기 때문에 전혀 다른 값이 출력된다.

위는 참조 타입 변환이 메모리의 실제 내용은 그대로 두고 단순히 해석 방식만 바꾼다는 것을 보여주는 좋은 예시이기도 하다.

안전도 분류


타입 변환은 안전도에 따라 분류할 수도 있다. 안전도는 데이터의 의미와 값이 변환 과정에서 얼마나 보존되는지를 나타내는 중요한 지표이다.

안전한 변환 (Safe Conversion)

불안전한 변환 (Unsafe Conversion)

의도성 분류


타입 변환은 프로그래머의 의도성에 따라서도 분류할 수 있다. 의도성 분류는 타입 변환이 코드에서 얼마나 명시적으로 드러나는지를 기준으로 한다.

암시적 변환 (Implicit Conversion)

명시적 변환 (Explicit Conversion)

연관없는 클래스 간 변환


값 변환

class Knight
{
public:
    int _hp = 10;
};

class Dog
{
public:
    int _age = 20;
    int _cuteness = 2;
};
int main()
{
    Knight k;
    **Dog d = (Dog)k;**
}

생성자 선언

**Dog(const Knight &knight)
{
    _age = knight._hp;
}**

연산자 오버로딩

**operator Knight()
{
    return (Knight)(*this);
}**
**Knight knight2 = d;**

참조 타입 변환

**Dog& d = (Dog&)k;**

어셈블리 레벨에서 보면 포인터참조는 동일한 방식으로 메모리를 다룬다.