🚀 들어가며
이전 글에서는 TypeId 기반으로
👉 dynamic_cast 없이 타입을 비교하는 방법을 구현했습니다.
이 방식은 매우 빠르고 단순합니다.
하지만 실제로 사용하다 보면 한 가지 한계에 부딪힙니다.
❗ 타입에 대한 “정보”가 부족하다
🎯 이번 글의 목표
이번 글에서는 TypeId 기반 시스템을 확장하여
👉 엔진 수준의 RTTI 구조를 만들어봅니다.
구체적으로는:
- 타입 이름 저장
- 상속 구조 표현
- 부모 타입까지 포함한 타입 체크
⚠️ TypeId 방식의 한계
TypeId 방식은 다음과 같은 특징이 있습니다:
- ✔ 빠른 비교 (주소 기반)
- ✔ 상속 체크 가능 (재귀 호출)
하지만:
- ❌ 타입 이름 없음
- ❌ 디버깅 어려움
- ❌ 확장성 부족 (메타데이터 불가)
👉 즉:
“타입은 구분되지만, 설명할 수는 없다”
🧠 해결 아이디어
필요한 것은 단순한 ID가 아니라:
“타입을 설명할 수 있는 구조”
👉 이를 위해 다음 정보를 묶습니다:
- 타입 이름
- 부모 타입
- 타입 비교 기능
🧩 TypeInfo 클래스 설계
class TypeInfo
{
public:
TypeInfo(const char* name, const TypeInfo* parent)
: className(name), parentType(parent) {}
const char* GetName() const
{
return className;
}
bool IsChildOf(const TypeInfo* other) const
{
for (const TypeInfo* current = this; current; current = current->parentType)
{
if (current == other)
return true;
}
return false;
}
private:
const char* className;
const TypeInfo* parentType;
};
🔍 핵심 기능 설명
✔ className
const char* className;
✔ parentType
const TypeInfo* parentType;
✔ IsChildOf
current = current->parentType
🎯 베이스 클래스 수정
기존 TypeId 기반 구조를 확장합니다.
class CraftObject
{
public:
virtual ~CraftObject() = default;
static const TypeInfo* StaticClass()
{
static TypeInfo typeInfo("CraftObject", nullptr);
return &typeInfo;
}
virtual const TypeInfo* GetClass() const
{
return CraftObject::StaticClass();
}
bool Is(const TypeInfo* type) const
{
return GetClass()->IsChildOf(type);
}
template<typename T>
bool IsTypeOf() const
{
return Is(T::StaticClass());
}
};
⚙️ 매크로로 자동화
#define TYPE_DECLARATIONS(Type, ParentType) \
public: \
using super = ParentType; \
static const TypeInfo* StaticClass() \
{ \
static TypeInfo typeInfo(#Type, ParentType::StaticClass()); \
return &typeInfo; \
} \
\
virtual const TypeInfo* GetClass() const override \
{ \
return Type::StaticClass(); \
}
🧩 실제 클래스 적용
class Actor : public CraftObject
{
TYPE_DECLARATIONS(Actor, CraftObject)
};
class Player : public Actor
{
TYPE_DECLARATIONS(Player, Actor)
};
🎯 사용 예제
std::shared_ptr<CraftObject> obj = std::make_shared<Player>();
if (obj->Is(Player::StaticClass()))
{
// 정확히 Player
}
if (obj->Is(Actor::StaticClass()))
{
// Player는 Actor의 자식이므로 true
}
🔥 이 구조의 핵심 장점
1. 상속 구조 완벽 지원
👉 부모 체인 탐색
2. 타입 이름 제공
👉 디버깅 / 로그 가능
3. 확장성 확보
👉 메타데이터 / 리플렉션 확장 가능
🧠 Unreal Engine과의 연결
이 구조는 실제로 Unreal Engine의 다음 개념과 유사합니다:
👉 Unreal은 여기에:
- GC (Garbage Collection)
- 프로퍼티 시스템
- 에디터 연동
까지 확장합니다
⚠️ dynamic_cast vs 커스텀 RTTI
| 항목 | dynamic_cast | 커스텀 RTTI |
|---|---|---|
| 타입 검사 | 자동 | 직접 구현 |
| 성능 | 상대적으로 느림 | 빠름 |
| 확장성 | 제한적 | 매우 높음 |
| 제어 | 불가능 | 완전 제어 |
🎯 언제 사용하는가
이 구조는 다음과 같은 경우에 사용됩니다:
- 게임 엔진
- ECS 시스템
- 런타임 오브젝트 관리
- 플러그인 시스템
🔥 다음 단계
이제 RTTI는 단순한 “타입 체크”를 넘어
👉 “타입으로 객체를 생성하는 단계”
로 확장할 수 있습니다.
🎯 다음 글 예고
다음 글에서는:
👉 TSubclassOf 스타일 시스템 구현
- 타입을 변수로 저장
- 런타임 객체 생성
- 엔진에서의 활용 방식
💡 핵심 정리
- TypeId → TypeInfo로 확장
- 타입 정보를 구조로 관리
- 상속 체인을 기반으로 타입 체크
- 엔진 수준 RTTI 완성
🎮 마무리
이번 글에서는
👉 엔진 수준 RTTI 구조의 핵심 아이디어를 구현했습니다.
이 구조를 이해하면:
- Unreal Engine 내부 구조
- 커스텀 엔진 설계
- 런타임 시스템 설계
까지 자연스럽게 연결됩니다.
👉 다음 편에서 계속됩니다.