오븐 노트

[C++] 타입 변환 #1~2 본문

Develop/C++

[C++] 타입 변환 #1~2

오 븐 2023. 2. 13. 22:18
#include <iostream>
using namespace std;

// malloc -> void*를 반환하고, 이를 우리가 (타입 변환)을 통해 사용하였음.

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

class Dog
{
public:
    Dog()
    {

    }
    // 타입 변환 생성자
    Dog(const Knight& knight)
    {
        _age = knight._hp;
    }

    // 타입 변환 연산자
    // 특이하게도 리턴 타입이 없음. Knight에서 모든 의미를 함축하고 있기 때문
    operator Knight()
    {
        return (Knight)(*this);
    }

public:
    int _age = 1;
    int _cuteness = 2;
};

class BullDog : public Dog
{
public:
    bool _french;
};

int main()
{
    // 1. 타입 변환 유형 (비트열 재구성 여부)
    // [1] 값 타입 변환
    // 특징) 의미를 유지하기 위해서, 원본 객체와 다른 비트열 재구성
    {
        int a = 123456789; // int => 2의 보수를 이용하여 데이터를 저장하는 방식
        float b = (float)a; // float => 부동소수점(지수 + 유효숫자) 기법을 이용하여 데이터를 저장하는 방식
        cout << b << endl;
    }
    // [2] 참조 타입 변환
    // 특징) 비트열을 재구성하지 않고, '관점'만 바꾸는 것
    // 거의 쓸 일은 없지만, 포인터 타입 변환도 '참조 타입 변환' 동일한 룰을 따르니 겸사겸사 공부
    {
        int a = 123456789;
        float b = (float&)a;
        cout << b << endl;
    }

    // 2. 안전도에 따른 분류
    // [1] 안전한 변환
    // 특징) 의미가 항상 100% 완전히 일치하는 경우
    // 같은 타입이면서 크기만 더 큰 바구니로 이동
    // 작은 바구니 -> 큰 바구니로 이동 ok (업캐스팅)
    // ex) char -> short, short -> int, int -> __int64
    {
        int a = 123456789;
        __int64 b = a;
        cout << b << endl;
    }
    // [2] 불안전한 변환
    // 특징) 의미가 항상 100% 일치한다고 보장하지 못하는 경우
    // 타입이 다르거나
    // 같은 타입이지만 큰 바구니 -> 작은 바구니 이동 (다운캐스팅)
    // 의미가 완전히 달라지기 때문에 매우 조심할 필요가 있음
    // 손실을 만드는 것이기 때문에 애당초 이런 코드 자체가 이상한 코드라고 볼 수 있음.
    {
        int a = 123456789;
        float b = a;
        short c = a;
        cout << b << endl;
        cout << c << endl;
    }

    // 3. 프로그래머 의도에 따른 분류
    // [1] 암시적 변환
    // 특징) 이미 알려진 타입 변환 규칙에 따라서 컴파일러 '자동'으로 타입 변환
    {
        int a = 123456789;
        float b = a; // 암시적
        cout << b << endl;
    }
    // [2] 명시적 변환
    {
        int a = 123456789;
        int* b = (int*)a; // 명시적
        cout << b << endl;
    }

    // 4. 아무런 연관 관계가 없는 클래스 사이의 변환
    // [1] 연관없는 클래스 사이의 '값 타입' 변환
    // 특징) 일반적으로는 불가능 (예외 : 타입 변환 생성자, 타입 변환 연산자)
    {
        Knight knight;
        Dog dog = (Dog)knight; // 타입 변환 생성자
        Knight knight2 = dog; // 타입 변환 연산자
    }
    // [2] 연관없는 클래스 사이의 참조 타입 변환
    // 특징) 명시적으로는 가능
    {
        Knight knight;
        // 어셈블리의 관점 : 포인터 = 참조
        // [ 주소 ] -> [ Dog ]
        Dog& dog = (Dog&)knight;
        dog._cuteness = 12; // 건들면 안되는 메모리를 건드릴 위험있음
    }

    // 5. 상속 관계에 있는 클래스 사이의 변환
    // [1] 상속 관계 클래스의 값 타입 변환
    // 특징) 자식 -> 부모 ok / 부모 -> 자식 no
    {
        //Dog dog;
        //BullDog bulldog = (BullDog)dog; // 실패

        BullDog bulldog; // 타입 변환 생성자를 만들면서 기본 타입 생성자가 막히기 때문에 error 발생
        Dog dog = bulldog;

    }
    // [2] 상속 관계 클래스의 참조 타입 변환
    // 특징) 자식 -> 부모 ok / 부모 -> 자식 (암시적 no) (명시적 ok)
    {
        //Dog dog;
        //BullDog& bulldog = (BullDog&)dog;

        // [ age cuteness french ]
        BullDog bulldog;
        Dog& dog = bulldog;
    }

    // 결론)
    // [값 타입 변환] : 비트열 변환, 논리적으로 말이 되도록 바꾸는 변환
    // - 논리적으로 말이 된다? (ex. BullDog -> Dog) ok
    // - 논리적으로 말이 안 된다 ( ex. Dog -> BullDog, Dog -> Knight) no
    // [참조 타입 변환] : 비트열은 그대로, 우리의 '관점'만 바꾸는 변환
    // - 명시적 요구를 하면 가능은 하지만, 암시적으로는 안전성 여부와 연관 있음.
    // -- 안전 (ex. BullDog -> Dog&) -> (암시적) ok
    // -- 위험 (ex. Dog -> BullDog&) -> (암시적) no
    // --- 메모리 침범 위험이 있는 경우는 암시적으로 해주지는 않음. (건드려서는 안되는 메모리 간섭 위험)
    // --- 위험 감수까지 하며 명시적으로 선언시에는 가능.

    return 0;
}

[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 - 인프런 | 강의
 
C++ 카테고리의 글은 인프런 Rookiss님의 강의를 공부하며 정리하는 내용입니다.
이미 알고 있는 내용도 다시 정리 되어있을 수 있습니다.

 

모든 글은 제가 공부하기 위해 작성합니다.

'Develop > C++' 카테고리의 다른 글

[C++] 타입 변환 #4~5  (0) 2023.02.15
[C++] 타입 변환 #3  (0) 2023.02.15
[C++] 동적할당 #3  (0) 2023.02.08
[C++] 동적할당 #2  (0) 2023.02.01
[C++] 동적 할당 #1  (0) 2022.10.06