2020. 6. 16. 19:24ㆍ프로그래밍/C++
암시적(Implicit) 캐스팅
컴파일러가 형을 변환해 줌
>단, 형 변환이 허용되고
>프로그래머가 명시적으로 형 변환을 안 할 경우
int num1 = 3;
long num2 = num1; // 암시적 캐스팅
명시적(Explicit) 캐스팅
프로그래머가 형 변환을 위한 코드를 직접 작성
C++ 캐스팅
1. static_cast
2. const_cast
3. dynamic_cast(C++98, 모던 C++)
4. reinterpret_cast
C 스타일 캐스팅
C++ 스타일 4개의 캐스팅 중 하나를 함
> 뭔가 명확하지 못함
명백한 실수를 컴파일러가 캐치하지 못함
> C++ 캐스팅이 이런 문제를 해결
C 스타일 캐스팅 대신 C++ 캐스팅 쓰는 이유?
> 컴파일 도중에 프로그래머의 실수를 잡아줄 수 있다
static_cast
1. 값
두 숫자 형 간의 변환
> 값을 유지하려고 노력(단, 반올림 오차는 제외)
> 이진수 표기는 달라질 수 있음
예시1)
int number1 = 3;
short number2 = static_cast<short>(number1); // 앞자리 비트가 잘렸을 뿐, 값은 변하지 않음
예시2)
float number1 = 3.f;
int number2 = static_cast<int>(number1); // int 3으로 바이너리가 변함
2. 개체 포인터 (위의 경우와 아예 따로 동작하니까 같다고 생각하지 말자)
변수형 체크 후(너네 정말 상속관계 맞아?) 베이스 클래스를 파생 클래스로 변환
컴파일 시에만(정적, static) 형 체크 가능
실행 도중 여전히 크래시가 날 수 있음
예시1)
Animal* myPet = new Cat(2, "Coco");
Cat* myCat = static_cast<Cat*>(myPet); // OK
Dog* myDog = static_cast<Dog*>(myPet); // 컴파일은 됨. 그러나 위험
myDog->GetDogHouseName(); // Dog 클래스의 멤버를 가지고 있지 않아 크래시가 날 수 있다!
예시2)
Animal* myPet = new Cat(2, "Coco");
House* myHouse = static_cast<House*>(myPet); // 컴파일 에러. 말도 안되는 실수를 저지르려고 할 때
myHouse->GetAddress(); // 컴파일 단계에서 막을 수 있다
reinterpret_cast
재해석
연관 없는 두 포인터 형 사이의 변환을 허용
Cat* <-> House*
char* <-> int*
포인터와 포인터 아닌 변수 사이의 형 변환을 허용
Cat* <-> unsigned int
이진수 표기는 달라지지 않음(바이너리 자체는 변하지 않음)
> A형의 이진수 표기를 그냥 B형인 것처럼 해석
예시1)
// unsigned int myPetAddress;
Cat* myCat = reinterpret_cast<Cat*>(myPetAddress);
예시2)
int* signedNumber = new int(-10);
// 컴파일 에러. 유효하지 않은 형 변환
unsigned int* unsignedNumber1 = static_cast<unsigned int*>(signedNumber);
// 컴파일 됨. 허나 값은 더 이상 -10이 아님
unsigned int* unsignedNumber2 = reinterpret_cast<unsigned int*>(signedNumber);
const_cast 하면안되는캐스팅
const_cast로 형을 바꿀 수 없음
const 또는 volatile 애트리뷰트를 제거할 때 사용
예시)
Animal* myPet = new Cat(2, "Coco");
const Animal* petPtr = mypet;
Animal* myAnimal1 = (Animal*)petPtr; // OK (C-style. 하면 다됨)
Cat* myCat1 = (Cat*)petPtr; // OK (C-style. 하면 다됨)
Animal* myAnimal2 = const_cast<Animal*>(petPtr); // OK
Cat* myCat2 = const_cast<Cat*>(petPtr); // 컴파일 에러. 하고 싶으면 static_cast 해야지~
포인터 형에 사용할 때만 말이 됨
> 값 형은 언제나 복사되니까... 복사해 놓은 값 아무리 써봐야 원본에 영향 없음
const_cast를 사용할 때는?
> 써드파티 라이브러리(내가 소스코드를 볼 수 없는 라이브러리)가 const를 제대로 사용하지 않을 때
>> 이 경우 아니면 진짜진짜진짜 쓰지 말자...
void WriteLine(char* ptr); // 뭔가 별로인 외부 라이브러리
void MyWriteLine(const char* ptr) // 우리 프로그램에 있는 함수. wrapper
{
WriteLine(const_cast<char*>(ptr));
}
dynamic_cast
실행 중에 형을 판단
포인터 또는 참조 형을 캐스팅할 때만 쓸 수 있음
호환되지 않는 자식형으로 캐스팅하려 하면 NULL을 반환
> 따라서, dynamic_cast가 static_cast 보다 안전
그러나 이걸 쓰려면 컴파일 중에 RTTI(실시간 타입정보, Real-Time Type Information)를 켜야 함
> 켜지 않으면 static_cast와 똑같이 동작
>> C++ 프로젝트에서 RTTI를 끄는 것이 보통(성능 중요시 하므로 RTTI를 켜서 얻는 과부하를 버틸수가 없다......)
캐스팅 규칙(베스트 프랙티스)
제일 안전한 것 ->가장 위험한 것
1. 기본적으로 static_cast를 쓸 것
> reinterpret_cast<Cat*> 대신 static_cast<Cat*>
>> 만약 Cat이 Animal이 아니라면 컴파일러가 에러를 뱉음(상속관계 없으면)
2. reinterpret_cast를 쓸 것
> 포인터와 비포인터 사이의 변환
> 서로 연관이 없는 포인터 사이의 변환은 그 데이터형이 맞다고 정말 확신할 때만 할 것
3. 내가 변경권한이 없는 외부 라이브러리를 호출할 때만 const_cast를 쓸 것
출처 : 포큐아카데미 C++ 언매니지드 프로그래밍
'프로그래밍 > C++' 카테고리의 다른 글
static 키워드 (0) | 2020.06.17 |
---|---|
인라인 함수(Inline Functions) (0) | 2020.06.17 |
추상 클래스 / 인터페이스 (0) | 2020.06.12 |
다중 상속 (0) | 2020.06.12 |
가상 함수 / 동적 바인딩 / 다형성 (0) | 2020.06.11 |