Language:
Page Info
Engine Version:

デリゲート

デリゲートは、汎用的でありながら型安全な方法で C++ オブジェクト上でメンバ関数の呼び出しを可能にします。デリゲートを使用すると、呼び出す側がオブジェクトの型を知らない場合でも、任意のオブジェクトのメンバ関数を動的に結合し、 オブジェクト上で関数を呼び出すことができます。

デリゲート オブジェクトは完全に安全にコピーできます。デリゲートは値渡しすることができますが、 ヒープ上にメモリを割り当てる必要があるので通常はお勧めしません。可能な限り、デリゲートは常に参照渡しが望ましいです。

安全にディスクにシリアライズできる動的デリゲートに加え、シングルキャスト デリゲートとマルチキャスト デリゲートにも対応しています。

デリゲートの宣言

提供された宣言用マクロの一つを使ってデリゲートを宣言します。デリゲートと結合する関数のシグネチャで使用するマクロが決定されます。これらの 汎用的な関数シグネチャの様々な組み合わせを事前に定義します。これを使って、必要な型がどれであっても、戻り値とパラメータに型名を入れて デリゲートの型を宣言することができます。現在、以下の組み合わせを使用しているデリゲートシグネチャに対応しています。

  • 値を返す関数

  • 4 つまでの "ペイロード" 変数

  • 8 つまでの関数パラメータ

  • const として宣言された関数

下表を使用してデリゲートの宣言に使う宣言用マクロを探してください。

関数シグネチャ

宣言用マクロ

void Function()

DECLARE_DELEGATE( DelegateName )

void Function( <Param1> )

DECLARE_DELEGATE_OneParam( DelegateName, Param1Type )

void Function( <Param1>, <Param2> )

DECLARE_DELEGATE_TwoParams( DelegateName, Param1Type, Param2Type )

void Function( <Param1>, <Param2>, ... )

DECLARE_DELEGATE_<Num>Params( DelegateName, Param1Type, Param2Type, ... )

<RetVal> Function()

DECLARE_DELEGATE_RetVal( RetValType, DelegateName )

<RetVal> Function( <Param1> )

DECLARE_DELEGATE_RetVal_OneParam( RetValType, DelegateName, Param1Type )

<RetVal> Function( <Param1>, <Param2> )

DECLARE_DELEGATE_RetVal_TwoParams( RetValType, DelegateName, Param1Type, Param2Type )

<RetVal> Function( <Param1>, <Param2>, ... )

DECLARE_DELEGATE_RetVal_<Num>Params( RetValType, DelegateName, Param1Type, Param2Type, ... )

マルチキャスト、動的、ラップされたデリゲート用に、上記のマクロのバリエーションも提供されます:

  • DECLARE_MULTICAST_DELEGATE...

  • DECLARE_DYNAMIC_DELEGATE...

  • DECLARE_DYNAMIC_MULTICAST_DELEGATE...

  • DECLARE_DYNAMIC_DELEGATE...

  • DECLARE_DYNAMIC_MULTICAST_DELEGATE...

名前空間やクラス宣言 (関数ボディではなくて) 内でも、デリゲート シグネチャ宣言はグローバルスコープで存在することが可能です。

これらの型のデリゲートの宣言についての詳細は 動的デリゲートマルチキャスト デリゲート
をご覧ください。

デリゲートの結合

デリゲートシステムはある一定のオブジェクト型を理解し、これらのオブジェクトを使用する場合に追加機能が有効になります。UObject のメンバあるいはシェアードポインタ クラスにデリゲートを結合させた場合、 デリゲート システムはそのオブジェクトへの弱い参照を保つことができるので、 オブジェクトがデリゲート側から破棄されても、IsBound() 関数または ExecuteIfBound() 関数を呼び出せば処理することができます。サポートされているオブジェクトの型別の特別な結合記法に注意してください。

関数

説明

Bind()

既存のデリゲート オブジェクトに結合します。

BindStatic()

生の C++ ポインタのグローバル関数デリゲートを結合します。

BindRaw()

生の C++ ポインタ デリゲートを結合します。生のポインタはいかなるタイプの参照も使用しないので、オブジェクトがデリゲート側から破棄された場合の呼び出しが安全ではない場合があります。Execute() の呼び出しには注意してください!

BindSP()

シェアードポインタ ベースのメンバ関数デリゲートを結合します。シェアードポインタのデリゲートはオブジェクトに対する弱い参照を保ちます。ExecuteIfBound() を使用して呼び出します。

