Interface在C++中的语法及使用

UE4官方
UE4-Declaring and using interfaces in C++
判断是否实现接口(参考):
若是C++里定义的接口,在蓝图里进行了实现,则在C++里通过该对象进行接口调用的方法如下:
 auto Owner = GetOwner<APawn>();
 if (Owner && Owner->GetClass()->ImplementsInterface(UAnjUpdatePoseInterface::StaticClass()))
 {
     IAnjUpdatePoseInterface::Execute_OnPoseUpdate(Owner, PoseData);
 }

UInterface and IInterface

///////// header file /////////
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "UObject/Interface.h"
#include "WhenCalled.generated.h"

class IWhenCalledInterface;
class UWhenCalledInterface;

UINTERFACE(BlueprintType, MinimalAPI)
class UWhenCalledManagerInterface: public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

class SURAXR_API IWhenCalledManagerInterface
{
	GENERATED_IINTERFACE_BODY()
public:
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="SURAXR")
	int AddHandler(const TScriptInterface<IWhenCalledInterface>& Handler);

	virtual void BindDelegates() = 0;
};

UINTERFACE(BlueprintType, MinimalAPI)
class UWhenCalledInterface: public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

class SURAXR_API IWhenCalledInterface
{
	GENERATED_IINTERFACE_BODY()
public:
	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
	int GetPriority() const;

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
	void DoAtBeginFrame();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
	void DoAtEndFrame();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
	void DoAtBeginFrameRT();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
	void DoAtEndFrameRT();
};

UCLASS(Blueprintable, BlueprintType)
class SURAXR_API AWhenCalled : public AActor, public IWhenCalledManagerInterface
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AWhenCalled();

	// Begin IWhenCalledManagerInterface
	// Return: 0 on success; -1 on null Handler; 1 on Handler exists; 2 on Priority conflicts.
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="SURAXR")
	int AddHandler(const TScriptInterface<IWhenCalledInterface>& Handler);
	virtual int AddHandler_Implementation(const TScriptInterface<IWhenCalledInterface>& Handler) override;
	virtual void BindDelegates() override;
	// End IWhenCalledManagerInterface

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

private:
	// Begin IWhenCalledManagerInterface
	UPROPERTY()
	TMap<int, TScriptInterface<IWhenCalledInterface>> Manager;
	// End IWhenCalledManagerInterface
};


//////// implementation file //////
// Fill out your copyright notice in the Description page of Project Settings.


#include "WhenCalled.h"

UWhenCalledInterface::UWhenCalledInterface(class FObjectInitializer const &ObjectInitializer)
	:Super(ObjectInitializer)
{}

UWhenCalledManagerInterface::UWhenCalledManagerInterface(class FObjectInitializer const &ObjectInitializer)
	:Super(ObjectInitializer)
{}

// Sets default values
AWhenCalled::AWhenCalled()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

int AWhenCalled::AddHandler_Implementation( const TScriptInterface<IWhenCalledInterface>& Handler )
{
	UObject* Object = Handler.GetObject();
	IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object);
	if (Object || IHandler)
	{
		if (Manager.FindKey(Handler) != nullptr)
		{
			return 1; // Handler exists
		}

		TArray<int> Keys;
		Manager.GetKeys(Keys);
		for (int k: Keys)
		{
			int Prior = IHandler == nullptr? IWhenCalledInterface::Execute_GetPriority(Object) : IHandler->GetPriority();
			if (k == Prior)
			{
				return 2; // Priority conflicts.
			}
		}

		int Prior = IHandler == nullptr ? IWhenCalledInterface::Execute_GetPriority(Object) : IHandler->GetPriority();
		Manager.Add(Prior, Handler);
		Manager.KeyStableSort([](int A, int B)
		{
			return A < B;
		});
		return 0;
	}
	return -1;
}

void AWhenCalled::BindDelegates( )
{
	FCoreDelegates::OnBeginFrame.AddWeakLambda(this, [this]()
	{
		for (auto& iter : Manager)
		{
			UObject* Object = iter.Value.GetObject();
			if (Object)
			{
				IWhenCalledInterface::Execute_DoAtBeginFrame(Object);
				continue;
			}

			IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object);
			if (IHandler)
			{
				IHandler->DoAtBeginFrame();
				continue;
			}
		}
	});
	FCoreDelegates::OnEndFrame.AddWeakLambda(this, [this]()
	{
		for (auto& iter : Manager)
		{
			UObject* Object = iter.Value.GetObject();
			if (Object)
			{
				IWhenCalledInterface::Execute_DoAtEndFrame(Object);
				continue;
			}

			IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object);
			if (IHandler)
			{
				IHandler->DoAtEndFrame();
				continue;
			}
		}
	});
	/*FCoreDelegates::OnBeginFrameRT.AddWeakLambda(this, [this]()
	{
		for (auto& iter : Manager)
		{
			IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(iter.Value);
			if (IHandler)
			{
				IHandler->DoAtBeginFrameRT();
			}
		}
	});
	FCoreDelegates::OnEndFrameRT.AddWeakLambda(this, [this]()
	{
		for (auto& iter : Manager)
		{
			IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(iter.Value);
			if (IHandler)
			{
				IHandler->DoAtEndFrameRT();
			}
		}
	});*/
}

// Called when the game starts or when spawned
void AWhenCalled::BeginPlay()
{
	Super::BeginPlay();
	
	BindDelegates();
}

void AWhenCalled::EndPlay( const EEndPlayReason::Type EndPlayReason )
{
	Super::EndPlay(EndPlayReason);
}

// Called every frame
void AWhenCalled::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}