read
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

Blog Logo

Ki Sung Bae


Published

Image

Gsong's Blog

Developer + Entrepreneur = Entreveloper

Back to Overview