타입 변환의 여러 관점
※ C / C++을 이미 알고 있으나 개인적인 복습 및 공부를 위해 포스팅 하는 글이므로
C++에 대한 구체적인 정보를 담고 있지 않습니다.
▶ 타입 변환의 여러가지 관점에 따른 분류
ㆍ 비트열 재구성 여부, 안전도에 따른 분류, 프로그래머 의도에 따른 분류, 클래스간의 변환..
----------타입 변환의 유형 (비트열 재구성 여부)----------
1) 값 타입 변환
ㆍ 의미를 유지하기 위해서, 원본 객체와 다른 비트열 재구성.. 뭔소리냐?
int a = 123456789; //2의 보수
float b = float(a);//부동소수점(지수+유효숫자)
cout << b << endl;
//메모리를 찍어보면 a엔 16진수로 123456789가 저장돼있고
//b엔 16진수로 의미가 비슷한 근접한 숫자가 저장되어있다
ㆍ 즉 의미를 유지하기 위해 최~대한 근접하게 해줌
2) 참조 타입 변환
ㆍ 비트열을 재구성 하지 않고, "관점"만 바꾸는 것
int a = 123456789; //2의 보수
float b = (float&)a;//부동소수점(지수+유효숫자)
cout << b << endl;
---------- 안전도 분류 ----------
1) 안전한 변환
ㆍ 의미가 항상 100% 일치하는 경우
ㆍ 같은 타입이면서 크기만 더 큰 바구니로 이동하는 경우
ㆍ 작은 바구니 -> 큰 바구니로 이동 ok (이걸 업케스팅 이라고 한다)
ex) char -> short, short -> int
int a = 123456789;
__int64 b = a;
cout << b << endl; //문제없이 실행
2) 불안전한 변환
ㆍ 의미가 항상 100% 일치한다고 보장하지 못하는 경우....
→ 타입이 다르거나, 같은 타입이지만 큰 바구니 -> 작은 바구니인 경우 (다운캐스팅)
int a = 123456789;
float b = a; // 1.2345..... 뭐 근사값 맞출라고 노력
short c = a; // 프로그래머 계산기 기준 short만큼만(2바이트) 분석하고 나머지 버림...
----------프로그래머 의도에 따른 분류----------
1) 암시적 변환
ㆍ 이미 알려진 타입 변환 규칙에 따라 컴파일러가 "자동"으로 타입 변환
int a = 123456789;
float b = a; // 암시적으로 알아서 해주는 상황
2) 명시적 변환
int a = 123456789;
int* b = (int*)a; // 이건 암시적으로 안댐...명시해줘
ㆍ위험한거 알고... 자동으로 해주는거 싫은거 알겠는데.. 그래도 해줘!
----------아무런 연관 관계가 없는 클래스 사이의 변환----------
1) 연관 없는 클래스 사이의 "값 타입" 변환
ㆍ 일반적으로 안됨 (타입변환 생성자를 만들어서 예외적으로 해야댐)
class Knight
{
public:
int _hp = 10;
};
class Dog
{
public:
int _age = 1;
int _cuteness = 2;
};
Knight knight;
Dog dog = (Dog)knight;
//기사랑 개사이엔 아무관계가 없어서 명시든,암시든 안됨 (타입변환 생성자 생성하면됨)
Knight knight2 = dog;
ㆍ 두 코드 다 안되는게 정상인데 어거지로 되게 할 수 있는 방법이 있긴 하다..
class Dog
{
public:
//타입 변환 생성자
Dog(const Knight& knight)
{
_age = knight._hp;
}
//타입 변환 연산자
operator Knight()
{
return (Knight)(*this);
}
int _age = 1;
int _cuteness = 2;
};
ㆍ 이렇게 해주면 위 코드들의 오류가 사라지긴 한다
2) 연관 없는 클래스 사이의 "참조 타입" 변환
ㆍ 위 타입 변환 연산자와 타입변환 생성자는 값 타입에서만 적용이 된다...
Knight knight;
//Dog& dog = knight; //안댐...
//
// 어셈블리 : 포인터 = 참조
// C++에선 다르지만 어셈블리에선 같았다
//
// [ 주소 ] -> [ Dog ]
Dog& dog = (Dog&)knight; //이건또 됨;; 진짜인지 아닌지를 컴파일타임에서 체크하지 않는것이다...
// 어셈블리 입장에선 주소라 함은 꼭 dog를 가리키지 않아도 상관이 없기때문에(null이여도 괜찮) 그래서 일단
// 컴파일타임 에서는 오류를 잡아주지 않는 것이다 (명시적으로는 ok)
//
dog._cuteness = 12; //이런식으로 가리키면 터질껄~
ㆍ 포인터 관련 사용 문제를 조심히자, 댕글링포인터 주의
----------상속 관계 클래스 사이의 변환----------
1) 상속 관계 클래스의 값 타입 변환
ㆍ 자식-> 부모 OK / 부모 -> 자식 NO
// Dog dog;
// BullDog bulldog = (BullDog)dog; 안댐!
BullDog bulldog;
Dog dog = bulldog;
2) 상속 관계 클래스의 참조 타입 변환
ㆍ 자식-> 부모 OK / 부모 -> 자식 NO
ㆍ 허용은 하지만... 쫌 그럼... 포인터 관련 문제 주의
Dog dog;
BullDog& bulldog =(BullDog&)dog; //되긴 함
BullDog bulldog;
Dog& dog = bulldog;