나만의 작은 도서관

[TIL][C++] 250805 MMO 서버 개발 73일차: override는 했지만 부모 클래스 함수의 내용을 쓰고 싶어!, UFUNCTION()의 지정자 정리(BlueprintCallable, BlueprintPure, BlueprintImplementableEvent) 본문

Today I Learn

[TIL][C++] 250805 MMO 서버 개발 73일차: override는 했지만 부모 클래스 함수의 내용을 쓰고 싶어!, UFUNCTION()의 지정자 정리(BlueprintCallable, BlueprintPure, BlueprintImplementableEvent)

pledge24 2025. 8. 6. 02:34
주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다. 

override는 했지만 부모 클래스 함수의 내용을 쓰고 싶어!

  • 상속 관계에 놓인 부모-자식 클래스가 있을 때 자식 클래스는 부모 클래스의 가상 함수(virtual 키워드가 붙은 함수)를 오버라이드할 수 있다. 오버라이드된 함수는 나중에 업캐스팅이 된 상태에서 부모의 함수를 호출해도 오버라이드한 내용이 호출되게 하는, 즉, “다형성”을 가지게 된다.
  • 그런데 개발을 하다 보면 부모 함수의 코드를 그대로 실행한 다음, 거기에 입맛에 맞는 코드를 추가시키고 싶을 때가 있다. 하지만, 오버라이드를 하게 되면 함수를 호출해도 부모 함수의 내용을 호출되지 않는다. 이 경우 어떻게 해야 할까?

 

 

그냥 오버라이드한 함수 첫 줄에 부모 함수를 호출하면 된다.

  • 그렇다. 그냥 부모 함수를 호출하면 된다. 부모 함수를 호출하는 방법은 “부모 클래스::함수 이름”과 같이 그냥 함수 앞에 부모 클래스 명을 적어 함수의 소속을 명시하면 된다.
class Base {
public:
    virtual void SomeFunction() {
        cout << "Base::SomeFunction()" << endl;
    }
};

class Derived : public Base {
public:
    virtual void SomeFunction() override {
        Base::SomeFunction();  // 부모 클래스 함수 직접 호출
        cout << "Derived::SomeFunction()" << endl;
    }
};
  • 위와 같이 적어주면 부모 클래스 함수가 먼저 호출된 다음, 자식 클래스 함수의 내용이 실행된다.

 

언리얼의 Super

  • 언리얼에서 사용하는 Super도 같은 맥락이다. 상속받은 부모 클래스의 이름을 찾지 않아도 사용할 수 있도록 “Super”라는 이름으로 통일시켰을 뿐이다. 단순히 언리얼에서 아래와 같은 매크로를 만들어 두었다고 생각해도 무방하다.
using Super = 부모_클래스_이름;
  • 이렇듯 Super는 코드를 작성하기 편리하게 해주는 문법인데, 이러한 것을 “syntactic sugar”라고 부른다.


UFUNCTION()의 지정자 정리

  • C++과 블루프린트를 혼합하여 로직을 짜는 경우, 서로 간의 통신이 중요하다. C++은 블루프린트의 모든 것을 알 수 있지만, 블루프린트는 C++ 이 등록해 준 내용만 접근할 수 있기 때문이다.
  • 함수 호출에 대한 정보를 누가 누구한테 전달하느냐에 따라 2가지로 구분된다. 블루프린트(이하 BP)가 네이티브(C++)로 함수호출에 대한 정보를 전달하는 지정자는 BlueprintCallable과 BlueprintPure, 네이티브가 블루프린트에게 함수 호출에 대한 정보를 전달하는 지정자는 BlueprintImplementableEvent와 BlueprintNativeEvent가 있다.

 

BP -> Native 함수 호출 정보 전달 지정자

 

BlueprintCallable 지정자 (파란색 노드)

  • 가장 자주 사용하는 지정자. C++ 함수가 BP에서 호출될 수 있도록 한다.
  • 해당 노드를 블루프린트에서 재정의 할 수 없다.
  • 이전 노드와 연결되어 있어야 하며, 이전 노드가 실행되어야만 해당 노드가 발동된다.

 

BlueprintPure 지정자 (초록색 노드)

  • BlueprintCallable과 동일하게 C++ 함수가 BP에서 호출될 수 있도록 한다. BlueprintCallable과 다른 점은 호출 중인 객체나 다른 글로벌한 상태를 바꾸지 않음을(즉, 쓰기 작업이 없는) 의도적으로 표현할 수 있다는 것이다. 이러한 BlueprintPure는 C++의 const 함수와 유사한 용도로 사용된다.
    • 주의할 점은 쓰기 작업이 있음에도 BlueprintPure 지정자를 사용하는 실수를 언리얼이 정정해주지는 않는다는 것이다. 따라서 쓰기 작업이 없다는 것을 보장하는 C++의 const 함수에다가 BlueprintPure를 붙이는 방식을 권장한다.
