일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- effective stl
- 상속
- 메타테이블
- 참조자
- reference
- implicit conversion
- 게임
- 언리얼
- 영화 리뷰
- 함수 객체
- 영화
- 암시적 변환
- lua
- exception
- resource management class
- virtual function
- c++
- Smart Pointer
- UE4
- 비교 함수 객체
- 예외
- 반복자
- 루아
- 오블완
- operator new
- Effective c++
- 스마트 포인터
- more effective c++
- 다형성
- 티스토리챌린지
Archives
- Today
- Total
스토리텔링 개발자
[More Effective C++] 2. C++ 스타일 캐스팅 본문
728x90
항목 2 : 가능한 C++ 스타일의 캐스트를 즐겨 쓰자.
C 스타일 캐스트의 문제점
- 타입을 다른 타입으로 제한 없이 바꾸어준다.
- 어떤 객체의 상수성(copnstness)만을 바꾼다.
- 기본 클래스 객체에 대한 포인터를 파생 클래스 객체에 대한 포인터로 바꾼다.
- 위 둘은 전혀 다른 캐스트지만, C 스타일 캐스트는 이 모든 걸 별 말 없이 소화해버리기 때문에 위험하다.
- C 스타일 캐스트는 눈으로 찾아내기가 힘들다.
- 식별자를 괄호로 둘러싼 것일 뿐이기 때문이다.
int firstNumber, secondNumber;
...
// c 스타일 캐스트
double result = ((double)firstNumber) / secondNumber;
// c++ 스타일 캐스트
// 인간의 눈이나 프로그램이나 발견하기 쉬운 캐스트
double result2 = static_cast<double>(firstNumber) / secondNumber;
C++ 스타일 캐스트의 종류
- static_cast
- C 스타일 캐스트와 같은 의미와 형변환 능력을 가지고 있는, 기본적인 캐스트 연산자.
- 제약도 C 스타일 캐스트와 동일하다.
- struct -> int 캐스트, double -> 포인터 캐스트 등은 불가능하다.
- 상수성 제거도 불가능하다.
- const_cast
- 표현식의 상수성(constness)이나 휘발성(volatileness)을 없애는 데 사용한다.
- const나 volatile 특성을 바꾸고 싶을 때'만' 사용한다.
class Widget { ... };
class SpecialWidget : public Widget { ... };
void update(SpecialWidget* psw);
SpecialWidget sw;
const SpecialWidget& csw = sw; // 상수 객체로 참조
// 실패 코드
update(&csw); // 상수 객체는 넣을 수 없으므로 컴파일 에러!
// 성공 코드
update(const_cast<SpecialWidget*>(&csw)); // const 제거
update((SpecialWidget*)&csw); // C 캐스트 스타일로 const 제거
Widget* pw = new SpecialWidget;
// 실패 코드
update(pw); // Widget* 을 넣으려 하므로 컴파일 에러!
update(const_cast<SpecialWidget*>(pw)); // const_cast는 상수성만 제거 가능하므로 컴파일 에러!
- dynamic_cast
- 상속 계층 관계를 가로지르거나 하향시킨 클래스 타입으로 안전하게 캐스팅한다.
- 기본 클래스 포인터, 참조자 타입 -> 파생, 형제 클래스 포인터, 참조자 타입
- 실패 시
- 포인터 캐스팅의 경우 널 포인터 리턴
- 참조자 캐스팅의 경우 예외 발생
- 제약
- 상속 계층 구조를 오갈 때만 가능하다.
- 가상함수가 없는 타입에는 적용이 불가하다.(항목 24 참조)
- 상수성 제거가 불가능하다.
Widget* pw;
// 포인터 다운 캐스팅
update(dynamic_cast<SpecialWidget*>(pw));
// 실패 시 null 포인터 리턴
void updateViaRef(SpecialWidget& rsw);
// 참조자 다운 캐스팅
updateViaRef(dynamic_cast<SpecialWidget&>(*pw));
// 실패 시 예외 발생
// 제약으로 인한 캐스팅 실패
int firstNumber, secondNumber;
double result = dynamic_cast<double>(firstNumber) / secondNumber; // 컴파일 오류!!
// 가상 함수가 전혀 없다.
const SpecialWidget sw;
update(dynamic_cast<SpecialWidget*>(&sw)); // 컴파일 오류!!
// 상수성을 제거하는 데 사용하려 했다.
- reinterpret_cast
- 변환 결과가 거의 항상 컴파일러에 따라 다르게 정의되어 있다.
- 직접 이식이 불가능하다.
- 보통 함수 포인터 타입 변환에 사용한다.
- 하지만 이는 소스의 이식성을 저하시킨다.
- 어떤 경우 이런 캐스팅은 잘못된 결과를 도출한다.(항목 31 참조)
- 그러므로 피하도록 하자.
- 변환 결과가 거의 항상 컴파일러에 따라 다르게 정의되어 있다.
typedef void (*FuncPtr)(); // 함수 포인터
FuncPtr funcPtrArray[10]; // 함수 포인터에 대한 배열
int doSomething(); // 이를 funcPtrArray에 넣고자 하면..
// 실패 코드
funcPtrArray[0] = &doSomething; // 타입 불일치로 컴파일 에러
// 성공 코드
funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething); // 컴파일 성공
참조
728x90
'개발 > More Effective C++' 카테고리의 다른 글
[More Effective C++] 6. operator++ / operator-- (0) | 2024.08.06 |
---|---|
[More Effective C++] 5. 암시적 변환 지양하기 (0) | 2024.08.05 |
[More Effective C++] 4. 불필요한 기본 생성자 미제공하기 (0) | 2024.08.04 |
[More Effective C++] 3. 다형성 객체의 배열 지양하기 (0) | 2024.08.03 |
[More Effective C++] 1. 포인터 vs 참조자 (0) | 2024.08.01 |
Comments