글
나는 여태까지 C++ 은 정적 컴파일이다보니
동적으로 뭔가를 한다는 게 불가능할 줄 알았는데,
그냥 내가 무식했나보다...ㅎㅎㅎ..
C++ 에서 4 가지 캐스팅 연산자 (dynamic_cast, static_cast, const_cast, reinterpret_cast) 가운데
dynamic_cast 에 대해 알아보고자 한다.
dynamic_cast 는 상속 관계 안에서 포인터나 참조자의 타입을
기본 클래스 → 파생 클래스 로의 다운캐스팅과
다중 상속에서 기본 클래스 간의 안전한 타입 캐스팅에 사용된다.
(안전한 타입 캐스팅 : 런타임에 타입 검사를 하겠다는 의미)
const_cast 와 같이 용도가 명확하기 때문에 다른 용도로는 사용하지 못한다.
+추가로
객체가 위치한 메모리의 시작부분을 찾는 데도 사용된다고 한다.
아래와 같이 p 에 시작주소가 담겨진다.
void* p = dynamic_cast<void*> (ObjectPointer);
* dynamic_cast 의 제약사항
1) 상속 관계 안에서만 사용할 수 있다.
2) 하나 이상의 가상 함수를 가져야 한다.
3) 컴파일러의 RTTI (Runtime Type Information) 설정이 켜져있어야 한다.
[예제1]
class Base { public: virtual void print() { cout << "This is Base" << endl; } }; class Derived : public Base { public: void print() { cout << "This is Derived" << endl; } }; void main() { Base* pBase1 = new Base; Base* pDerived1 = new Derived; Derived* pDerived2 = new Derived; Derived* pDerived = nullptr; // 컴파일 실패 : 부모는 자식이 될 수 없음 pDerived = pBase; // 컴파일 성공 : but 부모는 자식이 될 수 없으므로 널 포인터를 리턴한다! pDerived = dynamic_cast<Derived*> (pBase); if ( pDerived == nullptr ) cout << "failed to casting pBase->pDerived" << endl; // 컴파일 실패 : pDerived1 의 타입이 Base* 이므로, 부모는 자식이 될 수 없음 pDerived = pDerived1 // 컴파일 성공 : 런타임에 타입 변환이 성공하여 Derived 타입의 포인터를 리턴한다! pDerived = dynamic_cast<Derived*> (pDerived1); if ( pDerived ) pDerived->print(); // 컴파일 성공 : 이런 경우에는 캐스팅이 필요없다. pDervied = pDerived2; }
위 예제에서의 키포인트는
'포인터가 실제로 가르키는 대상이 캐스팅이 될 수 있는 녀석인가' 이다.
dynamic_cast 는 캐스팅에 실패할 경우,
대상이 pointer 면 nullptr 를 반환하고
대상이 참조자이면 bad_cast 예외를 던진다.
이 점이 위에서 언급한 안전한 타입 캐스팅의 의미이다.
캐스팅의 가능 여부를 런타임에 검사하여 처리할 수있다.
다음은 다중 상속일 때, 기본 클래스 간의 타입 캐스팅(Cross-Casting)을 다룬다.
[예제2]
class BaseOne { public: virtual void print() { cout << "This is BaseOne" << endl; } }; class BaseTwo { public: virtual void print() { cout << "This is BaseTwo" << endl; } }; class Derived : public BaseOne, public BaseTwo { public: void print() { cout << "This is Derived" << endl; } }; void main() { BaseOne* pBaseOne = nullptr; BaseTwo* pBaseTwo = new Derived; // 컴파일 실패 : BaseOne 과 BaseTwo 타입은 호환 불가 pBaseOne = pBaseTwo; // 컴파일 성공 : 기본 클래스 간의 타입 캐스팅 가능 pBaseOne = dynamic_cast<BaseOne*> (pBaseTwo); if ( pBaseOne ) pBaseOne->print(); }
[예제2] 를 정리하자면 아래의 그림과 같다.
크로스 캐스팅의 한 사용 예로는
각 기본 클래스 포인터(or 참조자) 타입의 컨테이너 혹은 배열을 운용하면서
서로 간의 요소를 교환할 때 사용할 수 있다.
여기까지 dynamic_cast 의 용도를 알아보았다.
( [예제1] : 다운 캐스팅, [예제2] : 크로스 캐스팅 )
참고로 다중 상속은 권장하지 않는 분위기(?)라서 설계를 재검토 하도록 하자.
※ 포스팅 참고 자료:
http://msdn.microsoft.com/ko-kr/library/cby9kycs.aspx
포스팅의 엄청난 도움을 주신 (+게으른 저를 포스팅하게 만들어 주셨습니다)
http://prostars.net/55 님께 감사의 인사를 덧붙입니다. (__)
'Programming > C++' 카테고리의 다른 글
.h 컴파일 : #ifndef vs. #pragma once (0) | 2014.08.25 |
---|---|
정적 바인딩(Static binding) vs. 동적 바인딩(Dynamic binding) (0) | 2014.08.19 |
RECENT COMMENT