기존의 c에서 캐스팅 방법은 (type)(표현식)으로 표현했다. 그러나 c++에서는 c++에서 제공하는 캐스트 연산자를 사용하고 c스타일의 캐스팅은 지양해야 한다.
그이유는 다음과 같다.
- c 스타일의 캐스팅은 타입 안정성을 보장하지 못한다 (버그를 발생시킬 가능성이 매우 높다.)
- c++스타일의 캐스팅을 하면 가독성이 좋아진다. (project에서 ***_cast만 검색하면 된다.)
- c++스타일의 캐스트 연산자는 보다더 세부적인 캐스팅을 지원한다. 즉, 상황에 적절하고 세부적인 캐스팅을 지원하는 연산자이다.(c스타일의 캐스팅은 모든 범위를 포함)
c++에서 제공하는 cast 연산자는 총 4개이다.
- const_cast<T>
- dynamic_cast<T>
- reinterpret_cast<T>
- static_cast<T>
1. const_cast
const_cast는 상수성을 없애거나 만드는 용도로 사용된다. const를 제거(캐스팅)후 값을 변경한다음 출력해보면 1이 나온다. 즉 casting은 가능하지만 값 변경은 불가
ex) const 제거
void test(int * val){
(*val) = 10;
}
int main(void){
const int a = 1;
test(const_cast<int *>(&a));
cout<<a<<endl;
return 0;
}
[실행결과]
1
Program ended with exit code: 0
ex) const 생성
void test(const int * val){
cout<<(*val)<<endl;
}
int main(void){
int a = 1;
test(const_cast<const int *>(&a));
return 0;
}
2. dynamic_cast
dynamic_cast는 좀 독특한점이 상속(+다형성)관계에 있는 포인터들을 캐스팅해주는 연산자이다. 즉, 업캐스팅(자식->부모), 다운캐스팅(부모->자식), 크로스캐스팅(형제->형제)를 지원한다. 캐스팅의 실패시 NULL을 반환한다.
추가적으로 dynamic_cast는 runtime 시 포인터 값을 얻어오고 비용이 매우 높다.
ex) upcasting (사실 upcasting시엔 dynamic_cast연산자를 쓸필요 없이 대입하면 된다.)
class Base{
private:
Temp t;
public:
Base(){
}
~Base(){
}
void show() const {
cout<<"show Base"<<endl;
}
};
class Derived : public Base{
public:
Derived(){
}
void show() const {
cout<<"show Derived"<<endl;
}
};
int main(void){
Derived * child = new Derived();
Base * parent = new Base();
parent = dynamic_cast<Base *>(child);
parent->show();
return 0;
}
ex) downcasting(반드시 다형성 관계를 가져야 한다. 실제 개발에서 이러한 다운캐스팅을 본적은 아직 없다.)
class Base{
private:
Temp t;
public:
Base(){
}
~Base(){
}
virtual void show() const {
cout<<"show Base"<<endl;
}
};
class Derived : public Base{
public:
Derived(){
}
virtual void show() const {
cout<<"show Derived"<<endl;
}
};
int main(void){
Derived * child = new Derived();
Base * parent = new Base();
parent = dynamic_cast<Base *>(child);
parent->show();
return 0;
}
실행결과 show Derived
3. reinterpret_cast
reinterpret은 재해석하다라는 뜻이있다. 말그대로 서로다른 타입들을 캐스팅해주는 가장 c스타일의 캐스팅에 가까운 연산자이다. 하지만 const_cast의 역할은 하지 못한다.
static void callback_func(void * userData) {
MyData * myData = reinterpret_cast<MyData *>(userData);
myData->getReadOnly();
}
int main(void){
MyData * myData = new MyData();
regiseter_callback(callback_func(static_cast<void *>(myData)));
return 0;
}
그러나 다음과 같은 캐스팅은 불가능하다.
int a = 10;
float f;
f = reinterpret_cast<float>(a); //Reinterpret_cast from 'int' to 'float' is not allowed
4. static_cast
static_cast는 캐스팅이 논리적으로 적법한 경우에만 사용 가능하다. 좀더 안정적인 캐스팅을 지원한다.
ex)
int main(void){
int a = 10;
float f;
f = static_cast<float>(a);
cout<<a<<endl;
return 0;
}
논리적으로 적법하지 않은 다음과 같은 경우 컴파일 에러가 발생한다.
int main(void){
int a = 10;
double * d = static_cast<int>(a);
cout<<d<<endl;
return 0;
}
'C and C++' 카테고리의 다른 글
[C++] NVI (non-virtual interface) idiom 비가상 인터페이스에 대해 (0) | 2018.08.11 |
---|---|
[C++] pImpl(pointer to implementation)를 이용해서 인터페이스와 구현을 분리하기 (0) | 2018.08.05 |
[C++] 클래스를 캡슐화(Encapsulation) 하는 이유(왜 멤버변수는 대부분 private인가?) (1) | 2018.07.18 |
[C++] 객체의 값을 전달할때 복사 비용을 줄이는 방법 "상수객체 참조자" (0) | 2018.07.10 |
[C++] RAII스타일로 동작하는 lock_guard (0) | 2018.06.25 |