형변환
형변환의 개념
형변환(Type Conversion)은 하나의 데이터 타입을 다른 데이터 타입으로 변환하는 과정입니다.
C++에서 형변환은 크게 두 가지로 나눌 수 있습니다.
암시적 형변환
암시적 형변환은 컴파일러가 자동으로 수행하는 변환입니다. 주로 다음과 같은 경우에 발생합니다.
대입 연산에서 서로 다른 타입 간 변환
산술 연산에서 피연산자 간 변환
함수 호출 시 인자 타입 변환
int i = 10;
double d = i; // int에서 double로 암시적 변환
char c = 'A';
int ascii = c; // char에서 int로 암시적 변환
int x = 5, y = 2;
double result = x / y; // 결과는 2.0 (정수 나눗셈 후 double로 변환)
명시적 형변환
명시적 형변환은 프로그래머가 직접 지정하는 변환입니다. C++에서는 여러 가지 방식의 명시적 형변환을 제공합니다.
C 스타일 캐스트
- C언어에서 사용하던 방식으로, 간단하지만 안전하지 않을 수 있습니다.
double d = 3.14;
int i = (int)d; // double에서 int로 명시적 변환
C++ 스타일 캐스트
- C++에서는 더 안전하고 명확한 형변환을 위해 다음 네 가지 캐스트 연산자를 제공합니다.
static_cast
- 컴파일 시간에 형 검사를 수행
- 주로 숫자 타입 간 변환에 사용
double d = 3.14;
int i = static_cast<int>(d);
dynamic_cast
- 주로 클래스의 다형성을 위해 사용
- 런타임에 형 검사를 수행
class Base { virtual void dummy() {} };
class Derived : public Base { /*...*/ };
Base* base_ptr = new Derived;
Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
const_cast
- const 또는 volatile 지정자를 제거
const int* ptr = &value;
int* mutable_ptr = const_cast<int*>(ptr);
reinterpret_cast
- 포인터 타입 간 변환 등 저수준 변환에 사용
- 매우 위험할 수 있으므로 주의 필요
int* p = new int(65);
char* ch = reinterpret_cast<char*>(p);
주요 형변환 사례
- 정수형 간 변환
short s = 1000;
int i = s; // 문제 없음
char c = s; // 데이터 손실 가능성
- 부동소수점형 간 변환
float f = 3.14f;
double d = f; // 문제 없음
f = d; // 정밀도 손실 가능성
- 정수형과 부동소수점형 간 변환
int i = 3;
float f = i; // 문제 없음
i = f; // 소수점 이하 손실
- 포인터 형변환
int* p_int = new int(65);
char* p_char = reinterpret_cast<char*>(p_int);
형변환의 위험성
- 데이터 손실
int large = 1000000;
short small = static_cast<short>(large); // 오버플로우 발생
- 오버플로우/언더플로우
unsigned char uc = 255;
uc++; // 오버플로우: uc는 0이 됨
- 부동소수점 정밀도 손실
double d = 0.1 + 0.2;
float f = static_cast<float>(d); // 정밀도 손실 가능성
안전한 형변환 기법
- 범위 체크
#include <limits>
template<typename T, typename U>
T safe_cast(U value) {
if (value > std::numeric_limits<T>::max() ||
value < std::numeric_limits<T>::min()) {
throw std::overflow_error("Cast would cause overflow");
}
return static_cast<T>(value);
}
numeric_limits
활용
#include <limits>
#include <iostream>
int main() {
std::cout << "int 최대값: " << std::numeric_limits<int>::max() << std::endl;
std::cout << "float 최소값: " << std::numeric_limits<float>::min() << std::endl;
}
실습
- 다양한 형변환 예제
#include <iostream>
int main() {
// 정수형 간 변환
short s = 1000;
int i = s;
long l = i;
std::cout << "short to int: " << i << std::endl;
std::cout << "int to long: " << l << std::endl;
// 부동소수점형 간 변환
float f = 3.14f;
double d = f;
std::cout << "float to double: " << d << std::endl;
// 정수형과 부동소수점형 간 변환
i = static_cast<int>(f);
f = i;
std::cout << "float to int: " << i << std::endl;
std::cout << "int to float: " << f << std::endl;
return 0;
}
- 형변환으로 인한 데이터 손실 사례
#include <iostream>
int main() {
int large = 1000000;
short small = static_cast<short>(large);
std::cout << "Original int: " << large << std::endl;
std::cout << "Converted to short: " << small << std::endl;
double d = 3.14159265358979323846;
float f = static_cast<float>(d);
std::cout << "Original double: " << d << std::endl;
std::cout << "Converted to float: " << f << std::endl;
return 0;
}
static_cast
와dynamic_cast
의 차이점
#include <iostream>
class Base {
public:
virtual void print() { std::cout << "Base" << std::endl; }
virtual ~Base() {}
};
class Derived : public Base {
public:
void print() override { std::cout << "Derived" << std::endl; }
};
int main() {
Base* base_ptr = new Derived();
// static_cast
Derived* derived_ptr1 = static_cast<Derived*>(base_ptr);
derived_ptr1->print(); // 안전하지만, 실제 타입 확인 불가
// dynamic_cast
Derived* derived_ptr2 = dynamic_cast<Derived*>(base_ptr);
if (derived_ptr2) {
derived_ptr2->print(); // 런타임에 타입 확인
} else {
std::cout << "Cast failed" << std::endl;
}
delete base_ptr;
return 0;
}
연습 문제
int
,float
,double
타입 간의 변환을 수행하고, 각 변환 과정에서 발생할 수 있는 정밀도 손실을 관찰하는 프로그램을 작성하세요.- 부호 있는 정수와 부호 없는 정수 간의 변환을 수행하고, 오버플로우가 발생하는 경우를 찾아 결과를 출력하는 프로그램을 작성하세요.
dynamic_cast
를 사용하여 다형성을 가진 클래스 계층에서 안전한 타입 변환을 수행하는 예제를 작성하세요.
참고자료
- C++ 형변환 연산자 : https://en.cppreference.com/w/cpp/language/expressions#Conversions
- C++ Core Guidelines on type safety : http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts
- Effective C++ : Item 27 "Cast operators" by Scott Meyers