일반적으로 데이터형 변환은 변환하고 싶은 변수 앞에 '(데이터형)변수' 뭐 이런 식으로 쓴다. 근데 이게 좀... 불안정하다고 한다. 그래서 이걸 강화하고자 4개의 데이터형 변환을 만들었다.
dynamic_cast
const_cast
static_cast
reinterpret_cast
dynamic_cast는 저번에 배웠고, const_cast부터 알아보자.
const_cast 연산자는 어떤 값을 const나 volatile로, 또는 그 반대로 변환할 수 있다. 사용 방법은 dynamic_cast와 비슷하다.
High bar;
const High * pbar = &bar;
High * pb = const_cast<High *>(pbar) // 맞다.
const Low * pl = const_cast<const Low*>(pbar); // 틀리다.
첫 번재는 const를 const가 아닌 포인터로 바꾸기 때문에 가능하다. 두 번째는 const를 const로 변환한다고 해서 틀렸다.
이 연산자는 왜 필요하나? const로 정의한 상수를 가끔씩 바꾸어야 할 때가 있기 때문이다. 근데 이거 일반 데이터형 변환도 가능하다. 그럼 왜 굳이 const_cast를 써야 하냐고? 일반 데이터형 변환은 데이터형도 동시에 바꿀 수 있어서 실수를 저지를 수 있기 때문이다. (잘 쓰면 좋은 거 아닌가? ㅋㅋ)
High bar;
const High * pbar = &bar;
High & pb = (High*)(pbar); // 맞다.
Low * pl = (Low*)(pbar); // 데이터형 변환도 같이 된다.
static_cast는 일반적인 데이터형 변환과 비슷하다. 대신 변환이 안 될 때는 에러를 호출한다. 예를 들어 High가 Low의 기초 클래스이고, Pond는 이 별개의 클래스라고 가정하자.
High bar;
Low blow;
High * pb = static_cast<High*>(&blow); // 유효한 업캐스팅.
Low * pl = static_cast<Low*>(&bar); // 유효한 다운캐스팅.
Pond * pmer = static_cast<Pond*>(&blow) // 에러 호출.
첫 번째는 업캐스팅이라 당연히 된다. 두 번째는 다운캐스팅인데 형변환 하면 되나 보다 ㄷㄷ. 형변환이 없으면 당연히 안 된다. 세 번째는 관련이 없어서 에러를 호출한다.
이와 비슷하게 double형을 int형으로 바꾼다던지, 열거값을 정수형으로 바꾼다던지가 가능하다.
reinterpret_cast 연산자는 위험한 데이터형 변환을 하기 위해 쓰인다.
struct dat { short a; short b; };
long value = 0xA224B118;
dat* pd = reinterpret_cast<dat*>(&value);
cout << pd->a; // value의 처음 2바이트를 출력한다.
굉장히 난해하다. 근데 이 연산자도 불가능할 때가 있다. 예를 들어 포인터형을 포인터형을 저장할 수 있는 큰 정수형으로 캐스팅할 수 있지만, 반대는 안 된다. 또 함수 포인터를 데이터 포인터로, 그 반대도 안 된다. 언제 사용하게 되는지 궁금하다.