INDEX
- C 스타일 캐스팅
- static_cast
- reinterpret_cast
- const_cast
- dynamic_cast
- staic_cast vs reinterpret_cast
- static_cast vs dynamic_cast
- 캐스팅 규칙
- 정리
C 스타일 캐스팅
암시적 캐스팅
- 커파일러가 형을 변환해줌
- 단 형변환이 허용 범위 내에 있어야 함
- 프로그래머가 명시적으로 형 변환을 안할 경우
명시적 캐스팅
-
프로그래머가 형 변환을 직접 하는 것
-
C++ 캐스팅
static_cast
const_cast
dynamic_cast
reinterpret_cast
-
C 스타일 캐스팅
int score = (int)someVariable;
- 문제점 : 위의 코드는 대체 무엇을 할까?
- C++의 4개의 캐스팅 중 하나를 함
- 즉 4개중 뭘 하는지 모름
- 명백한 실수를 컴파일러가 캐치하지 못함
- C++캐스팅이 이러한 문제를 해결
- C++의 4개의 캐스팅 중 하나를 함
- 문제점 : 위의 코드는 대체 무엇을 할까?
정적 캐스팅
- 컴파일 도중에 결정됨
C
float number1 = 3.f; int number2 = (int)number1; Animal* myPet = new Cat(2, "Coco"); Cat* myCat = (Cat*)myPet;
C++
float number1 = 3.f; int number2 = static_cast<int>(number1); Animal* myPet = new Cat(2,"Coco"); Cat* myCat = static_cast<Cat*>(myPet);
리인터프리트(reinterpret) 캐스팅
C
Animal* myPet = new Cat(2,"Coco"); unsigned int myPetAddr = (unsigned int)myPet; cout<<"address:"<<hex<<myPet;
C++
Animal* myPet = new Cat(2,"Coco"); unsigned int myPetAddr = reinterpret_cast<unsigned int>(myPet); cout<<"address:"<<hex<<myPet;
컨스트(const) 캐스팅
C
void Foo(const Animal* ptr) { //Bad code Animal* animal = (Animal*)ptr; animal->SetAge(5); }
C++
void Foo(const Animal* ptr) { //Bad code Animal* animal = const_cast<Animal*>ptr; animal->SetAge(5); }
동적(dynamic) 캐스팅
- 실행 중에 캐스팅
C
Cat* myCat = (Cat*)myPet;
C++
Cat* myCat = dynamic_cast<Cat*>(myPet);
static_cast
정적 캐스팅
C의 경우
//1.값 int number2 = (int)number1; //2.개채포인터 Cat* myCat = (Cat*)myPet;
C++의 경우
//1.값 int number2 = static_cast<int>(number1); //2.개채포인터 Cat* myCat = static_cast<Cat*>(myPet);
-
값
-
두 숫자 형 간의 변환
-
값을 유지 (단 반올림 오차는 제외)
-
이진수 표기는 달라질 수 있음
예시1
int number1 = 3; short number2 = static_cast<short>(number1);
비트값과 값 둘 다 바뀌지 않음
예시2
int number1 = 3; short number2 = static_cast<short>(number1);
비트값은 달라지지만, 사람이 느끼는 값은 달리지지 않음
2.개체 포인터
-
변수형 체크 후 베이스 클래스를 파생 클래스로 변환
-
컴파일 시에만 형 체크 가능
-
실행 도중 여전히 크래시가 날 수 있음
예시1
Ainmal* myPet = new Cat(2, "Coco"); Cat* myCat = static_cast<Cat*>(myPet); //OK Dog* myDog = static_cast<Dog*>(myPet); //컴파일은 됨. 그러나 위험(크래시가 날 수 있다) myDog->GetDogHouseName();
예시2
Animal* myPet = new Cat(2, "Coco"); House* myHouse = static_cast<House*>(myPet); // 컴파일 에러 myHouse->GetAddress();
-
static_cast 사용법
static_cast<<type>> (<variable-name>)
예시
int number2 = static_cast<int>(number1);
Dog* myDog = static_cast<Dog*>(myPet);
reinterpret_cast
reinterpret_cast
-
연관 없는 두 포인터 형 사이의 변환을 허용
-
포인터와 포인터 아닌 변수 사이의 형 변환을 허용
-
이진수 표기는 달라지지 않음
- A형의 이진수 표기를 그냥 B형인 것처럼 해석
-
가장 위험한 캐스팅
C의 경우
unsigned int myPetAddr = (unsigned int)myPet;
C++의 경우
unsigned int myPetaddr = reinterpret_cast<unsigned int>(myPet);
예시
reinterpret_cast 사용법
reinterpret_cast<<type>> (<variable-name>)
예시
Cat* myCat = reinterpret_cast<Cat*>(myPetAddress);
아니 얘를 어따써??
- 포인터를 직렬화(srialize)해야하는 경우
- 포인터를 메모리 주소. int로 저장 가능
const_cast
const_cast
- const또는 volatile 속성을 제거할 때 사용
- const_cast는 포인터 또는 참조형의 상수성(const)를 잠깐 제거해주는데 사용
- volatile키워드를 잠깐 제거해 주는데도 사용
- const_cast로 형을 바꿀 수 없음
-
포인터 형에 사용할 때만 말이 됨 (값 형은 언제나 복사되니까…)
-
예시
C의 경우
void Foo(const Animal* ptr) { Animal* animal = (Animal*)ptr; animal->SetAge(5); }
Animal* myPet -new Cat(2,"Coco"); const Animal* petPtr = myPet; Animal* myAnimal1 = (Animal*)petPtr; //OK Cat* myCat1 = (Cat*)petPtr; //OK
C++의 경우
void Foo(const Animal* ptr) { Animal* animal = const_cast<Animal*>(ptr); animal->SetAge(5); }
Animal* myPet -new Cat(2,"Coco"); const Animal* petPtr = myPet; Animal* myAnimal2 = const_cast<Animal*>(petPtr); //OK Cat* myCat2 = const_cast<Cat*>(petPtr); //컴파일 에러
const_cast를 사용해야 할 때는?
-
일반적인 코드에서 const_cast를 코드에서 쓰려고 한다면 무언가 잘못하고 있는 중이다!!
void Foo(const char* name) { char* str = const_cast<char*>(name); *str = 'p'; } // 바꾸면 안되는걸 바꿈 -> 뭔가 잘못 돌아가고 있다..!
-
서드파티 라이브러리가 const를 제대로 사용하지 않을 때 사용한다
예시
void WriteLine(char* ptr); //뭔가 별로인 외부 라이브러리 void MyWriteLine(const char* ptr) //우리 프로그램에 있는 함수 { //WriteLine()을 사용하기 위해서 어쩔 수 없이 cosnt_cast를 사용 WriteLine(const_cast<char*>(ptr)); }
dynamic_cast
dynamic_cast
- 부모 클래스의 포인터에서 자식 클래스의 포인터로 다운 캐스팅해줌
- 부모 클래스의 포인터가 실제 무엇을 가리키고 있는지가 중요
- 실행 중에 형을 판단
- 포인터 또는 참조 형을 캐스팅할때만 쓸 수 있음
- 호환되지 않는 자식형으로 캐스팅하려 하면 NULL을 반환!
- 따라서 dynamic_cast가 static_cast보다 안전
- 그러나 이걸 쓰려면 컴파일 중에 RTTI(실시간 타입정보, Real-Time Type Information)를 켜야함
- RTTI를 끄면 dynamic_cast와 static_cast가 동일하게 동작
- 근데 보통 C++프로젝트에서 RTTi를 끄는 것이 보통 (과부하를 버틸 수 없기 때문에)
C의 경우
Animal* myPet = new Cat(); //Compiles Dog* myDog = (Dog*)myPet; //Compiles, but crashes myDog->GetHouseName();
C++의 경우
Animal* myPet = new Cat(); //Compiles, and returns NULL Dog* myDog = dynamic_cast<Dog*>myPet; //Compiles, GetHouseName() will not execute if(myDog != NULL) { myDog->GetHouseName(); }
dynamic_cast사용법
dynamic_cast <<type>> (<variable_name>)
예시
Dog* myDog = dynamic_cast<Dog*>(myPet);
staic_cast vs reinterpret_cast
예시
int* signedNumber = new int(-10); //컴파일 에러. 유효하지 않은 형변환 unsigned int* unsignedNumber1 = static_cast<unsigned int*>(signedNumber); //컴파일은 됨. 허나 값은 더 이상 -10이 아님 unsigned int* unsignedNumber2 = reinterpret_cast<unsigned int*>(signedNumber);
static_cast vs dynamic_cast
예시
static_cast 예시
Animal* myPet = new Cat(); //컴파일됨 Dog* myDog = static_cast<Dog*>(myPet); //컴파일됨. 허나 실행 중 어떻게 동작할지 모름. 크래시? myDog->GetHouseName();
dynamic_cast 예시
Animal* myPet = new Cat(); //컴파일됨. 그리고 언제나 NULL을 반환 Dog* myDog = dynamic_cast<Dog*>(myPet); //컴파일됨. GetHouseName()은 실행되지 않음 if(myDog) { mydog->GetHouseName(); }
캐스팅 규칙
제일 안전한 것 -> 가장 위험한 것 순서로 진행
- 기본적으로 static_cast를 쓸 것
reinterpret_cast<Cat*>
대신static_cast<Cat*>
- 만약 Cat이 Animal이 아니라면 컴파일러가 에러를 뱉음
- reinterpret_cast를 쓸 것
- 포인터와 비포인터 사이의 변환
- 이걸 정말 해야 할 때가 많음
- 서로 연관이 없는 포인터 사이의 변환은 그 데이터형이 맞다고 정말 확신할 때만 사용할 것
- 포인터와 비포인터 사이의 변환
- 내가 변경권하니 없는 외부 라이브러리를 호출할 때만 const_cast를 사용할 것
정리
C스타일 캐스팅 대신 C++캐스팅을 쓰는 이유는?
- 좀 더 안전하기 때문에
정적 캐스팅
-
컴파일 시에 실수 잡아줌
-
값을 변환함
-
값이나 포인터에 사용 가능
-
- 포인터 : 부모간의 관계가 있는 두 클래스 사이에 캐스팅인지 확인하여 아닌 경우 컴파일 에러
리인터프리트 캐스팅
- 정말 아무거나 캐스팅 가능하게 해줌
- 포인터 아닌 데이터간에도 캐스팅 가능하게 해줌
컨스트 캐스팅
- 위험하지만 아주 가끔 필요할 경우가 있다.
- 하지만 내가 작성한 코드 안에서 존재하면 문제가 있는 것이다.
- 컨스트 캐스팅은 정말 필요한 경우 아니면 쓰지 말아야한다.
동적 캐스팅
- static_cast는 컴파일 시에만 형을 체크하지만, 동적 캐스팅은 실행 중에 형을 체크한다.
- 캐스팅에 실패하면 NULL포인터를 반환하기 때문에 매우 안전
- RTTI가 켜져야 하기 때문에 쓸 가능성은 적다
어떤 캐스팅을 써야 하지?
-
안전한 캐스팅 -> 위험한 캐스팅
-
- 정적 캐스팅 -> 리인터프리트 캐스팅 -> 컨스트 캐스팅