int p; double dou; //same as p = int (dou); p = (int) dou;
위처럼 괄호를 이용한 C-style 캐스팅을 쓸 때의 단점은, 타입체크를 하지 않아서 버그를 만들기 쉽다는 것이다.
C++ 에는 static_cast, dynamic_cast, reinterpret_cast, const_cast 와 같은 cast operator 들이 있는데 각각의 역할을 다시 한번 되새겨 볼 필요가 있다.
static_cast
derived class 의 포인터를 base class 로 캐스팅한다. base class 를 derived class 로 캐스팅하는 데도 쓰인다. compile time 에 타입체크를 한다. 이 외에도 기본적인 타입들의 변환에도 사용된다. 그러나 runtime check 를 하지 않기 때문에, 그리 안전한 선택은 아니다.
int p; double dou; p = static_cast<int> (dou); -------------------------- #include <iostream.h> #include <stdlib.h> int main() { int sum = 1000; int count = 21; double average1 = sum/count; cout<<"Before conversion = "<<average1<<endl; double average2 = static_cast<double>(sum)/count; cout<<"After conversion = "<<average2<<endl; system("pause"); return 0; }
// static_cast_Operator.cpp // compile with: /LD class B {}; class D : public B {}; void f(B* pb, D* pd) { D* pd2 = static_cast<D*>(pb); // Not safe, D can have fields // and methods that are not in B. B* pb2 = static_cast<B*>(pd); // Safe conversion, D always // contains all of B. }
const_cast
타입에 const 키워드를 붙이거나 뗄 때 사용된다. 그 외에 volatile 키워드에도 사용될 수 있다. 역시 컴파일 타임에 타입을 확인한다.
dynamic_cast
이 캐스팅은 객체의 포인터에만 사용한다. 특히 해당 객체를 상속 관계 속에서 캐스팅 할 때 쓰인다. 다른 캐스팅과는 달리 dynamic_cast 는 runtime 시에 작동한다. 그래서 polymorphic class 를 다룰 때 사용한다. 즉 virtual function 을 가지고 있는 클래스 말이다. non polymorphic class 를 다룰 때에는 위에서 살펴본 static_cast 를 사용하면 된다. 만약 주어진 포인터가 캐스팅하기에 적절치 않으면 NULL 을 리턴한다.
dynamic_cast 를 통해 하는 캐스팅에는 다시 upcast, downcast, crosscast 가 있다. upcast 는 derived class 를 base class 로 캐스팅 하는 것이고, downcast 는 그 반대이다. 클래스 상속도 에서 부모 자식 관계를 생각해 보면 되니, 그리 어렵지 않다.
crosscast 는 multiple inheritance 일 때 사용된다. upcast 와 downcast 거기에 더해서 multiple inheritance 가 된다는 것을 이해하면 cross cast 도 쉽게 이해할 수 있다. 예를 들어 다음의 코드를 보자.
// dynamic_cast_6.cpp // compile with: /c /GR class A {virtual void f();}; class B : public A {virtual void f();}; class C : public A { }; class D {virtual void f();}; class E : public B, public C, public D {virtual void f();}; void test(D* pd) { B* pb = dynamic_cast<B*>(pd); // cross cast A* pa = pb; // upcast, implicit conversion } void main() { D* ptr = dynamic_cast<D*>(new E()); // up cast test(ptr); }
test 함수 안을 보면 D 타입의 포인터를 받아 B 타입으로 dynamic_cast 를 하고 있다. main 함수를 참고하면 여기서 넘어가 D* pd 가 가르키는 진짜 object 는 사실 E 객체라는 것을 알 수 있다. 그렇기 때문에 cross cast 할 때 D* 에서 E* (down cast) -> B* (up cast) 되는 두 단계를 거쳐서 캐스팅이 이뤄진다. 만약 D* pd 가 가르키는 것이 new D() 로 만들어진 객체 였다면 cross cast 는 실패하고 NULL 을 리턴할 것이다.
reinterpret_cast
이 캐스트는 아무 포인터를 받아서 어떤 걸로든 캐스트 할 수 있다. 그만큼 강하지만 위험하기도 하다. const 와 volatile 관련해서는 쓸 수 없다. 이 경우는 const_cast 를 써야 한다. 조심해서 써야하는 operator.
References