1. 변환 종류에 따른 변환

(1) 값 타입 변환

의미를 유지하기 위하여 원본 객체와 다른 비트열로 (원본과 거의 비슷하도록)재구성한다.

int main()
{
    
    {
        int a = 12345678; // 2의 보수로 저장됨
        float b = (float)a; // 부동 소수점(지수와 유효숫자)
    }
	
    return 0;
}
// b에 a와 거의 유사한(같지 않은) 숫자가 저장됨

 

(2) 참조 타입 변환

비트열을 재구성하지 않고 데이터의 타입만 바꿈. 의미가 완전히 달라짐.

    {
        int a = 12345678; // 2의 보수로 저장됨
        float b = (float&)a; // 부동 소수점(지수와 유효숫자)
    }

포인터 타입 변환도 참조 타입 변환과 동일하게 사용할 수 있음.

 

2. 안전도에 따른 변환

(1) 안전한 변환

동일한 타입이면서 크기를 확대 변환하고자 할 때 안전한 변환이라고 한다. -> 의미가 동일함

ex) 업 캐스팅(Up Casting) : char -> short , short -> int, int -> __int64

 

(2) 불안전한 변환

서로 다른 타입을 캐스팅 할 때 불안전한 변환이라고 한다.

데이터가 손실될 수 있음! -> 의미가 달라질 수 있음

ex) 다운 캐스팅(Down Casting) : __int64 -> int, int -> short, short -> char

ex2) int -> float

 

3. 프로그래머의 의도에 따른 변환

(1) 암시적 변환

이미 알려진 타입 변환 규칙에 따라 컴파일러가 자동으로 타입 변환함.

    {
        int a = 12345678; // 2의 보수로 저장됨
        float b = a; // 부동 소수점(지수와 유효숫자)
    }

 

(2) 명시적 변환

프로그래머의 의도에 따라 타입을 강제로 변환함.

    {
        int a = 12345678; // 2의 보수로 저장됨
        int* b = (int*)a; // 부동 소수점(지수와 유효숫자)
    }

 

4. 연관 없는 클래스 사이의 변환

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

class Dog
{
public:
    int _age = 1;
    int _cuteness = 2;
};

int main()
{
    {
        Knight knight;
        Dog dog = (Dog)knight; // 객체 knight를 Dog 타입으로 변환 불가
    }
    return 0;
}

단, 고의적으로 타입 변환 생성자 (또는 연산자)를 만들어주면 오류없이 빌드가 가능하다.

 

(1) 타입 변환 생성자

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

 

(2) 타입 변환 연산자

// 타입 변환 연산자
    operator Knight()
    {
        return (Knight)(*this);
    }

 

5. 연관 없는 클래스 사이의 참조 타입 변환

int main()
{
    {
        Knight knight;
        Dog& dog = knight;
    }
	return 0;
}

위에서는 오류가 발생한다(암시적 변환이 불가). 하지만 강제로 변환할 수 있다.

int main()
{
    {
        Knight knight;
        Dog& dog = (Dog&)knight;
    }
	return 0;
}

위의 코드로 knight 주소를 따라가면 Dog형 타입의 데이터가 저장되어 있다고 주장할 수 있다(명시적 변환).

 

6. 상속 관계에 있는 클래스 사이의 타입 변환

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

(1) 값 타입 변환

	{
        BullDog bulldog;
        Dog dog = bulldog;
    }

Dog를 상속받은 자식인 bulldog는 dog 타입으로 변환이 가능하지만, 반대로 dog 타입의 객체는 bulldog이 될 수는 없다.

이 때 bulldog가 가지고 있던 멤버 변수 _french는 제거된다.

 

(2) 참조 타입 변환

 

    {
        // Dog dog;
        // BullDog& bulldog = (BullDog&)dog;

        BullDog bulldog;
        Dog& dog = bulldog;
    }

자식에서 부모 타입으로 변환은 가능하지만 반대의 타입으로 변환할 때는 명시적으로 변환해야 함.

 

6. 결론

(1) 값 타입 변환

실제 비트열도 바꾸며 논리적으로 말이 되도록( BullDog -> Dog O, Dog -> BullDog X) 변환함

 

(2) 참조 타입 변환

비트열을 바꾸지 않고 해당 데이터를 보는 관점을 바꾸는 것

안전하면 암시적으로 변환해 줌.

불안전하면 명시적으로 지정해야 변환해 줌.

'기초 C++ 스터디 > 객체지향' 카테고리의 다른 글

6-4. 얕은 복사, 깊은 복사  (0) 2023.06.01
6-3. 형(Type) 변환 : 포인터 (2)  (0) 2023.06.01
6-1. 동적 할당  (0) 2023.05.31
5-7. 객체지향 정리  (0) 2023.05.30
5-6. 연산자 오버로딩  (0) 2023.05.30