TIL

[TIL] C++ 클래스 기초: 캡슐화와 객체 간 상호작용 (feat. 언리얼 엔진 대비)

think95592 2026. 4. 29. 21:06

오늘 C++의 핵심인 클래스(Class)를 공부하며, 단순한 문법을 넘어 객체지향 설계의 기초를 다졌습니다. 특히 실무(언리얼 엔진)에서 쓰이는 데미지 시스템 로직을 직접 구현해 본 과정이 인상적이었습니다.

1. 클래스의 핵심 개념

  • 캡슐화(Encapsulation): 데이터를 private 영역에 숨겨 외부의 직접적인 접근을 차단하고, 반드시 public 함수(Getter/Setter)를 통해서만 데이터를 조작하도록 설계했습니다. 이는 데이터의 오염을 막고 유지보수성을 높이는 핵심입니다.
  • 생성자와 초기화 리스트: 객체가 생성될 때 멤버 변수를 초기화하는 효율적인 방법을 익혔습니다. 특히 초기화 리스트는 대입 연산보다 성능 면에서 우수하며, 멤버 변수 간의 초기화 순서가 중요하다는 점을 배웠습니다.

2. 객체 간 상호작용 설계 (Attack & TakeDamage)

단순히 변수를 깎는 것이 아니라, 객체와 객체가 메시지를 주고받는 상호작용을 구현했습니다.

  • 레퍼런스(&) 전달: 객체를 함수로 넘길 때 복사본을 만들지 않고 원본을 직접 참조하여 성능을 최적화하고, 실제 원본의 상태(HP 등)를 변경할 수 있게 했습니다.
  • 상태 보고 체계: 공격자가 피격자의 TakeDamage를 호출하면, 피격자가 자신의 방어력(DEF)을 계산한 뒤 최종 입은 피해량을 return하여 공격자에게 알려주는 구조로 설계했습니다.

3. 트러블슈팅 (Troubleshooting)

오늘 겪은 가장 중요한 기술적 이슈 두 가지입니다.

① LNK2019: Unresolved External Symbol

  • 문제: 함수를 선언만 하고 구현(.cpp)을 연결하지 않았을 때 발생.
  • 해결: 클래스 함수 구현 시 클래스명::함수명 형식을 정확히 갖추고, 모든 구현부가 프로젝트 빌드에 포함되어 있는지 확인했습니다.

② 쓰레기 값(-858993460)과 초기화 순서

  • 문제: HP가 비정상적인 큰 음수로 출력됨.
  • 원인: C++ 멤버 변수는 클래스 선언부에 적힌 순서대로 초기화됩니다. HP(MaxHP)라고 썼을 때, MaxHP가 아직 초기화되기 전이라 쓰레기 값이 HP에 복사된 것이 원인이었습니다.
  • 해결: 다른 멤버 변수에 의존하지 않고, 생성자의 매개변수(maxhp)를 직접 사용하여 초기화하도록 수정했습니다.

4. 구현 코드 (GameCharacter 클래스)

C++
 
// 방어력 시스템이 적용된 데미지 처리 로직
int GameCharacter::TakeDamage(int amount) {
    int actualDamage = amount - DEF;
    if (actualDamage <= 0) actualDamage = 1; // 최소 데미지 보장
    
    HP -= actualDamage;
    if (HP <= 0) {
        HP = 0;
        std::cout << Name << "이(가) 쓰러졌습니다." << std::endl;
    }
    return actualDamage; // 실제 입은 피해를 반환
}

5. Unreal Engine 5.5.4 연결 고리

오늘 배운 C++ 기초는 언리얼 엔진의 핵심 시스템과 직결됩니다.

  • ACharacter: 엔진의 기본 캐릭터 클래스도 오늘 만든 GameCharacter처럼 TakeDamage 가상 함수를 통해 데미지를 처리합니다.
  • FMath::Clamp: HP의 범위를 제한할 때 엔진에서는 수동 조건문 대신 Clamp 함수를 사용하여 코드를 더 깔끔하게 관리합니다.

마무리하며 처음에는 파일 분리와 참조자 개념이 헷갈렸지만, 직접 코드를 짜며 발생하는 에러를 해결해 보니 객체지향의 흐름이 보이기 시작했습니다. 다음에는 이 클래스를 확장하는 상속 개념을 공부할 예정입니다.