본문 바로가기

프로그래밍

C++ 개발 생산성 극대화! 기본값을 지원하는 Getter/Setter 자동 생성 매크로 (수정 및 개선)

728x90
728x90

 

개발 효율을 높여줄 팁을 들고 왔습니다. 특히 C++ 개발, 그중에서도 언리얼 엔진(Unreal Engine)을 다루시는 분들이라면 주목해주세요! 반복적인 코딩 작업을 줄여주고 생산성을 확 끌어올려 줄 Getter/Setter 자동 생성 매크로에 대해 이야기해보려 합니다.

 

 

왜 이 매크로가 필요할까요?

C++로 개발하다 보면 멤버 변수를 선언하고, 그에 대한 Getter/Setter를 만드는 작업은 정말 흔하죠. 여기에 언리얼 엔진에서는 UPROPERTY 매크로를 이용해 변수 속성을 지정하고, 기본값까지 설정해야 합니다. 이 모든 과정을 매번 손으로 타이핑하는 건 시간 낭비이자 오타 발생의 주범이 될 수 있습니다.

오늘 소개해 드릴 매크로는 Getter/Setter 자동 생성을 중점적으로 다룹니다. 멤버 변수 선언과 기본값 설정, 그리고 UPROPERTY 선언은 매크로 밖에서 직접 작성해야 하지만, 반복적인 Getter/Setter 코딩은 이 매크로로 간편하게 해결할 수 있습니다. 이를 통해 개발 시간을 단축하고 코드 가독성까지 높일 수 있습니다.

 

 

PROPERTY_WITH_ACCESSORS 매크로 파헤치기

제가 사용하는 매크로는 다음과 같습니다. 언리얼 엔진 스타일에 맞춰 Getter/Setter를 한 번에 정의할 수 있도록 구성했습니다.

// Getter/Setter 자동 생성 매크로
#define PROPERTY_WITH_ACCESSORS(Type, VarName) \
public: \
    FORCEINLINE Type Get##VarName() const { return VarName; } \
    FORCEINLINE void Set##VarName(const Type& InValue) { VarName = InValue; }
 

이 매크로의 동작 원리는 간단합니다.

  • Type: 멤버 변수의 자료형을 지정합니다. (예: float, int32)
  • VarName: 멤버 변수의 이름을 지정합니다. (예: Health, Ammo)

매크로를 사용하면 public으로 해당 변수에 대한 Get 함수와 Set 함수를 FORCEINLINE으로 생성하여 인라인 최적화를 유도합니다.

 

 

실제 사용 예시 (개선된 구조)

UMyObject라는 클래스에서 이 매크로를 어떻게 활용하는지 보시죠. UPROPERTY 선언과 멤버 변수 선언 및 기본값 초기화는 protected 접근 지정자 내에 직접 작성해야 하며, UPROPERTY는 해당 변수 선언 바로 위에 위치해야 합니다.

class UMyObject : public UObject
{
    GENERATED_BODY()

protected: // UPROPERTY와 멤버 변수는 protected에 선언
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats")
    float Health = 100.0f;
    PROPERTY_WITH_ACCESSORS(float, Health) // Getter/Setter 매크로 호출

protected: // UPROPERTY와 멤버 변수는 protected에 선언
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats")
    int32 Ammo = 30;
    PROPERTY_WITH_ACCESSORS(int32, Ammo) // Getter/Setter 매크로 호출
};
 

위 코드를 컴파일하면 다음과 같은 코드가 자동으로 생성되는 효과를 얻습니다.

// 자동 생성될 코드 (실제 코드는 아니지만 이해를 돕기 위한 예시)
class UMyObject : public UObject
{
    GENERATED_BODY()

protected:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats")
    float Health = 100.0f;
public: // Getter/Setter는 public으로 생성됩니다.
    FORCEINLINE float GetHealth() const { return Health; }
    FORCEINLINE void SetHealth(const float& InValue) { Health = InValue; }

protected:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats")
    int32 Ammo = 30;
public: // Getter/Setter는 public으로 생성됩니다.
    FORCEINLINE int32 GetAmmo() const { return Ammo; }
    FORCEINLINE void SetAmmo(const int32& InValue) { Ammo = InValue; }
};
 

어떤가요? 일일이 타이핑해야 할 반복적인 Getter/Setter 코드를 매크로를 통해 깔끔하게 처리했습니다.

 

참고 사항

  • UPROPERTY Attribute: EditAnywhere, BlueprintReadWrite와 같이 UPROPERTY의 속성들은 쉼표(,)로 구분하여 나열합니다.
  • 변수 기본값 초기화: 언리얼 엔진에서는 생성자에서 멤버 변수를 명시적으로 초기화하는 것이 일반적인 패턴이지만, C++11 이상부터는 멤버 변수 선언부에서 기본값을 지정하는 것도 지원합니다. 이 매크로는 Getter/Setter 생성만을 담당하므로, 멤버 변수 선언과 기본값 지정은 직접 해주셔야 합니다.
  • 접근 지정자 및 UPROPERTY 위치: 언리얼 엔진의 관례상, UPROPERTY로 선언되는 멤버 변수는 protected 영역에 위치시키고, 그 변수 바로 위에 UPROPERTY를 선언하는 것이 일반적입니다. 이 매크로는 Getter/Setter를 public으로 생성하므로, 클래스 구조를 더욱 깔끔하게 유지할 수 있습니다.
  • Unreal Engine 리플렉션: 언리얼 엔진의 강력한 리플렉션 시스템과 블루프린트와의 연동을 위해서는 UPROPERTY 매크로가 필수적입니다. 이 매크로는 UPROPERTY를 포함하지 않으므로, 개발자가 명시적으로 UPROPERTY를 선언해야 합니다.

 

 

마치며

이 PROPERTY_WITH_ACCESSORS 매크로를 활용하면 반복적인 Getter/Setter 작성을 효율적으로 처리하여 개발 생산성을 크게 향상시킬 수 있습니다.

 


 

 
728x90
반응형