LoginSignup
8
9

More than 3 years have passed since last update.

Unreal Engine 4メモ:デリゲートをprivateで書く

Last updated at Posted at 2018-04-23

デリゲートはコールバックの登録にとても便利なフィーチャで簡単に処理のフックを作れます。UIで使用することが多いです。

なぜ非公開にするのか?

デリゲートを公開にしているクラスはUE4エンジン内にもありますが、これはマネしてはいけません。
なぜなら下記のとおりです。

BadSample.cpp
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FWindowDelegate);

UCLASS(Blueprintable)
class AT_API WindowClass : public UObject
{
    GENERATED_BODY()

public:
    FWindowDelegate OpenDelegate;
}
BadUseSample.cpp
WindowClass->OpenDelegate.AddDynamic(this, &UserClass::OnOpenWindow);
WindowClass->OpenDelegate.Broadcast(); // ???

外側からブロードキャストされるととんでもない結果になるのは目に見えています。

ダイナミックマルチキャストデリゲート

ダイナミックマルチキャストデリゲートをprivateにしたいと思ったときにちょっと悩んだのでメモしました。

最初は間違えて下記のような使う側が面倒なもの書いてしまいました・・・。

NotGoodSample.cpp
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FWindowDelegate);

UCLASS(Blueprintable)
class AT_API WindowClass : public UObject
{
    GENERATED_BODY()

private:
    FWindowDelegate OpenDelegate;

public:
    template< class UserClass >
    void SetOnOpenDelegate(UserClass* InUserObject, typename FUserClassDelegate::FDelegate::template TMethodPtrResolver< UserClass >::FMethodPtr InMethodPtr, FName InFunctionName)
    {
        OpenDelegate.__Internal_AddDynamic(InUserObject, InMethodPtr, InFunctionName);
    }
}
NotGoodUseSample.cpp
WindowClass->SetOnWindowOpenDelegate(this, &UserClass::Function, STATIC_FUNCTION_FNAME(TEXT("&UserClass::Function")));

AddDynamicマクロを使えない悲しみ・・・。


本来は下記のような感じですね。

Sample.cpp
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FWindowDelegate);

UCLASS(Blueprintable)
class AT_API WindowClass : public UObject
{
    GENERATED_BODY()

private:
    FWindowDelegate OpenDelegate;

public:
    void SetOnOpenWindowDelegate(FWindowDelegate::FDelegate& openDelegate)
    {
        OpenDelegate.Add(openDelegate);
    }
}
UseSample.cpp
FWindowDelegate::FDelegate windowDelegate;
windowDelegate.BindDynamic(this, &UserClass::OnOpenWindow);
WindowClass->SetOnGameWindowCloseDelegate(windowDelegate);

何?ラムダを使いたい?

それは下記のように書けます。

UseSample.cpp
FWindowDelegate::FDelegate windowDelegate;
windowDelegate= FWindowDelegate::FDelegate::CreateLambda([]() {
    // 処理
});
WindowClass->SetOnGameWindowCloseDelegate(windowDelegate);

各種使用するクラスでは非公開にしたい。でも!BPにはデリゲートを公開にしたい!

こちらは、「ダイナミックマルチキャストデリゲート」しかBPに公開できません。

コードは下記のような感じです。

Sample.cpp
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FWindowDelegate);
UCLASS(Blueprintable)
class AT_API WindowClass : public UObject
{
    GENERATED_BODY()
private:
    UPROPERTY(BlueprintAssignable, Category = "UI")
    FWindowDelegate OpenDelegate;
public:
    void SetOnOpenWindowDelegate(FWindowDelegate::FDelegate& openDelegate)
    {
        OpenDelegate.Add(openDelegate);
    }
}

その他

デリゲートに空関数を入れると最適化されて何も入っていない状態になる

empty_function_test.cpp
DECLARE_DELEGATE(FTestDelegate);

void test()
{
    FTestDelegate TestDelegate;
    TestDelegate = FTestDelegate::CreateLambda([this]() {
        // 空にした場合
    });

    if (TestDelegate.IsBound())
    {
        // ここには来ない
    }
    else
    {
        // ここに来てしまう
    }
}
8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9