언리얼 엔진 5/공부

[언리얼 엔진 5] 헤더를 include할 때 주의할 점 (+ 포워드 선언)

ciel45 2023. 11. 27. 23:04

우선, #include "__.h"를 사용하는 것은 해당 헤더의 소스 코드 전체를 include문의 위치에 그대로 복사 & 붙여넣기하는 것과 같다.

컴파일 시에 소스 코드의 include문이 해당 헤더 파일 전체로 교체되는 것이다.

 

 

 

 

주의: 헤더에 헤더를 include하는 것은 가급적 피하는 것이 좋다.

 

 

  • 헤더 파일의 비대화
    • 헤더파일은 기본적으로 다른 여러 소스코드에서 include되어서 사용된다.
    • 만약 자기 자신이 아닌 다른 헤더를 include하는 헤더가 있다면, 그 헤더를 include하는 것은 그 헤더 뿐만이 아니라 그 헤더가 포함하고 있는 다른 헤더까지 include하는 것과 같다.
      • 예를 들어, Item.h에서 Character 타입 변수를 사용하기 위해 #include "Character.h"를 사용한다고 하자.
      • 그런데 Character.h가 캐릭터 기능에 필요한 다른 여러 헤더 파일 (Weapon.h, Inventory.h, ...) 등을 include하고 있다면,
      • Item.h에서 #include "Character.h"를 하는 것은 Weapon.h, Inventory.h, ...까지 모두 include하는 것이다.
    • 이는 헤더의 비대화로 이어지고, 컴파일 성능을 크게 악화시킨다.

 

 

 

 

 

 

 

  • 두 헤더 include의 무한루프
    • 두 헤더파일 HeaderA.h, HeaderB.h가 있다고 가정하자.
    • 그리고, 각각의 헤더는 #include <HeaderB.h>, #include <HeaderA.h>로 시작한다고 가정하자.
    • 이 상태로 컴파일을 한다면, 먼저 HeaderA에서 HeaderB를 include하므로 HeaderB를 그대로 #include <HeaderB.h> 문의 위치로 가져온다.
    • 가져온 HeaderB.h는 #include <HeaderA.h>로 시작하므로, 이번엔 그 위치에 HeaderA.h를 그대로 가져온다.
    • 가져온 HeaderA.h는 #include <HeaderB.h>로 시작하므로, 이번엔 그 위치에 HeaderB.h를 그대로 가져온다.
    • 상술한 과정이 무한히 반복되면서, 컴파일이 제대로 이루어질 수 없다. (컴파일 에러 발생)
    • 프로젝트의 규모가 커질수록, 이 같은 문제가 암시적으로 일어나기 쉽다.

 

 

 

 

 

 

 

 

따라서, 언리얼 엔진 프로젝트에서는 헤더를 include할 때 .h(헤더)이 아닌 .cpp(구현 코드)에서 하는 것이 바람직하다.

  • 다만, 부모 클래스의 헤더를 포함하는 것은 괜찮다. 슈퍼클래스의 함수를 override하는 등의 일을 하려면 불가피하며, 상술한 무한루프의 문제가 나타날 가능성이 없기 때문이다.
  • struct 헤더를 포함하는 것도 괜찮다. 일반적으로 구조체는 클래스에 비해 크기가 상대적으로 작아, 헤더 파일의 비대화가 잘 일어나지 않는다.

 

 

 

 

 

 

 

 

하지만, 헤더 파일에서 해당 클래스 타입의 변수를 써야할 때는? → 포워드 선언을 사용하도록 한다.

  • 포워드 선언에는 두 가지 방법이 있다.
    • 사용하고자 하는 외부 클래스 타입 변수를 선언할 때, 앞에 'class' 키워드 붙이기
    • 클래스 본문 위에 'class (외부 클래스 이름)' 작성
  • 포워드 선언은 실제로 클래스 전체를 include하는 것이 아닌, 그 타입의 이름을 임시로 사용하겠다는 의미이다.
  • 따라서 해당 클래스 타입을 자유롭게 사용하는 것은 불가능하지만, 해당 타입의 포인터를 선언하는 것이 가능하다.
  • 결과적으로 헤더 파일에서는 포워드 선언을 통해 포인터만 만들어두고, .cpp파일에서 해당 포인터에 값을 할당해서 사용할 수 있다.
  • 또한 .cpp파일에서는 헤더 파일의 include함으로써 해당 타입의 실제 변수를 생성하거나, 함수의 매개변수나 리턴 타입으로 설정하는 등 다양한 작업을 할 수 있다.

 

 

 

 

추가로, 꼭 헤더에서 include하고 싶은 외부 클래스의 어떤 부분이 있다면, 그것만 .h파일로 따로 분리해내어 해당 헤더를 include하는 것도 좋은 방법이다.