// 올바른 사용
UFUNCTION(BlueprintPure)
float ConstFunction() const;

// 잘못된 사용: 언리얼이 딱히 막지는 않음
UFUNCTION(BlueprintPure)
float NotConstFunction() { memberVar = 10; }

 

  • BlueprintCallable과 다르게 실행 핀이 없으며, 다른 노드에서 값이 필요할 때 자동으로 호출된다. 노드 흐름의 중간에 사용하는 것이 아닌, 독립적으로 발동시키고 싶은 기능이 있을 때 유용하다.(대부분 간단한 계산의 결괏값을 반환할 때 사용)
  • C++ const 함수를 BlueprintCallable로 지정했다면 언리얼은 이를 자동으로 BlueprintPure로 인식하여 실행 핀이 없는 초록색 노드로 표시된다. 대부분의 경우 이러한 자동 인식이 문제가 되지 않지만 때때로 실행 핀이 있는 파란색 노드가 필요할 때가 있다.(Ex. 연산 코스트가 매우 높은 함수라 여러 번 호출되는 것을 방지하기 위해 실행 핀 추가) 이럴 때에는 아래와 같이 명시적으로 BlueprintPure = false를 넣어주면 다시 파란색 노드로 나온다.
// 실행 핀이 없는 초록색 노드로 표시됨
UFUNCTION(BlueprintCallable)
void ConstFunction() const;

// 실행 핀이 있는 파란색 노드로 표시됨.
UFUNCTION(BlueprintCallable, BlueprintPure = false)
void ConstFunction() const;

 

 

Native  -> BP 함수 호출 정보 전달 지정자

 

BlueprintImplementableEvent 지정자(빨간색 노드)

  • C++에서 작성된 함수를 블루프린트의 이벤트로 취급하도록 하는 지정자. C++ 코드에서 함수를 호출하면 블루프린트의 이벤트 노드가 실행된다.
  • C++에서 함수 선언만 하고, 정의를 하지 않는다. 이벤트가 발동했을 때 후속 작업은 블루프린트에서 작성한다.
  • C++ 내부에서 블루프린트를 발동시키고 싶을 때 유용하다.

언리얼에서 레퍼런스 매개변수 사용하는 법 - UPARAM 매크로

 

레퍼런스 매개변수를 사용하면 핀 위치가 이상해진다?

  • C++ 버릇 그대로 매개변수를 레퍼런스 타입으로 가져온 다음, 이를 UFUNCTION으로 지정하면 이상하게도 블루프린트 노드에서 매개변수들이 입력 핀 위치가 아닌, 출력 핀 위치에 놓여 있는 것을 볼 수 있다.

 

해결법 1. const를 붙인다.

  • 이는 블루프린트 시스템이 레퍼런스를 바라보는 관점 때문인데, 블루프린트 시스템이 기본 레퍼런스(&)를 “함수가 실행된 후 값이 변경될 수 있는 변수”로 해석하는 경향이 있기 때문이다. 즉, const가 붙은 레퍼런스(상수 참조)와 const가 붙지 않은 레퍼런스(비상수 참조)를 구분하기 때문인 것이다.
    • 다른 말로, 언리얼이 비상수 참조를 OUT 변수로 본다고 할 수 있다.
  • 그래서 이러한 핀 위치 문제는 간단하게 const를 추가하는 것으로 해결된다.
void OnLoginClicked(const FString& Username, const FString& Password);

 

 

해결법 2. UPARAM 매크로를 사용한다.

  • 다른 해결법으로 UPARAM 매크로를 사용하는 방법도 있다. 사용법은 아래와 같이 UPARAM(ref)를 레퍼런스 변수 앞에 적어주는 것이다.
void OnLoginClicked(UPARAM(ref) FString& Username, UPARAM(ref) FString& Password);
  • 이 방법을 사용하면 좋은 점이 하나 추가되는데, 바로 핀에 표시되는 이름을 지정할 수 있다는 것이다.

 

 

출처: https://darkcatgame.tistory.com/64

 

UE4 C++와 블루프린트 연동 기본 -2. UFUNCTION()

UFUNCTION() 이전 UPROPERTY()는 C++의 변수를 블루프린트와 연동하는 내용이였으면 이번엔 함수에 대해 포스팅을 합니다. Category나 Meta키워드는 UPROPERTY와 중복되는 내용이니 이전 포스팅을 참고해 주

darkcatgame.tistory.com