728x90
캐스팅이란?
- 형(Type) 변환을 말한다.
- 기존의 C스타일 캐스팅 방법은 (int), (float)등을 통한 명시적 형변환이고, C++에서는 4종류의 캐스팅으로 나뉜다.
static_cast
- 암시적 변환을 명시적 변환으로 진행할 때 사용되는 방법이다. (비상수 객체를 상수 객체로 바꾸는? int <->float 등)
- 포인터 타입을 다른 것으로 변환하는 것은 허용하지 않는다.
- 형 변환 시점이 컴파일 시점이기 때문에 static이라는 명칭이 붙는다.
- 사용 빈도가 가장 높다.
- 기본 자료형의 형변환 및 상속 관계에 있는 클래스 타입의 형변환은 가능하다.
- 부모 클래스의 참조/포인터 형식에서 자식 클래스의 참조/포인터 형식으로의 형변환 허용 (불안전)
-> 다운 캐스팅 (부모 -> 자식으로서의 형변환) - 자식 클래스의 참조/포인터 형식에서 부모 클래스의 참조/포인터 형식으로의 형변환 허용 (안전)
-> 업 캐스팅 (자식 -> 부모로서의 형변환)
- 부모 클래스의 참조/포인터 형식에서 자식 클래스의 참조/포인터 형식으로의 형변환 허용 (불안전)
[1] int <-> float
int hp = 100;
int maxHp = 200;
float ratio = static_cast<float>(hp) / maxHp;
[2] Player* <-> Knight*
class Player
{
};
class Knight : public Player
{
};
int main()
{
// 자식 -> 부모는 그냥 가능 (업 캐스팅)
Player* p = new Player();
Knight* k = p;
// Knight* k = static_cast<Player*>(p); 로 대체 가능
// 부모 -> 자식 (다운 캐스팅)
Player* p2 = new Knight();
Knight* k2 = static_cast<Knight*>(p2); // Player <-> Knight 명확할 때는 그나마 안전
}
- 명시적 변환처럼, static_cast도 다운캐스팅이 가능하다. (단, 안전성은 보장하지 못한다)
- Player* p3 = new Knight(); 가 아닌, new Archer() 등 다른 타입을 받을 경우 문제가 생길 수 있다.
- 따라서 꼼꼼히 확인하여 서로 동일한 타입인지 보고 사용하고, 조건식 등을 활용하여 안전성을 높이는 것이 좋다.
dynamic_cast
- static_cast와 달리 컴파일 시점이 아닌, 런 타임시에 형변환을 검사하여 형변환을 보다 안전하게 검사한다.
- 기본 자료형 간의 형변환이 불가능하고, 포인터 또는 참조형을 캐스팅할 때만 사용가능하다.
- 안전한 다운캐스팅을 할 때 유용한데, 만약 부모 클래스가 호환되지 않는 자식 클래스로 캐스팅했다면 nullptr을 반환한다. (안전 여부 확인)
기본 자료형 간의 형변환을 제외하곤 dynamic_cast를 사용하면 편하지 않나?
- dynamic_cast는 RTTI (Run Time Type information)을 지원한다.
- RTTI는 런 타임에서 클래스의 type_info를 보고 해당 클래스가 올바른 type의 형태인지 아닌지 판단하게 해 준다.
- RTTI를 사용하기 때문에, 런 타임 비용이 비싸고, 반드시 하나 이상의 가상 함수가 존재해야 한다.
class Player
{
public:
virtual ~Player() { }
};
class Knight : public Player
{
public:
};
class Archer : public Player
{
public:
};
int main()
{
Player* p = new Archer();
Knight* k1 = static_cast<Knight*>(p); // 잘못된 캐스팅을 했을 경우 static_cast
Knight* k2 = dynamic_cast<Knight*>(p); // 잘못된 캐스팅을 했을 경우 dynamic_cast
cout << k1 << endl;
cout << k2 << endl;
return 0;
}
/*실행 결과
000002D8FE4D2A10
0000000000000000
*/
- static_cast를 사용한 k1의 경우 잘못된 캐스팅을 하더라도 직접적인 메모리상에 문제가 발생하지 않는 이상 확인하기 어렵다.
- 하지만 dynamic_cast를 사용한 k2의 경우, 잘못된 캐스팅을 하더라도 nullptr을 뱉어줘서 바로 확인할 수 있다.
- 이를 이용하여 잘못된 캐스팅인지 맞는 타입으로 캐스팅했는지 확인하기 유용하다.
const_cast
- const 속성을 제거할 때 사용한다.
- const라는 의미는 객체가 변하지 말아야 한다는 코드 작성자의 의도를 다른 사람에게 알려주는 수단으로 막 const 속성을 제거하는 것은 옳지 않다.
- 보통 라이브러리의 함수 인자가 const 기능이 없고 const 속성이 존재하는 변수를 넘기지 못하는 경우 사용한다.
void PrintName(char* str)
{
cout << str << endl;
}
int main()
{
//PrintName("Hello"); // 이렇게 문자를 넣어주고 싶지만 const char형이기 때문에 안된다.
PrintName(const_cast<char*>("Hello"));
return 0;
}
/*실행 결과
Hello
*/
reinterpret_cast
- 일반적으로 허용하지 않는 형변환을 강제적으로 형변환할 때 사용한다.
- 포인터가 다른 포인터 형식으로도 변환이 가능하고, 정수 계열 형식이 포인터 형식으로도 형변환이 가능하고, 그 반대로도 가능하다.
- 포인터/참조와 관련된 형변환만 지원한다.
- 자료를 그대로 변수에 bit단위로 전달한다.
class Player
{
};
class Knight : public Player
{
};
class Dog
{
};
int main()
{
// 정수 -> 포인터
Knight* knight = new Knight();
__int64 address = reinterpret_cast<__int64>(knight);
// 관계없는 포인터 -> 포인터
Dog* dog = reinterpret_cast<Dog*>(knight);
// 그나마 사용용도? dog2에 메모리 공간 할당
void* p = malloc(1000);
Dog* dog2 = reinterpret_cast<Dog*>(p);
return 0;
}
728x90
'📕Programming > 📝C/C++' 카테고리의 다른 글
| [C / C++] algorithm 라이브러리 (0) | 2023.11.24 |
|---|---|
| [C / C++] 함수 포인터, 함수 객체, 람다 표현식 (0) | 2023.10.24 |
| [C / C++] 메모리 구조, 동적 할당 (0) | 2023.10.04 |
| [C / C++] 문자열 (0) | 2023.09.14 |
| [C / C++] 포인터 / 레퍼런스 (0) | 2023.09.12 |