C++ 공부

[C++ Study] 객체지향 설계의 핵심: 관계 정의와 다형성 (Is-A, Has-A, Casting)

Client Side 2026. 4. 18. 23:14

1. 관계 정의의 종류: Is-A vs Has-A

설계 단계에서 가장 먼저 결정해야 할 것은 클래스 간의 관계입니다.

Is-A (상속 관계)

  • 정의: 한 클래스가 다른 클래스의 일종임을 나타냅니다. (A는 B이다)
  • 언리얼 구현: class AMyCharacter : public ACharacter
  • 용도: 부모 클래스의 기능을 확장하거나, 공통 인터페이스를 통해 여러 객체를 동일한 방식으로 다룰 때(다형성) 사용합니다.

Has-A (포함/소유 관계 - Composition)

  • 정의: 한 객체가 다른 객체를 구성 요소로 가지고 있음을 나타냅니다. (A는 B를 가지고 있다)
  • 언리얼 구현: UPROPERTY()로 선언된 컴포넌트 포인터나 멤버 변수.
  • 용도: 기능을 모듈화하고 객체 간의 결합도를 낮추는 데 유리합니다. 현대 프로그래밍에서는 "Inheritance보다 Composition을 우선하라"는 원칙이 권장됩니다.

2. 타입 체크와 클래스 비교: IsA() vs GetClass() == ...

런타임에 객체의 타입을 확인해야 할 때, 언리얼에서는 두 가지 방식을 주로 고민하게 됩니다.

구분 IsA() 함수 == 직접 비교 (GetClass())
특징 다형성 지원 (상속 관계 포함) 엄격한 타입 체크 (정확히 일치)
동작 해당 클래스나 하위 클래스면 true 클래스 정보가 정확히 일치해야 true
비용 계층 구조를 순회하므로 상대적 오버헤드 발생 포인터 주소 비교로 매우 빠름

[Engine Insight]

IsA()는 언리얼 리플렉션 시스템을 사용하여 계층 구조를 확인합니다. 일반적인 이벤트 로직에서는 문제가 없으나, 수천 개의 객체를 매 프레임 Tick에서 체크해야 한다면 Enum이나 Bit Flag를 통한 O(1) 비교가 더 효율적일 수 있습니다.


3. 다형성 (Polymorphism)

다형성이란 "하나의 인터페이스로 여러 가지 형태의 객체를 조작하는 능력"입니다.

  • 핵심 기제: virtual 키워드를 통한 가상 함수(Virtual Function)동적 바인딩(Dynamic Binding).
  • 동작 원리: 가상 함수가 포함된 클래스는 vtable(가상 함수 테이블)을 가지게 되며, 런타임에 실제 객체의 타입을 확인하여 적절한 함수를 호출합니다.
  • 장점: 새로운 자식 클래스가 추가되어도 부모 포인터를 사용하는 기존 코드를 수정할 필요가 없어 확장성이 극대화됩니다.

4. 업캐스팅(Upcasting) vs 다운캐스팅(Downcasting)

다형성을 구현하기 위해 객체의 타입을 변환하는 과정입니다.

① 업캐스팅 (Upcasting)

  • 정의: 자식 클래스 포인터를 부모 클래스 타입으로 변환.
  • 특징: 항상 안전하며 암시적(Implicit)으로 가능합니다.
  • 용도: 여러 종류의 자식 객체들을 하나의 배열(TArray<Parent*>)로 관리할 때 사용합니다.

② 다운캐스팅 (Downcasting)

  • 정의: 부모 클래스 포인터를 구체적인 자식 클래스 타입으로 변환.
  • 특징: 위험성 존재. 실제 객체가 해당 타입이 아닐 경우 문제가 발생합니다.
  • 언리얼 방식: Cast<T>()를 사용하며, 실패 시 nullptr을 반환합니다.
  • 최적화 팁: 모바일 환경(Android Vulkan 등)에서는 런타임 캐스팅 비용을 고려해야 합니다. 빈번한 캐스팅보다는 가상 함수 호출을 통한 해결이 권장됩니다.

5. 결론 및 요약

개념 목적 복잡도(Big-O)
Is-A 계층 구조 설계 및 다형성 활용 -
Has-A 기능 모듈화 및 결합도 감소 -
IsA() 상속 관계를 포함한 타입 확인 O(H) (H: 상속 깊이)
Casting 타입 변환을 통한 특수 기능 접근 O(1) (언리얼 Cast 기준)

게임을 설계할 때 상속(Is-A)은 공통된 인터페이스가 필요할 때만 엄격하게 사용하고, 기능의 확장은 컴포넌트(Has-A) 기반으로 구성하는 것이 현대적인 게임 엔진 활용의 정석입니다. 특히 모바일 환경에서는 런타임 타입 체크와 가상 함수 호출의 비용을 인지하고 적절한 캐싱 전략을 세우는 것이 중요합니다.