'dynamic_cast'에 해당되는 글 1건

  1. 2009/06/08 [부록] 잉여들을 위한 클래스설계 이야기를 위한 RTTI (4)


폴리모피즘을 적으며 RTTI(Run-Time Type Identification)를 함께 적었어야 했지만
포스팅 길이로 인해 부록으로 적어둔다.

상속과 객체들의 참조들이 많아지면 객체들은 "난 누군가 또 여긴 어딘가"와 같은 상황이 자주 생기게 된다.
(안 그럴 것 같지? 한번 고생해보면 안다.)

...젤 오른쪽, 넌 누구냐?

...젤 오른쪽, 넌 누구냐?


그럴때 도움이 되는 것이 바로 런타입 타입 식별(RTTI, Run-Time Type Identification)이다.

가장 간단한 방법은 클래스마다 WhoAmI() 같은 함수를 만들어 리턴값을 받아오는 것이겠지만,
일일이 모든 클래스에 대해 이런 노가다를 한다는 것은 옮지 않다.

다행히 C++에서는 이를 위해 typeid 라는 유용한 연산자를 마련해주고 있다.
먼저 프로젝트에서 Enable Run-Time Type info가 Yes가 되어 있는지 확인하자.
사실 이게 디폴트다.

사실 이게 디폴트다.


백문이 불여일런(Run), 이제 MSDN에 나와있는 소스를 긁어보자.

#include "stdafx.h"
#include <iostream>
#include <typeinfo>    // <-- typeid() 를 위해 반드시 인클루드
using namespace std;

class Base
{
public:
 virtual void vvfunc() {}  // <-- 베이스 클래스는 하나 이상 virtual 선언이 되어야 한다.
};

class Derived : public Base {};

int main()
{
 Derived* pd = new Derived;
 Base* pb = pd;

 cout << typeid( pb ).name() << endl;   //prints "class Base *"
 cout << typeid( *pb ).name() << endl;   //prints "class Derived"
 cout << typeid( pd ).name() << endl;   //prints "class Derived *"
 cout << typeid( *pd ).name() << endl;   //prints "class Derived"
 delete pd;
}

(아 정말이지 티스토리 글상자 버그는 짜증나서 미치겠다!!! 차라리 ActiveX로 만들어달라!!!!!)

typeid()를 이용하면 이렇듯 실행 중에 클래스의 포인터나 참조가 가르키는 실제 타입이 무엇인지 알아낼수 있으며
리턴형은 typeinfo.h에 정의된 type_info 구조체이다.

주의할 것은 Base 클래스에 소멸자 포함하여 반드시 하나 이상 virtual 함수가 있어야 바인딩이 일어나 정상적으로 구현된다는 점이다(위 소스의 Base클래스에서 virtual을 지워보고 실행해보라.).

typeid()는 == 연산자를 지원하므로 객체가 개발자가 원하는 올바른 객체인지 판별할때도 유용하다.
CAmazon *pAma = &Ama;
if(typeif(*pAma) == typeid(CAmazon))
{
   pAma->Attack();
}


typeid() 설명에 절대 빠질수 없는 것이 static_castdynamic_cast인데,
결론적으로 static_cast는 무조건 변환을 수행하므로 상당히 위험한 코드가 되며
무조건 dynamic_cast를 사용하는 것이 좋다. dynamic_cast는 실제 RTTI의 일부분이며
변환이 불가능하면 0을 리턴하므로 두 객체의 비교나 포인터를 사용할때는 항상 dynamic_cast를 사용하자.
물론 약간의 속도 저하는 있지만 그래도 이게 정답이다.
아래 소스에서 직접 캐스팅을 바꿔보며 결과를 살펴보자.

#include <iostream>
#include <conio.h>
#include <typeinfo>
using namespace std;
class A {
public:
 virtual void print()const {cout << " A\n";}
};
class B {
public:
 virtual void print()const {cout << " B\n";}
};
class C: public A, public B {
public:
 void print()const {cout << " C\n";}
};
int main()
{
 A* a = new A;
 B* b = new B;
 C* c = new C;
 a -> print(); b -> print(); c -> print();
 b = dynamic_cast< B*>(a);  //fails
 if (b) 
  b -> print(); 
 else
  cout << "no B\n";
 a = c;
 a -> print(); //C prints
 b = dynamic_cast< B*>(a);  //succeeds
 if (b)
  b -> print(); 
 else
  cout << "no B\n";
 }

RTTI에 대한 정보는 인터넷에 엄청 많고 위의 소스들보다 좋은 예제 역시 아주 많으니 이쯤에서 줄인다.
(티스토리 글상자 버그땜에 짜증나서 못 쓰겠다. -_-;; 소스 붙이기 실패!!)

아무리 타입을 캐스팅해도 이 년의 정체는 바퀴. 더듬이가 증거다!

아무리 타입을 캐스팅해도 이 년의 정체는 바퀴. 더듬이가 증거다!




크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君