C++ RTTI 완벽 정리 (dynamic_cast, typeid 실전 활용까지)

C++ RTTI 개념과 dynamic_cast, typeid 사용법을 설명하는 런타임 타입 확인 구조 다이어그램

dynamic_cast를 왜 써야 하는지, RTTI 개념부터 typeid 활용까지 한 번에 정리했습니다.

👉 잘못된 캐스팅으로 인한 버그, RTTI로 안전하게 해결할 수 있습니다.

 

C++로 게임이나 엔진을 개발하다 보면 이런 문제를 만나게 됩니다.

“이 포인터가 실제로 어떤 타입인지 알고 싶다”

“상속 구조에서 안전하게 형변환을 하고 싶다”

“이 객체의 실제 타입을 런타임에서 확인할 수 없을까?”

“이 포인터를 dynamic_cast 해야 할까?”

“static_cast 쓰면 위험한가?”

이 문제를 해결하기 위한 기능이 바로 RTTI (Run-Time Type Information)입니다.

👉 RTTI는 실행 중에 객체의 실제 타입을 확인할 수 있게 해주는 기능입니다.

C++ RTTI를 활용하면 다형성 구조에서 객체의 실제 타입을 안전하게 확인할 수 있습니다.

특히 C++ RTTI는 dynamic_casttypeid를 통해 런타임 타입 정보를 제공하며, 잘못된 형변환을 방지하는 데 중요한 역할을 합니다.


//
//

RTTI란 무엇인가

RTTI의 전체 구조를 그림으로 보면 다음과 같습니다.

C++ RTTI 구조와 dynamic_cast, typeid를 통한 런타임 타입 확인 과정을 설명하는 다이어그램
RTTI는 vtable을 기반으로 객체의 실제 타입 정보를 확인하며 dynamic_cast와 typeid를 통해 안전한 형변환과 타입 비교를 수행합니다.

👉 RTTI는 vtable을 기반으로 객체의 실제 타입 정보를 추적합니다.

 

RTTI는 Run-Time Type Information의 약자입니다.

👉 RTTI는 “포인터가 가리키는 실제 객체 타입을 런타임에 확인하는 기능”입니다.

 

일반적으로 C++은 컴파일 타임에 타입이 결정됩니다.

그래서 대부분의 타입 정보는 컴파일 이후에는 필요하지 않습니다.

하지만 다형성을 사용하는 순간 상황이 달라집니다.

class GameActor
{
};

class GameCamera : public GameActor
{
};

GameActor* actor = new GameCamera();

이 코드에서 actor의 타입은 GameActor*입니다.

하지만 실제 객체는 GameCamera입니다.

👉 이 “실제 타입”을 확인하기 위해 RTTI가 필요합니다.


왜 RTTI가 필요한가 (실무 관점)

RTTI는 단순한 개념보다 “언제 쓰는가”가 더 중요합니다.

실무에서는 다음과 같은 상황에서 자주 사용됩니다.

  • 충돌 처리
  • 이벤트 시스템
  • 엔진 내부 타입 분기
  • 툴 및 디버깅

예를 들어 충돌 처리 코드:

void HandleCollision(GameActor* a, GameActor* b)
{
    if (auto player = dynamic_cast<Player*>(a))
    {
        // 플레이어 충돌 처리
    }
}

👉 실제 타입에 따라 다른 로직을 수행해야 할 때 RTTI가 필요합니다.


//

dynamic_cast (안전한 형변환)

RTTI의 가장 대표적인 기능입니다.

GameActor* actor = new GameCamera();

// 성공
GameCamera* camera = dynamic_cast<GameCamera*>(actor);

// 실패 → nullptr
GamePlayer* player = dynamic_cast<GamePlayer*>(actor);

특징은 다음과 같습니다.

  • 형변환이 가능하면 성공
  • 불가능하면 nullptr 반환

👉 런타임에서 안전성을 보장하는 형변환입니다.

👉 dynamic_cast는 안전하지만 내부적으로 RTTI를 사용하기 때문에 비용이 발생합니다.

따라서 성능이 중요한 구간에서는 남용하지 않는 것이 중요합니다.


static_cast와의 차이

