Animal*myPet=newCat(2,"Coco");Cat*myCat=static_cast<Cat*>(myPet);// 당연히 됨. 상속 관계니까.Dog*myDog=static_cast<Dog*>(myPet);// 컴파일은 됨.// 컴파일러가 체크하는 건 Dog와 Animal간의 상속 관계가 있느냐는 것 뿐.// 그래서 캐스팅은 해주는데, myDog은 사실 Cat이니까myDog->GetDogHouseName();// Dog에 있는 함수 호출 해주면 문제가 생길 수 있음. 함수 자체가 없으니
예시 2
1
2
3
4
Animal*myPet=newCat(2,"Coco");House*myHouse=static_cast<House*>(myPet);// 컴파일 에러myHouse->GetAddress();// House하고 Cat은 아무런 상속 관계가 없어;
2. 리인터프리트 캐스팅 (Reinterpret_cast)
interpret : 해석
즉 재해석 한다는 것.
가장 위험한 캐스팅.
연관 없는 두 포인터 형 사이의 변환을 허용
Cat* <-> House*
char* <-> int*
포인터와 포인터 아닌 변수 사이의 형 변환을 허용
Cat* <-> unsigned int
이진수 표기는 달라지지 않음
컴퓨터는 결과적으로 이진수를 저장할 뿐, 이렇게 해석해달라고 코딩을 하는 것이다.
그래서 이진수는 그대로 둔 채, A를 B로 해석해달라- 고 하는 것.
1
2
3
4
5
6
7
8
9
10
11
int*signedNumber=newint(-10);unsignedint*unsignedNumber1=static_cast<unsignedint*>(signedNumber);// 컴파일 에러. 유효하지 않은 형 변환// int 포인터를 unsigned int포인터로 읽어버리면, -10이 unsigned int 최대값이 되어버림. // 왜냐면 signed int 에서 부호비트(첫번째 비트)는 -일 경우 1로 되어 있으니까...// 이진수는 그대로 둔 채 해석이 바뀌는 것이므로, 최대값이 된다 이 말임.unsignedint*unsignedNumber2=reinterpret_cast<unsignedint*>(signedNumber);// 컴파일 됨. 하지만 값은 더이상 -10이 아님! // unsigned int 의 최대값이 되어버림.
voidFoo(constchar*name){char*str=const_cast<char*>(name);// const를 뗀 다음 첫 글자를 바꾸고 있는 코드;;*str='p';// 잘못된 코드}
언제 쓰냐면… 써드파티 라이브러리가 const를 제대로 사용하지 않을 때
1
2
3
4
5
6
7
8
voidWriteLine(char*ptr);// 뭔가 별로인 외부 라이브러리// 출력한다는 함수라고 가정할 때, 내용물이 바뀌지 않아야 하는데// 그런 보장이 없음voidMyWriteLine(constchar*ptr)// 내 프로그램에 있는 함수 새로 작성{WriteLine(const_cast<char*>(ptr));// const로 받아서 떼고 넘겨주면 된다}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Animal*myPet=newCat(2,"Coco");constAnimal*petPtr=myPet;Animal*myAnimal1=(Animal*)petPtr;// const 떼줘! 그냥 Animal* 로 바꿀래!// 컴파일 가능Cat*myCat1=(Cat*)petPtr;// 나 Cat*으로 바꿀래! //컴파일 가능Animal*myAnimal2=const_cast<Animal*>(petPtr);// Animal로 바꿀건데 const_cast 사용할래!// 컴파일 가능. const 떼는 거니까 뭐...Cat*myCat2=const_cast<Cat*>(petPtr);// Cat으로 바꿀건데 const_cast 사용할래!// 컴파일 에러. 형 변환 허용 안함! static_cast 써야 함.
4. 동적 캐스팅 (dynamic_cast)
실행 중에 형을 판단
포인터 또는 참조 형을 캐스팅 할 때만 쓸 수 있음.
호환되지 않는 자식형으로 캐스팅하려 하면 NULL 반환
따라서 static_cast보다 안전!
하지만 이걸 쓰려면 컴파일 중에 RTTI(실시간 타입정보)를 켜야 한다.
킨다면 typeID를 받아옴.
켜지 않으면 static_cast와 똑같이 작동.
근데 기본적으로 c++ 프로젝트에서 RTTI를 끄는 것이 보통…
c++ 프로젝트에선 성능을 중요시 하므로. 이거 느림.
그래서 직접 RTTI를 구현하기도 함.
몇몇 오브젝트에 대해서 부모 클래스에 mType 이런식으로 넣어놓고,
GetType() 함수를 만들어서 타입 비교를 하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Animal*myPet=newCat();// 컴파일 가능, NULL 반환Dog*myDog=dynamic_cast<Dog*>(myPet);// static_cast 했을 땐 아무 문제 없는 코드였는데...// (물론 Dog에만 있는 함수를 호출한다면 문제가 발생할 수 있음)// 그러나 동적 캐스팅은.. 너 Dog가 아닌데..? Dog이 니 부모도 아니고..? NULL 반환함.// 컴파일 가능, 하지만 GetHouseName() 함수 호출 안 됨. if에서 걸려서.if(myDog!=NULL){myDog->GetHouseName();}
4-1. static_cast vs dynamic_cast
1
2
3
4
5
6
7
8
9
// static_castAnimal*myPet=newCat();// 컴파일 됨. Animal-Dog 과의 관계만 체크하므로.Dog*myDog=static_cast<Dog*>(myPet);// 컴파일 됨. 하지만 어떻게 동작할지 모름. 크래시 날 가능성 있음.myDog->GetHouseName();
1
2
3
4
5
6
7
8
9
10
11
12
// dynamic_castAnimal*myPet=newCat();// 컴파일 됨. 그리고 언제나 NULL을 반환Dog*myDog=dynamic_cast<Dog*>(myPet);// 컴파일 됨. GetHouseName()은 실행되지 않음. if에서 걸려서if(myDog!=NULL){myDog->GetHouseName();}
5. 캐스팅 규칙
기본적으로 static_cast를 쓸 것
reinterpret_cast<Cat> 대신 static_cast<Cat>을 쓰면 컴파일 에러 확인 가능하니까
댓글남기기