C++의 4가지 캐스트 연산자에 대한 이야기 중 두 번째다.
이번은 그중에서 dynamic_cast 에 대해서 이야기한다.
dynamic_cast 는 상속 관계 안에서 포인터나 참조자의 타입을 기본 클래스에서 파생 클래스로의 다운 캐스팅과 다중 상속에서 기본 클래스 간의 안전한 타입 캐스팅에 사용된다.
안전한 타입 캐스팅이란 런타임에 타입 검사를 한다는 것이며 아래에 조금 더 자세하게 나온다.
const_cast와 같이 다른 용도로는 사용하지 못하며 용도가 명확하다.
참고로 dynamic_cast 를 사용하려면 기본적으로 다형성은 이해를 하고 있어야 하며 RTTI도 이해하고 있다면 이 글을 볼 필요가 없을 것이다.
- dynamic_cast 사용
dynamic_cast 를 사용하기 전에 제약 사항을 확인하자.
나름 제약 사항이 많다.
[예제 1] 에서 중요한 내용은 'pDerived = dynamic_cast<Derived*>( pBase );' 에서 볼 수 있듯이 포인터가 실제로 가리키는 대상이 기본 클래스의 객체라면 변환은 실패한다는 것이다.
dynamic_cast 가 캐스팅해주는 것은 포인터나 참조자의 타입을 다운 캐스팅하는 것이지 객체의 타입을 캐스팅하지는 못한다.
dynamic_cast 는 캐스팅에 실패할 때 대상이 포인터라면 널을 리턴하고 참조자였다면 bad_cast 예외를 던진다.
이것이 위에서 언급한 '안전한 타입 캐스팅'의 의미다.
A에서 B로 포인터의 타입을 캐스팅하는 것이 문제없는지 런타임에 검사하여 처리할 수 있다.
다중 상속의 상황에서 기본 클래스 간의 타입 캐스팅을 보자.
[예제 2] 와 같은 캐스팅의 한 사용 예로는 각 기본 클래스 포인터(또는 참조자) 타입의 컨테이너 혹은 배열을 운용하면서 서로 간의 요소를 교환할 때 사용할 수 있다.
[예제 1] 과 같은 캐스팅을 다운 캐스팅이라고 하며 [예제 2] 와 같은 캐스팅을 크로스 캐스팅이라고 한다.
별도로 적지는 않았지만 파생 클래스에서 기본 클래스로의 캐스팅을 업 캐스팅이라고 한다.
업 캐스팅은 캐스팅 연산자가 있으나 없으나 안전하게 캐스팅된다.
- 참고 사항
다중 상속이 발생한다면 설계를 다시 검토하라는 말이 있듯이(있나..-_-?) 다중 상속은 그리 권장하지 않는 방식이다.
이번은 그중에서 dynamic_cast 에 대해서 이야기한다.
dynamic_cast 는 상속 관계 안에서 포인터나 참조자의 타입을 기본 클래스에서 파생 클래스로의 다운 캐스팅과 다중 상속에서 기본 클래스 간의 안전한 타입 캐스팅에 사용된다.
안전한 타입 캐스팅이란 런타임에 타입 검사를 한다는 것이며 아래에 조금 더 자세하게 나온다.
const_cast와 같이 다른 용도로는 사용하지 못하며 용도가 명확하다.
참고로 dynamic_cast 를 사용하려면 기본적으로 다형성은 이해를 하고 있어야 하며 RTTI도 이해하고 있다면 이 글을 볼 필요가 없을 것이다.
객체가 위치한 메모리의 시작부분을 찾는 데도 사용된다는데 사용해 본 적이 없다.
객체를 void* 로 dynamic_cast 하면 시작 주소가 나온다.
[예] void* p = dynamic_cast<void*>( ObjectPointer );
- dynamic_cast 사용
dynamic_cast 를 사용하기 전에 제약 사항을 확인하자.
나름 제약 사항이 많다.
- 상속 관계 안에서만 사용할 수 있다.
- 하나 이상의 가상함수를 가지고 있어야 한다.
- 컴파일러의 RTTI 설정이 켜져 있어야 한다.
[예제 1]위의 [예제 1] 에서 dynamic_cast 의 기본 동작을 볼 수 있다.
class Base
{
public :
virtual void Put( void ) { cout << "Base" << endl; }
};
class Derived : public Base
{
public :
void Put( void ) { cout << "Derived" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
Base* pBase = new Base;
Base* pDerived1 = new Derived;
Derived* pDerived2 = new Derived;
Derived* pDerived = NULL;
// 컴파일 오류 : 타입 변환을 할 수 없다.
//pDerived = pBase;
// 컴파일 성공 : 런타임에 타입 변환에 실패하며 널을 리턴한다.
pDerived = dynamic_cast<Derived*>( pBase );
if ( pDerived == NULL )
cout << "Runtime Error" << endl;
// 컴파일 오류 : 타입 변환을 할 수 없다.
//pDerived = pDerived1;
// 컴파일 성공 : 런타임에 타입 변환에 성공하며 Derived 타입의 포인터를 리턴한다.
pDerived = dynamic_cast<Derived*>( pDerived1 );
if ( pDerived )
pDerived->Put();
// 컴파일 성공 : 이런 경우에는 캐스팅이 필요 없다.
pDerived = pDerived2;
}
[예제 1] 에서 중요한 내용은 'pDerived = dynamic_cast<Derived*>( pBase );' 에서 볼 수 있듯이 포인터가 실제로 가리키는 대상이 기본 클래스의 객체라면 변환은 실패한다는 것이다.
dynamic_cast 가 캐스팅해주는 것은 포인터나 참조자의 타입을 다운 캐스팅하는 것이지 객체의 타입을 캐스팅하지는 못한다.
dynamic_cast 는 캐스팅에 실패할 때 대상이 포인터라면 널을 리턴하고 참조자였다면 bad_cast 예외를 던진다.
이것이 위에서 언급한 '안전한 타입 캐스팅'의 의미다.
A에서 B로 포인터의 타입을 캐스팅하는 것이 문제없는지 런타임에 검사하여 처리할 수 있다.
다중 상속의 상황에서 기본 클래스 간의 타입 캐스팅을 보자.
[예제 2][예제 2] 는 아래 [그림 1] 처럼 다중 상속 관계의 클래스 구성에서 기본 클래스 간의 타입 캐스팅을 보여준다.
class BaseOne
{
public :
virtual void Put( void ) { cout << "BaseOne" << endl; }
};
class BaseTwo
{
public :
virtual void Put( void ) { cout << "BaseTwo" << endl; }
};
class Derived : public BaseOne, public BaseTwo
{
public :
void Put( void ) { cout << "Derived" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
BaseOne* pBaseOne = NULL;
BaseTwo* pBaseTwo = new Derived;
// 컴파일 오류 : 타입 변환을 할 수 없다.
//pBaseOne = pBaseTwo;
// 컴파일 성공 : 런타임에 타입 변환에 성공하며 BaseOne 타입의 포인터를 리턴한다.
pBaseOne = dynamic_cast<BaseOne*>( pBaseTwo );
if ( pBaseOne )
pBaseOne->Put();
return 0;
}
[예제 2] 와 같은 캐스팅의 한 사용 예로는 각 기본 클래스 포인터(또는 참조자) 타입의 컨테이너 혹은 배열을 운용하면서 서로 간의 요소를 교환할 때 사용할 수 있다.
[예제 1] 과 같은 캐스팅을 다운 캐스팅이라고 하며 [예제 2] 와 같은 캐스팅을 크로스 캐스팅이라고 한다.
별도로 적지는 않았지만 파생 클래스에서 기본 클래스로의 캐스팅을 업 캐스팅이라고 한다.
업 캐스팅은 캐스팅 연산자가 있으나 없으나 안전하게 캐스팅된다.
- 참고 사항
다중 상속이 발생한다면 설계를 다시 검토하라는 말이 있듯이(있나..-_-?) 다중 상속은 그리 권장하지 않는 방식이다.
반응형
'Dev' 카테고리의 다른 글
C++ 이야기 - [4] 캐스트 연산자 reinterpret_cast (0) | 2007.10.20 |
---|---|
C++ 이야기 - [3] 캐스트 연산자 static_cast (2) | 2007.10.14 |
C++ 이야기 - [1] 캐스트 연산자 const_cast (0) | 2007.10.04 |
추천 공개 소프트웨어 모음 (4) | 2007.09.25 |
멋진 소프트웨어 MaxiVista (0) | 2007.09.15 |