C++에서는 C 언어에서 사용하던 전통적인 형변환 방식((자료형)값)도 여전히 지원한다. 그러나 C 스타일 형변환은 너무 포괄적이고, 안전성이 떨어진다는 단점이 있다.
즉, 맞는 변환인지 아닌지를 컴파일러가 제대로 검사하지 못한다는 것이다.
예를 들어, int* 같은 포인터를 float 같은 기본형으로도 바꿀 수 있으며, 이 경우 프로그램의 안정성은 전적으로 프로그래머의 책임이다.
이를 보완하기 위해 C++에서는 4가지 형변환 연산자를 제공한다:
- reinterpret_cast
- const_cast
- static_cast
- dynamic_cast
아래에서 각각의 특징과 사용법을 살펴본다.
1. C 스타일 형변환의 한계
- C 스타일 형변환
· (자료형)값 형태를 사용한다.
· 컴파일러는 변환이 합법적인지 여부를 검사하지 않는다.
· 상위 클래스와 하위 클래스 간의 잘못된 변환도 그대로 통과된다.
💻 예제 코드
#include <iostream>
using namespace std;
class Ex {
public:
Ex() { cout << "Ex 생성자" << endl; }
};
class cEx : public Ex {
public:
cEx() { cout << "cEx 생성자" << endl; }
};
int main() {
Ex* ex = new cEx(); // 업캐스팅 (안전)
cEx* cex1 = (cEx*)ex; // 다운캐스팅 (위험 가능)
Ex* ex2 = new Ex();
cEx* cex2 = (cEx*)ex2; // ❗ 잘못된 다운캐스팅 (컴파일러는 오류를 잡아내지 못함)
return 0;
}
📌 위 코드에서 cex2는 실제로 Ex 객체를 가리키고 있지만, 강제로 cEx*로 변환하였다. 이는 정의되지 않은 동작(UB, Undefined Behavior)을 초래한다.
✅ 따라서, C++에서는 목적에 맞는 형변환 연산자를 사용하는 것이 안전하다.
2. reinterpret_cast
· 전혀 상관없는 자료형으로의 형변환에 사용한다.
· 포인터, 정수, 참조 등과 관련된 모든 변환을 허용한다.
· 성공 여부는 컴파일러가 보장하지 않는다. 책임은 프로그래머에게 있다.
사용법
· reinterpret_cast<T>(대상)
💻 예제 코드
#include <iostream>
using namespace std;
int main() {
int num = 65;
char* ch = reinterpret_cast<char*>(&num); // int* → char*
cout << "첫 번째 바이트 값: " << *ch << endl;
void* ptr = #
int* intPtr = reinterpret_cast<int*>(ptr); // void* → int*
cout << "재해석된 값: " << *intPtr << endl;
return 0;
}
📌 위 예시는 정상적인 reinterpret_cast 사용이다.
그러나 전혀 무관한 객체 포인터끼리 변환하면 프로그램 오류가 발생할 수 있다.
3. const_cast
· const 성질을 제거할 때 사용한다.
· const 키워드를 강제로 무시할 수 있다.
사용법
· const_cast<T>(대상)
💻 예제 코드
#include <iostream>
using namespace std;
void showStr(char* str) {
cout << str << endl;
}
int main() {
const char* str = "C++ 배우기";
showStr(const_cast<char*>(str)); // const 제거 후 전달
return 0;
}
⚠️ 주의: 원래 const로 선언된 값을 수정하려 하면 정의되지 않은 동작이 발생한다.
따라서 const_cast는 읽기 전용 데이터를 수정하는 용도로 사용하면 안 된다.
4. static_cast
· 상속 관계에서의 업캐스팅, 다운캐스팅에 사용한다.
· 기본 자료형 간의 변환에도 사용한다.
· 잘못된 형변환을 해도 컴파일러가 에러를 잡지 못하므로 프로그래머의 주의가 필요하다.
사용법
· static_cast<T>(대상)
💻 예제 코드
#include <iostream>
using namespace std;
class Ex {
public:
virtual void show() { cout << "Ex 클래스" << endl; }
};
class cEx : public Ex {
public:
void show() override { cout << "cEx 클래스" << endl; }
};
int main() {
Ex* ex = new cEx();
cEx* cex = static_cast<cEx*>(ex); // 다운캐스팅 (위험 가능, 책임은 프로그래머)
cex->show();
float result = static_cast<float>(10) / 3; // 기본형 변환
cout << "나눗셈 결과: " << result << endl;
return 0;
}
5. dynamic_cast
· 상속 관계에서 안전한 형변환을 수행한다.
· 다운 캐스팅은 가상 함수(virtual function)가 있는 클래스에서만 동작한다. (Polymorphic Class)
· 업캐스팅은 항상 허용되며, 다운캐스팅은 유효성 검사를 거쳐 안전하게 수행된다.
· 잘못된 변환은 nullptr(포인터 변환 시) 또는 bad_cast 예외(참조 변환 시)를 발생시킨다.
사용법
· dynamic_cast<T>(대상)
💻 예제 코드
#include <iostream>
using namespace std;
class Ex {
public:
virtual void show() { cout << "Ex 클래스" << endl; } // 가상 함수
};
class cEx : public Ex {
public:
void show() override { cout << "cEx 클래스" << endl; }
};
int main() {
Ex* ex1 = new cEx();
cEx* cex1 = dynamic_cast<cEx*>(ex1); // 안전한 다운캐스팅
if (cex1) cex1->show();
Ex* ex2 = new Ex();
cEx* cex2 = dynamic_cast<cEx*>(ex2); // ❗ 실패 → nullptr 반환
if (!cex2) cout << "변환 실패 (nullptr 반환)" << endl;
return 0;
}
✅ 마무리 정리
1️⃣ C 스타일 형변환은 안전하지 않고, 책임은 전적으로 프로그래머에게 있다.
2️⃣ reinterpret_cast는 포인터/정수 재해석 시 사용하며 안전성은 보장되지 않는다.
3️⃣ const_cast는 const 속성을 제거한다. 잘못 사용하면 UB 발생 가능하다.
4️⃣ static_cast는 상속 관계나 기본형 변환에 사용되며, 책임은 프로그래머에게 있다.
5️⃣ dynamic_cast는 가상 함수가 있는 상속 관계에서만 안전하게 다운캐스팅을 수행한다. 실패 시 nullptr 또는 bad_cast 예외가 발생한다.
'Language > C++' 카테고리의 다른 글
| 📌예제 - 온라인 쇼핑몰 주문 관리 시스템 (0) | 2025.11.01 |
|---|---|
| 📌예제 - 은행 계좌 관리 시스템 (고급 구현) (0) | 2025.10.31 |
| 📌 Chapter 13 - 예외처리 (Exception Handling) (0) | 2025.10.28 |
| 📌 Chapter 12 - 클래스 템플릿 (0) | 2025.10.24 |
| 📌 Chapter 12 - 템플릿 (0) | 2025.10.24 |