【UE C++】インターフェースの使用方法
1.コンセプト
インターフェイス クラスは、共通の親クラスを持たないが同じ機能を必要とする (おそらく) 無関係なクラスのグループによって、一連の共通機能を確実に実装するのに役立ちます。この場合、インターフェイスをお勧めします。
ネイティブ C++ にはインターフェイスがないため、C++ 開発者はインターフェイスの代わりに純粋な抽象クラスを使用します。UE では、インターフェイスを管理用のリフレクション システムに含めることを可能にするために、UInterface が導入されています。UInterface は UObject を継承しますが、UE 開発者がインターフェイスを使用する必要がある場合、UInterface を直接継承するとダイヤモンド継承の問題が発生します。仮想継承で軽減できますが、安全ではありません。したがって、インターフェイスを作成すると、2 つのクラスが存在します。2 番目のクラスは、開発者がインターフェイス関数を定義する場所です。このクラスはどのクラスからも継承されず、ダイアモンド継承を回避します。最初のクラスは UInterface から継承し、主にインターフェイス クラスをUE リフレクション システムに含めることができるようにします。
2. インターフェースの作成
新しい C++ クラス 一番下までスクロールして [Unreal Interface] を選択します。[すべてのクラスを表示] をクリックして選択しないでください。検索できません。
3. インターフェース関数の宣言
3.1 C++ での定義
UFUNCTION()
virtual void UFUNCTIONTesFun(float value) {};//UFunction虚函数
virtual void VirtualTestFun(float value) {};//普通虚函数,须有定义
virtual void PureVirtualTestFun(float value) = 0;//纯虚函数
予防:
- インターフェイス関数を意味のあるものにするには、仮想関数として宣言する必要があります。virtual キーワードが追加されていない場合は、コンパイルが通らない可能性があります (UFUNCTION マークが付いています)。パスした場合は、関数のオーバーロードではなく、関数のオーバーライドになります。
- 純粋でない仮想宣言された関数には、インターフェイス内に対応する定義が必要です。上記の例の"{}"は、コンパイルが失敗するのを防ぐために空の定義を使用しています。
- Pure 仮想関数がインターフェイスに存在すると、C++ でこのインターフェイスを継承するクラスがその関数を実装する必要があります。実装しないとコンパイルが通過しません。このインターフェイスを実装するブループリント クラスは効果がありません
3.2 ブループリントで定義する
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
void BlueprintImpTestFun(float value);//不能有virtual
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void BlueprintNatTesFun(float value);//不能有virtual
virtual void BlueprintNatTesFun_Implementation(float value) {};//可以不在接口类中声明定义。只在实现自该接口的C++类中声明并定义
予防:
BlueprintCallable
ブループリント呼び出し可能としてマークされた関数も存在するBlueprintImplementableEvent
か、BlueprintNativeEvent
マークされている必要があります。同時に宣言された関数を仮想関数にすることはできません (ブループリントには仮想関数用の特別な処理メソッドがあります)- インターフェイス クラスを C++ でのみ実装したい場合、ブループリントではそれを実装できません。インターフェイス クラスは としてマークできます
UINTERFACE(meta = (CannotImplementInterfaceInBlueprint))
が、追加BlueprintImplementableEvent
またはBlueprintNativeEvent
マークすることはできません。そうしないとコンパイルが通過しません。現時点では単独で存在しておりBlueprintCallable
、この関数がブループリントから呼び出せることを示しています。
4. インターフェイス クラスを実装して使用する
これが私のインターフェースクラスです
UINTERFACE(MinimalAPI)
class UInterfaceTest : public UInterface
{
GENERATED_BODY()
};
class STUDY427TEST_API IInterfaceTest
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
void BlueprintImpTestFun(float value);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void BlueprintNatTesFun(float value);
virtual void BlueprintNatTesFun_Implementation(float value) {};
UFUNCTION()
virtual void UFUNCTIONTesFun(float value) {};
void NormalFun(float value);//此函数无作用,用于测试蓝图覆盖
virtual void VirtualTestFun(float value) {};
virtual void PureVirtualTestFun(float value) = 0;
};
4.1 インターフェースクラスの実装
上で述べたのは、IInterfaceTest
開発者がインターフェイス関数を宣言する場所であるため、それを継承する必要があるため、リフレクションに使用される補助クラスUInterfaceTest
です。
class STUDY427TEST_API AInterfaceTestActor : public AActor, public IInterfaceTest
4.2 インターフェイス クラスが実装されているかどうかを確認する
4.2.1 授業を通じて
ここで使用されているのは、UInterfaceTest
判断するために反射が使用されていることです。
bool bIsImplemented = false;
bIsImplemented = this->GetClass()->ImplementsInterface(UInterfaceTest::StaticClass());
bIsImplemented = this->Implements<UInterfaceTest>();
Implements<UInterfaceTest>()
実際に内部で呼び出されるGetClass()->ImplementsInterface(UInterfaceTest::StaticClass())
メソッド
4.2.2 スルーキャスト
使用されるのはIInterfaceTest
、C++ クラスがそれを継承するIInterfaceTest
ため、Cast オブジェクトがそれです。
IInterfaceTest* MyInterfaceTest = Cast<IInterfaceTest>(this);
if(MyInterfaceTest)
{
//内部逻辑
}
注:ブループリント クラスは継承を介さずにインターフェイスを使用するため、このメソッドはブループリント クラスがインターフェイスを実装しているかどうかを判断できません。そのため、 Cast は無効です。Classによる判定方法(4.2.1)
4.3 インターフェース関数の呼び出し
4.3.1 C++で定義された関数
通常の C++ 関数呼び出しメソッドを使用するだけです
IInterfaceTest* MyInterfaceTest = Cast<IInterfaceTest>(TestActor);
if (MyInterfaceTest)
{
MyInterfaceTest->UFUNCTIONTesFun(10.f);
MyInterfaceTest->PureVirtualTestFun(20.0f);
MyInterfaceTest->VirtualTestFun(30.0f);
}
4.3.2 ブループリントで定義された関数
それでも上記の方法を使用してIInterfaceTest::Execute_XXXXX(Actor, Parameter···)
呼び出しを強制すると、エディタがクラッシュする可能性があります。
//使用之前判断是否实现该接口更保险
IInterfaceTest::Execute_BlueprintImpTestFun(this,50.0f);
IInterfaceTest::Execute_BlueprintNatTesFun(this, 60.0f);