폴리모피즘을 적으며 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;
}
typeid()를 이용하면 이렇듯 실행 중에 클래스의 포인터나 참조가 가르키는 실제 타입이 무엇인지 알아낼수 있으며
리턴형은 typeinfo.h에 정의된 type_info 구조체이다.
주의할 것은 Base 클래스에 소멸자 포함하여 반드시 하나 이상 virtual 함수가 있어야 바인딩이 일어나 정상적으로 구현된다는 점이다(위 소스의 Base클래스에서 virtual을 지워보고 실행해보라.).
typeid()는 == 연산자를 지원하므로 객체가 개발자가 원하는 올바른 객체인지 판별할때도 유용하다.
if(typeif(*pAma) == typeid(CAmazon))
{
}
typeid() 설명에 절대 빠질수 없는 것이 static_cast와 dynamic_cast인데,
결론적으로 static_cast는 무조건 변환을 수행하므로 상당히 위험한 코드가 되며
무조건 dynamic_cast를 사용하는 것이 좋다. dynamic_cast는 실제 RTTI의 일부분이며
변환이 불가능하면 0을 리턴하므로 두 객체의 비교나 포인터를 사용할때는 항상 dynamic_cast를 사용하자.
물론 약간의 속도 저하는 있지만 그래도 이게 정답이다.
아래 소스에서 직접 캐스팅을 바꿔보며 결과를 살펴보자.
#include <conio.h>
#include <typeinfo>
using namespace std;
public:
virtual void print()const {cout << " A\n";}
};
public:
virtual void print()const {cout << " B\n";}
};
public:
void print()const {cout << " C\n";}
};
{
A* a = new A;
B* b = new B;
C* c = new C;
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에 대한 정보는 인터넷에 엄청 많고 위의 소스들보다 좋은 예제 역시 아주 많으니 이쯤에서 줄인다.
(티스토리 글상자 버그땜에 짜증나서 못 쓰겠다. -_-;; 소스 붙이기 실패!!)
