C++ Type Casting
묵시적 형 변환
자동 변환을 말한다. 예를 들어
int main(){
float a = 3.4f;
int b;
b = a;
cout << b << endl;
}
위 코드를 실행하면 3이 출력된다.
위 코드에서 3.4가 3으로 자동 변환되었다.
명시적 형 변환
직접 형변환을 지정해 주는 것을 말한다.
(int), (float)등으로 지정해 준다.
int main(){
float a = 3.4f;
int b;
b = (int) a;
cout << b << endl;
}
c++ 에는 Cast Operator라고 하는 형변환이 따로 있다.
1. static_cast
2. const_cast
3. reinterpret_cast
4. dynamic_cast
static_cast
사용법: static_cast<type>(expression)
int main(){
float a = 3.4f;
int b;
b = static_cast<int>(a);
cout << b << endl;
}
정수 외에도 많은 것을 변환 가능하다.
논리적으로 변경이 가능하면 거의 모든 경우에서 변경해준다.
하지만 서로 다른 타입의 포인터 끼리는 타입 변환이 불가능하다.
Reinterpret Casting
사용법: reinterpret_cast<type>(expression)
Reinterpret : 재해석
- 값에 대한 type casting은 불가능하고,
- Pointer에 대한 type casting을 위한 것이다.
예를 들면 int*를 char*로 변경할 수 있다.
#include <iostream>
using namespace std;
int main(){
int number = 12345;
int* intPointer = &number;
cout << *intPointer << endl;
// int* to char*
char* charPointer = reinterpret_cast<char*>(intPointer);
// 변환된 포인터를 이용한 메모리 접근
for (int i = 0; i < sizeof(int); ++i) {
std::cout << "Byte " << i << ": " << static_cast<int>(charPointer[i]) << std::endl;
}
int* intPointerAgain = reinterpret_cast<int*>(charPointer);
cout << *intPointer << endl;
}
위 코드에서는 12345로 테스트를 진행한다. int가 char로 변경될때는 바이트 단위로 나누어지게 된다. int는 4바이트, char는 1바이트이다.
12345를 16진수로 나타내면, 4바이트이므로 8자리가 나오게 되고, 0x00003039이다. 이걸 1바이트씩 나누면 0x30, 0x39이므로 위 코드 실행결과는
12345
Byte 0: 57
Byte 1: 48
Byte 2: 0
Byte 3: 0
12345
와 같이 나오게 된다.
Const casting
const casting은 객체의 상수성을 제거 또는 추가하는데 사용된다.
#include <iostream>
void modifyValue(const int* ptr) {
// const_cast를 사용하여 const를 제거
int* nonConstPtr = const_cast<int*>(ptr);
*nonConstPtr = 20; // 이제 값을 수정할 수 있습니다.
}
int main() {
int x = 10;
const int* ptr = &x;
std::cout << "Before modifyValue: " << x << std::endl;
modifyValue(ptr);
std::cout << "After modifyValue: " << x << std::endl;
return 0;
}
위 코드는 const_cast를 통해 객체의 상수성을 제거하는 과정을 나타낸다.
또는 상수성을 추가할 수도 있는데, 이는 좀 일반적이지 않기에 여기서는 다루지 않겠다.
dynamic casting
dynamic casting은 객체의 형 변환에서 사용된다.
다음 예제를 살펴보자.
#include <iostream>
#include <typeinfo> // for 'std::bad_cast'
class Base {
public:
virtual ~Base() {} // 다형성을 위해 가상 소멸자 선언
};
class Derived : public Base {
public:
void sayHello() const {
std::cout << "Hello from Derived!" << std::endl;
}
};
위 예제에는 Base 클래스와 이를 상속하는 Derived 클래스가 있다.
int main() {
Base* basePtr = new Derived(); // 업캐스팅 (Derived* -> Base*)
// 다운캐스팅 (Base* -> Derived*)
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr != nullptr) {
derivedPtr->sayHello(); // 다운캐스팅 성공 시 메서드 호출
} else {
std::cout << "dynamic_cast 실패: basePtr을 Derived*로 변환할 수 없습니다." << std::endl;
}
delete basePtr;
return 0;
}
위 예제는 성공적으로 작동하게 된다.
주의할 점이 있다. 위 코드에서 basePtr은 원래 Derived 객체를 가르켰기에 basePtr이 Derived*타입으로 변환될 수 있었던 것이다.
다음 코드에서는 에러가 발생한다.
int main() {
Base baseObj;
Base& baseRef = baseObj;
try {
Derived& derivedRef = dynamic_cast<Derived&>(baseRef);
derivedRef.sayHello();
} catch (const std::bad_cast& e) {
std::cout << "dynamic_cast 실패: " << e.what() << std::endl;
}
return 0;
}
변환에 실패하게 되면 std::bad_cast 예외를 생성한다.