출처: http://kukuta.tistory.com/25
/**
예전에 한번 보긴 했었지만, 거의 C style의 type casting만을 사용하다 보니 내 머리 속에서 점점 잊혀져 가고 있다.
C style의 type casting이 사용하기도 쉽고, 자유도가 높긴 하지만 여러가지 오류의 소지도 있고, 코드도 지저분하게 만든느 경향이 있으므로 앞으로는 C++ style의 type casting을 사용 하기로 결심. 이렇게 다시 한번 정리 한다.
*/
* static_cast
static_cast는 C에서의 type casting의 제한된 버젼이라고 생각하면 된다. 다만 C와의 차이점은 상속 트리 내에서의 포인터 형 변환만이 가능하다는 것이다.
즉, 상속 트리 내에서 부모나 자식간으로의 포인터 casting은 가능하지만 전혀 관계가 없는 type으로 casting 하고자 하면 컴파일 타임에 오류가 난다.
};
class B : public A {
};
class C {
};
A* a = new A;
// B는 A의 자식이므로 casting이 가능하다. 또한 그 반대로도 가능하다.
B* b = static_cast<B*>(a);
// 컴파일 오류
C* c = static_cast<C*>(a);
* const_cast
const_cast는 서로 다른 형간의 변환을 수행하지는 못하지만 대신 const가 아니었던것을 const로 만들거나, const였던것을 non-const로 만들 수 있다. 하지만 일반적으로 non-const type을 const로 바꾸는 경우는 거의 없으며 그리 제한적인 변경이 아니므로 자동적인 type casting이 일어난다. 하지만 const를 non-const type으로 변경 하는 것은 명시적으로 지정 해 주어야만 한다.
};
class B : public A{
};
int main() {
A* a = new A;
// 컴파일 오류 invalid const_cast from type `A*' to type `B*'
B* b = const_cast<B*>(a);
const int ci = 10;
int* pi = const_cast<int*>(&ci);
*pi = 1000;
std::cout << pi << " " << *pi << std::endl;
std::cout << &ci << " " << ci << std::endl;
}
※ 신기한 것은 같은 주소 공간에 서로 다른 값을 가지고 있다는 것이다. 이것을 어떻게 설명 해야 하는 것인고..
* reinterpret_cast
C style type casting과 똑같은 위력을 발휘한다. type, 상속 관계에 관계 없이 어떤 내장형, 어떤 포인터형이든지 다 casting이 가능하다.
※ 각종 예외상황들은 해당 컴파일러에 따라 다르게 처리된다.
* dynamic_cast
다른 casting과 dynamic_cast의 차이점은 다른 여타 cast 연산자들은 컴파일 타임에 컴파일러에 의해 평가되며, 정상적인 컴파일 또는 오류로 결과가 나타난다. 하지만 dynamic_cast는 casting의 가능 여부를 런타임시에 평가하며 내장 테이터 형을 제외한 포인터나 참조에만 이용 할 수 있다.
dynamic_cast는 static_cast와 달리 두 포인터가 동일한 상속 트리에 있는지 확인하지 않으며 포인터가 참조하는 개체의 실제 형을 확인하고 변환이 가능한지를 확인한다. 만일 가능하다면 다중 상속을 처리하기 위한 오프셋 계산까지 마친 새로운 포인터를 리턴하고, 불가능 하다면 NULL 포인터를 리턴한다.
보다 자세한 설명을 위해 아래의 예를 살펴 보도록 하자 :
{
public :
virtual void polymorphic() = 0;
};
class DeriveA : public Parent
{
public :
virtual void polymorphic() {
}
};
class DeriveB : public Parent
{
public :
virtual void polymorphic() {
}
};
int main(int argc, char** argv)
{
Parent* p = new DeriveA;
DeriveB* db = dynamic_cast<DeriveB*>(p);
if(NULL == db)
{
std::cout << "It is not a instance of DeriveB" << std::endl;
}
else
{
std::cout << "It is a instance of DeriveB" << std::endl;
}
DeriveA* da = dynamic_cast<DeriveA*>(p);
if(NULL == da)
{
std::cout << "It is not a instance of DeriveA" << std::endl;
}
else
{
std::cout << "It is a instance of DeriveA" << std::endl;
}
return 0;
}
※ dynamic_cast를 사용하기 위해서는 컴파일러의 RTTI(real time type infomation) 옵션을 켜놓아야 한다.
위의 코드를 컴파일 하여 결과를 살펴 보면 :
It is a instance of DeriveA
와 같이 나올 것이다.
요약을 하자면, DeriveA의 인스턴스는 다형성을 이용하기 위해 부모 클래스의 포인터를 이용하고 있고, dynamic_cast는 런타임시에 어떤 자식 클래스의 인스턴스인지 부모 클래스의 포인터를 통해서 알아 낼 수 있는 것이다.
다이나믹 캐스트에 대한 보다 자세한 설명은 아래 링크 참조 :
http://www.cprogramming.com/reference/typecasting/dynamiccast.html