3. C 스타일 캐스트
다양하게 사용될 수 있으나 이식성을 확인해주지 않는다.
- 용도 파악이 힘들다, 안전하지 않다
단순히 식별자를 괄호롤 둘러싸는 방식이므로 보기가 힘듬
- 가독성이 저하된다
=> 코드 읽기도 힘들고 버그도 잘나고 원인 찾기도 무척 어렵다.
4. 예제
int integerNumber;
double multiple = 50.2, divide=5.5;
double result = (int)((double)integerNumber*multiple)/(int)divide;
int integerNumber = (int)30.5;
int a;
double* p = (double*)&a;
5. C++ 스타일 캐스트
static_cast, const_cast, dynamic_cast, reinterpret_cast
구체적인 목적을 둔 연산자로 용도 파악이 쉽고 안전하도록 함
사용 방식이 간단하지 않아 눈에 잘 띄므로 가독에 도움을 줌
6. static_cast
C 스타일 캐스트와 같은 의미와 형변환 기능을 지님
- 같은 제약을 받음( 구조체->기본형, 기본형->포인터가 안되는 등.. )
- 안전하지 않은 경우도 있음
상수성(const)을 떼어내지는 못함
- 다른 캐스트 연산자에서 지원하므로 분리되어 있음
=> 아 이건 C처럼 캐스팅할게 필요해서 쓴거구나
7. 예제
int firstNumber, secondNumber;
...
double result = ((double)firstNumber)/secondNumber;
int firstNumber, secondNumber;
...
double result = static_cast<double>(firstNumber)/secondNumber;
C 캐스트
static_cast
9. 예제
void Update( int* a )
{
a += 50;
}
int main( const char* argc, int argv )
{
int a = 50;
const int* pa = &a;
Update( pa ); // 에러
Update( const_cast<int*>( pa ) );
}
10. dynamic_cast
상속 관계에 있는 클래스 타입을 캐스팅 할 때 사용
- 캐스팅 불가능하면 알려주므로 안전하다!
- 포인터는 nullptr 반환
- 참조자는 예외 throw
가상함수가 없으면 적용 불가
- 안전을 위함이므로 상관없다, 이유는 이후에 나옴(RTTI)
=> 상속 관계에 있는 타입으로 캐스팅 하고싶어서 썼구나
11. 예제
class parent
{
public: virtual ~parent(){}; // 가상 함수가 있어야만 가능하므로
};
class child : public parent {};
class child2 : public parent {};
int main( const char* argc, int argv )
{
child childClass;
parent* parentClass = &childClass;
child* savedChild = dynamic_cast< child* >( parentClass );
child2* anotherChild = dynamic_cast< child2* >( parentClass ); // nullptr 반환!
}
12. reinterpret_cast
포인터 타입을 막무가내로 캐스팅 할 때 주로 사용
변환 결과가 컴파일러에 따라 다르게 정의되어 있다.
- 소스 직접 이식이 불가능하다
- 윈도우즈에서 하던거 리눅스로 들고가니 전혀 다른 동작….
=> 로우레벨 로직 아니면 쓸일 없을듯, 웬만하면 사용 X
13. 예제
void print( int a )
{
printf("%dn", a);
}
typedef void (*FuncPtr)();
typedef void (*printFuncPtr)( int );
int main( const char* argc, int argv )
{
std::vector< FuncPtr > functions;
functions.push_back( reinterpret_cast< FuncPtr >( print ) );
void (*myPrint)( int ) = reinterpret_cast< printFuncPtr >( functions[0] );
myPrint( 5 );
}
함수 포인터 타입이 달라도 모두 동일한 구조라는 보장이 없으므로 무척 위험한 코드
14. 컴파일러에서 지원하지 않는 경우
#define static_cast (TYPE, EXPR) ((TYPE)(EXPR))
#define const_cast(TYPE, EXPR) ((TYPE)(EXPR))
#define reinterpret_cast(TYPE, EXPR) ((TYPE)(EXPR))
#define dynamic_cast(TYPE, EXPR) ((TYPE)(EXPR))
Double result = static_cast(double, firstNumber)/secondNumber;
Update(const_cast(SpecialWidget*, &sw));
funcPtrArray[0] = reinterpret_cast(FuncPtr, &doSomething);
derivedClass = dynamic_cast(DerivedClass, baseClass);
15. 아쉬운 부분
형식만 맞춘 것이므로 다르게 사용되어도 검증이 힘들다.
- 안전하지 않다.
Dynamic_cast의 경우는 완전한 기능을 제공하지 못한다.
- 변환 불가능하면 nullptr 반환이나 예외 던지는 기능
16. C++ 캐스트 사용이 불편한 문제
타입 캐스팅은 피해야 하는 것이므로 사용의 불편함은 나쁘지만은 않음
확실한 의미와 인식성을 컴파일러와 개발자에게 선사
의도와 다른 형변환이 이뤄질 시 컴파일 에러 발생
위와같은 장점들을 위안으로 삼자