많은 분들이 이렇게 생각합니다.

“static_cast로 하면 안 되나?”

가능은 합니다.

하지만 위험합니다.

GameCamera* camera = static_cast<GameCamera*>(actor);

이 코드는 컴파일은 되지만,
실제 타입이 다르면 런타임에서 문제가 발생할 수 있습니다.

👉 dynamic_cast는 안전, static_cast는 빠르지만 위험


typeid (타입 정보 확인)

typeid는 객체의 타입을 직접 확인할 때 사용합니다.

GameActor* actor = new GameCamera();

std::cout << typeid(*actor).name();

이 코드는 실제 객체의 타입을 출력합니다.

👉 “이 객체가 정확히 어떤 타입인가”를 확인할 때 사용합니다.

👉 주의: typeid(ptr)은 포인터 타입을 반환하고, typeid(*ptr)은 실제 객체 타입을 반환합니다.


typeid로 타입 비교하기

두 객체가 같은 타입인지 비교할 수도 있습니다.

if (typeid(*obj1) == typeid(*obj2))
{
    // 같은 타입
}

이 방식은 다음 상황에서 유용합니다.

  • 정확히 같은 타입인지 확인
  • 상속 관계가 아닌 “동일 타입” 비교

RTTI 사용 시 반드시 알아야 할 조건

이 부분이 가장 중요합니다.

👉 반드시 virtual 함수가 있어야 합니다

class GameActor
{
public:
    virtual ~GameActor()
    {
    }
};

이유는 간단합니다.

  • RTTI는 vtable 기반으로 동작
  • virtual이 없으면 dynamic_cast 실패

실무에서의 올바른 사용법

RTTI는 강력하지만 남용하면 안 됩니다.

기본 원칙은 다음과 같습니다.

  • 가능하면 virtual 함수로 해결
  • 정말 필요한 경우에만 dynamic_cast 사용

예:

class GameActor
{
public:
    virtual void Update() = 0;
};

👉 타입 분기보다 다형성이 우선입니다.


언제 RTTI를 써야 하는가

다음 상황에서는 RTTI 사용이 적절합니다.

  • 외부 시스템 연동
  • 디버깅
  • 툴 개발
  • 엔진 내부 처리

👉 “타입을 반드시 알아야 하는 경우”에만 사용하세요.


정리

  • RTTI는 런타임 타입 확인 기능
  • dynamic_cast는 안전한 형변환
  • typeid는 타입 정보 확인
  • virtual 함수는 필수

👉 RTTI는 다형성을 보완하는 도구로 사용하는 것이 핵심입니다.


마무리

RTTI를 제대로 이해하면 다음 단계로 넘어갈 수 있습니다.

👉 엔진 수준의 객체 시스템 설계

단순히 기능을 아는 것이 아니라,
왜 필요한지 이해하는 것이 더 중요합니다.

이번 글에서는 C++의 기본 RTTI 기능인 dynamic_cast와 typeid를 중심으로 정리했습니다.

하지만 실제 게임 엔진에서는 여기서 더 나아가,
RTTI를 직접 구현하거나 확장하는 구조까지 사용하게 됩니다.

이미 블로그에서 RTTI 기초부터 커스텀 RTTI 구현까지 시리즈로 정리해두었으니,
함께 보시면 전체 흐름을 이해하는 데 도움이 됩니다.

👉 RTTI 기초부터 커스텀 RTTI까지 시리즈 이어보기


한 단계 더 나아가려면

이러한 구조는 단순한 문법 수준이 아니라,
게임 엔진 내부에서 객체를 어떻게 다루는지와 깊이 연결됩니다.

👉 게임 엔진 구조를 더 깊이 이해하고 싶다면

아래 강의를 통해 직접 구현해보는 것을 추천드립니다.

C++로 만드는 게임 엔진 프레임워크 강의

👉 C++로 만드는 게임 엔진 프레임워크 강의 바로가기

단순히 사용하는 것을 넘어서,
엔진이 어떻게 동작하는지 이해하는 데 초점을 맞춘 내용입니다.

//
   

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Please turn AdBlock off

Notice for AdBlock users

Please turn AdBlock off