초보 코린이의 성장 일지
C++ Casts 본문
Casts 설명
- 데이터 형식을 다른 데이터 형식으로 변환하는 작업
Casts의 종류
1. 정적 캐스트(static_cast)
- 자료형을 변경하기 위해 사용.
- 컴파일 시간에 형변환이 가능한지 검사한다.
- 클래스가 잘못된 캐스팅 시 런타임 중 유효성 검사를 하지 않는다.
- 상위계층에서 하위계층, 하위계층에서 상위계층 둘다 데이터 타입 변환은 가능하다.
- 하위계층 데이터 타입 변환에는 안전하지 않으므로, 상속 관계에 있는 클래스 간의 캐스팅을 수행할 때는 dynamic_cast를 사용하는게 좋은 방법이다.
- 포인터 간의 변화에도 사용할 수 있다.
- 부모 클래스에서 자식 클래스로 캐스팅하려고 할 때, static_cast는 컴파일러에게 허용하도록 지시하지만, 실제로 캐스팅이 안전한지는 확인하지 않는다.
#include <iostream>
using namespace std;
class A
{
public:
int a = 10;
};
class B : public A
{
};
int main()
{
// B클래스 객체를 동적으로 할당
B* test = new B;
// test가 가리키는 B클래스의 객체를 A클래스의 포인터로 캐스팅 (B가 A에 상속되어 있기 때문에 가능)
A* test2 = static_cast<A*>(test);
// test2가 가리키는 A클래스의 객체를 B클래스의 포인터로 다시 캐스팅 (주의할점 : test2가 실제로 B클래스의 객체를 가리켜야만 가능)
B* test3 = static_cast<B*>(test2);
// 정수형 포인터
int* a = new int(5);
// 정수형 포인터를 부동소수점이 있는 float로 캐스팅하기 때문에 오류발생
float* b = static_cast<float*>(a);
cout << "test : " << test << endl; // cast 성공
cout << "test2 : " << test2 << endl; // cast 성공
cout << "test3 : " << test3 << endl; // cast 성공
return 0;
}
2. 상수 캐스트(const_cast)
- const_cast는 변수에 const 속성을 추가하거나 제거할 때 사용한다.
- 변수를 const롤 설정했다면 const 상태를 유지하겠다는 의미로 변경을 자제해야한다.
#include <iostream>
using namespace std;
void Test(char* bb)
{
// char* 매개변수의 2번째 문자 'c'로 변경
bb[1] = 'c';
cout << bb << endl;
}
void f(const char* str)
{
// Test함수를 호출, const_cast를 사용하여 str을 char*로 캐스팅 후 Test함수에 전달
Test(const_cast<char*>(str));
}
int main()
{
char aaa[] = "abc"; // 'abc'문자열을 aaa에 저장
const char* b = aaa; // b라는 const char*를 선언하고, 이를 aaa에 대한 포인터로 초기화
char* c = const_cast<char*>(b); // const_cast를 사용하여 b를 char*으로 캐스팅하고 c에 저장
cout << "기존 aaa : " << aaa << endl;
cout << "기존 b : " << b << endl;
cout << "기존 c : " << c << endl;
f(b); // f함수 호출, const_cast를 사용하여 const char을 char로 변환, Test함수에 전달
c[0] = 'h'; // c가 가리키는 첫 번째 문자를 'h'로 변경
cout << "이후 aaa : " << aaa << endl;
cout << "이후 b : " << b << endl;
cout << "이후 c : " << c << endl;
return 0;
}
3. dynamic_cast
- 런타임에(동적) 동작합니다.
- 런타임 타입 정보(RTTI)를 사용하여 안전성을 검사하기 때문에, 안전한 타입 변환을 보장한다.
- 상속 관계에서 안전하게 업캐스팅, 다운캐스팅을 수행할 수 있다.
- 다만 다운캐스팅을 위해 가상 함수(virtual function)이 있어야 하고, 실행 시간에 타입 정보를 확인하다 보니 오버헤드가 발생할 수 있다.
- 업캐스팅은 파생 클래스 -> 기본 클래스로 변환, 다운캐스팅은 기본 클래스 -> 파생 클래스로 변환.
- 캐스팅 실패시 NULL(*)이나 예외(&)를 보고 판별할 수 있다. (유효성검사를 한다.)
4. reinterpret_cast
- 다른 포인터 타입이나 레퍼런스 타입으로 유연하게 형변환을 할 수 있다. (서로 관련없은 레퍼런스끼리 변환도 가능)
- 특수한 상황에서 사용하길 바람. (해당 캐스팅 성공이 확실할 때만 사용하는 것이 좋다.)
- 보편적으로 void* 타입으로 캐스팅해서 사용한다.
- 내부적으로 처리되기 때문에 명시적으로 캐스팅하지 않아도 된다.
- 안전하지 않은 형변환도 허용하기 때문에 안정성을 해칠 수 있으므로 신중하게 사용해야 한다.
#include <iostream>
using namespace std;
int main()
{
int num = 10;
int* numPtr = #
// int 포인터를 void 포인터로 형변환
void* voidPtr = reinterpret_cast<void*>(numPtr);
// void 포인터를 다시 int 포인터로 형변환
int* newNumPtr = reinterpret_cast<int*>(voidPtr);
cout << "num의 값: " << num << endl; // num의 값 출력
cout << "numPtr이 가리키는 값: " << *numPtr << endl; // numPtr이 가리키는 값 출력
cout << "newNumPtr이 가리키는 값: " << *newNumPtr << endl; // newNumPtr이 가리키는 값 출력
return 0;
}
'개인 공부' 카테고리의 다른 글
C++ Byte Padding (2) | 2024.04.22 |
---|---|
짐벌락 (GimBal Lock) (2) | 2023.09.27 |
C++ Static (0) | 2023.07.27 |
C++ malloc, free, new, delete 차이 (0) | 2023.07.25 |
C++ Extern (0) | 2023.07.21 |
Comments