C++에는 casting을 위한 연산자 4가지를 제공한다.
static_cast, const_cast, dynamic_cast, reinterpret_cast 인데 각자의 역할이 모두 다르다.
static_cast 는 가장 일반적인 형변환 형식이다. 논리적으로 변환 가능한 타입을 변환해준다. 예를들어 float형을 int로 변환한단거나 하는
float a = 10.123
int b = static_cast<int>(a);
이런식으로 사용하면 된다.
cosnt_cast는 const 형식의 변수에서 const를 제거하는데 사용된다.
그렇다고 const형 변수의 값을 변환할 수 있는건 아니고,
void f(int n);
int main()
{
const int a = 10;
f(*(const_cast<int *>(&a));
}
위와 같이 const형이 아닌 매개변수를 받는 함수의 매개변수로 const형 변수를 넘겨주려고 할 때나 사용된다.
그리고 형 변환은 포인터형으로만 변경할 수 있다.
하지만 const_cast에는 큰 취약점이 존재하는데,
const int a = 10;
int *b = const_cast<int *>(&a);
*b = 20;
cout << a << " " << *b << endl;
cout << &a << " " << b << endl;
위 코드를 실행해보면
이와 같이 출력된다.
b는 a를 가리키는 포인터이고, 해당 주소에 있는 값을 변경해주었으나 a의 값은 변경되지 않고 출력이 된다.
그리고 또 정작
const int *c = &a;
코드를 추가해서 실행해보면 20이 출력된다.
그러니 const 변수의 주소에 접근해서 값을 변경하는데 사용하지는 말자.
dynamic_cast 는 업캐스팅 후 안정적인 다운캐스팅을 하는데 사용된다.
예를 들어 Base를 상속받은 클래스 A, B, C가 존재한다고 하자.
그리고 Base 형 변수 b에 A, B, C 셋 중 하나의 생성자가 랜덤하게 실행된다고 할 때, 이 변수의 원래 타입을 찾는데 사용될 수 있다.
사용방법은 다음과 같다.
if (dynamic_cast<A*>(b))
std::cout << "A" << std::endl;
else if (dynamic_cast<B*>(b))
std::cout << "B" << std::endl;
else if (dynamic_cast<C*>(b))
std::cout << "C" << std::endl;
reinterpret_cast 는 일반적으로 허용되지 않는 캐스팅에 사용된다. 포인터를 정수로, 정수를 포인터로 혹은 포인터를 다른 타입의 포인터로 바꾸는데 사용할 수 있다.
일반적으로 포인터형 변수를 다른 타입(특히 그보다 작은 크기의 자료형)으로 변환할 수 없다. 예를들어 int형 포인터 변수는 4byte를 차지하지만 char형 변수는 1byte를 차지한다.
int a = 123;
int *b = &a;
char c = *(reinterpret_cast<char *>(b));
이런식으로.
결국 형 변환을 해줄 때 char형 포인터 변수로 형변환 해준 것의 값을 char에 넣은거 아니냐고 할 수도 있지만, static_cast로는 불가능한 변환이다.