초보 코린이의 성장 일지

C++ Casts 본문

개인 공부

C++ Casts

코오린이 2024. 4. 11. 16:01

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;
}

static_cast 성공 출력.

 

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;
}

const_cast 성공 출력.

 

3. dynamic_cast

  • 런타임에(동적) 동작합니다.
  • 런타임 타입 정보(RTTI)를 사용하여 안전성을 검사하기 때문에, 안전한 타입 변환을 보장한다.
  • 상속 관계에서 안전하게 업캐스팅, 다운캐스팅을 수행할 수 있다.
  • 다만 다운캐스팅을 위해 가상 함수(virtual function)이 있어야 하고, 실행 시간에 타입 정보를 확인하다 보니 오버헤드가 발생할 수 있다.
  • 업캐스팅은 파생 클래스 -> 기본 클래스로 변환, 다운캐스팅은 기본 클래스 -> 파생 클래스로 변환.
  • 캐스팅 실패시 NULL(*)이나 예외(&)를 보고 판별할 수 있다. (유효성검사를 한다.)

 

4. reinterpret_cast

  • 다른 포인터 타입이나 레퍼런스 타입으로 유연하게 형변환을 할 수 있다. (서로 관련없은 레퍼런스끼리 변환도 가능)
  • 특수한 상황에서 사용하길 바람. (해당 캐스팅 성공이 확실할 때만 사용하는 것이 좋다.)
  • 보편적으로 void* 타입으로 캐스팅해서 사용한다.
  • 내부적으로 처리되기 때문에 명시적으로 캐스팅하지 않아도 된다.
  • 안전하지 않은 형변환도 허용하기 때문에 안정성을 해칠 수 있으므로 신중하게 사용해야 한다.
#include <iostream>

using namespace std;

int main()
{
	int num = 10;
	int* numPtr = &num;

	// 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;
}

reinterpret_cast 성공 출력.

 

'개인 공부' 카테고리의 다른 글

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