BindUObject()

UObject ベースのメンバ関数デリゲートを結合します。UObject デリゲートはオブジェクトに対する弱い参照を保ちます。ExecuteIfBound() を使用して呼び出します。

UnBind()

このデリゲートの結合を解除します。

これらの関数のバリエーション、引数、実装については、DelegateSignatureImpl.inl (located in ..\UE4\Engine\Source\Runtime\Core\Public\Templates\) をご覧ください。

ペイロード データ

デリゲートに結合する時、ペイロード データも一緒に渡すことができます。呼び出されると結合した関数に直接渡される任意の変数です。これは、 結合時にデリゲートそのものにパラメータを格納することができるので、非常に便利です。全てのデリゲート型 (動的な型を除く) は、ペイロード変数に自動的に対応しています。
このサンプルでは、 bool と int32 という 2 つのカスタム変数をデリゲートに渡します。デリゲートが呼び出されると、これらのパラメータが結合関数に渡されます。これらの 追加の変数による引数は、必ず、デリゲート型に必要な引数の後に置く必要があります。

MyDelegate.BindRaw( &MyFunction, true, 20 );

デリゲートの実行

デリゲートと結合している関数は、デリゲートの Execute() 関数を呼ぶと実行されます。デリゲートが結合しているかどうかを実行前に確認する必要があります。デリゲートに戻り値があり、初期化されておらず、後でアクセスされる出力パラメータを持つ場合があるため、 コードをより安全にする目的で行うものでです。結合していないデリゲートを実行すると、 場合によってはメモリ上に実際に書き込まれることがあります。デリゲートの実行が安全かどうかは IsBound() を呼び出して確認できます。デリゲートに戻り値がない場合も ExecuteIfBound() を呼び出せますが、 初期化されていない可能性のある出力パラメータに注意してください。

実行関数

説明

Execute()

ExecuteIfBound()

IsBound()

マルチキャスト デリゲートの実行に関する詳細は マルチキャスト デリゲート をご覧ください。

使用例

どこからでも呼び出せるメソッドでクラスを持つとします。

class FLogWriter
{
    void WriteToLog( FString );
};

WriteToLog 関数を呼び出すには、その関数のシグネチャに対してデリゲート型を作成する必要があります。そのためには、まず以下のマクロの 1 つを使ってデリゲートを 宣言します。例えば、以下は簡単なデリゲート型です。

DECLARE_DELEGATE_OneParam( FStringDelegate, FString );

これで FString という型の単一パラメータを受け取る FStringDelegate と呼ばれるデリゲート型が作成されます。

以下はクラスで FStringDelegate を使用する例です。

class FMyClass
{
    FStringDelegate WriteToLogDelegate;
};

これにより、任意のクラスのメソッドに対してクラスはポインターを保持できるようになります。クラスは、このデリゲートが関数シグネチャであるということしか分かっていません。

デリゲートを割り当てるには、デリゲート クラスのインスタンスを作成し、テンプレートパラメータとしてそのメソッドを所有しているクラスと共に渡します。オブジェクトのインスタンスと メソッドの実際の関数アドレスも渡します。FLogWriter クラスのインスタンスを作成し、 そのオブジェクトのインスタンスの WriteToLog メソッドに対してデリゲートを作成します。

FSharedRef< FLogWriter > LogWriter( new FLogWriter() );

WriteToLogDelegate.BindSP( LogWriter, &FLogWriter::WriteToLog );

これで、クラスのメソッドにデリゲートを動的に結合しました。とてもシンプルですよね?

シェアードポインタが所有するオブジェクトへ結合したので、BindSP の SP の部分は「シェアードポインタ」を表していることにご注意ください。BindRaw() や BindUObject() など オブジェクト型には異なるバージョンがあります。

WriteToLog メソッドは、 FLogWriter クラスについて何も知らなくても FMyClass で呼び出すことができます。デリゲートの呼び出しには、以下のように Execute() メソッドを使うだけです。

WriteToLogDelegate.Execute( TEXT( "Delegates are spiffy!" ) );

関数をデリゲートに結合する前に Execute() を呼び出すと、アサーションがトリガーされます。以下を使いたくなる場合が多いでしょう。

WriteToLogDelegate.ExecuteIfBound( TEXT( "Only executes if a function was bound!" ) );