Interface
December 29, 2023About 1 min
Interface
下面是一个简单的接口示例:
#pragma once
#include "CoreMinimal.h"
#include "DoSomeThings.generated.h"
UINTERFACE(MinimalAPI)
class UDoSomeThings : public UInterface
{
GENERATED_BODY()
// This will always be empty!
};
class YOURPROJECT_API IDoSomeThings
{
GENERATED_BODY()
public:
// Get the number of things
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Things")
int GetNumberOfThings();
};
继承接口的类:
#pragma once
#include "CoreMinimal.h"
#include "DoSomeThings.h"
#include "SomeThingsActor.generated.h"
UCLASS(Blueprintable)
class YOURPROJECT_API ASomeThingsActor : public AActor, public IDoSomeThings
{
GENERATED_BODY()
public:
virtual int GetNumberOfThings_Implementation() override;
};
#include "SomeThingsActor.h"
int ASomeThingsActor::GetNumberOfThings_Implementation()
{
return 1;
}
UE中C++的接口有一些特别使用方法,下面记录一下:
BlueprintNativeEvent
在接口里使用BlueprintNativeEvent
来标记方法为虚方法,而不是直接使用virtual
。这样做的好处是可以在蓝图实现也可以在C++里使用,与此同时可以在C++中不实现该接口方法也是可以的。
最重要的是在调用接口方法时不需要手动强转一次,虚幻提供了专用的调用方式:
int Num = IDoSomeThings::Execute_GetNumberOfThings(SomethingInstance);
Implements
判断一个对象是否继承与一个接口,使用U开头的类来判读,而不是I开头的。
if (Actor && Actor->Implements<UDoSomeThings>())
{
// Use the interface
}
Storing Interfaces As Variables
把接口作为类的变量,官方提供了TScriptInterface<>
来存储,不过这种方式很容易出错,所以这里并不推荐。直接使用UObject
存储更加合适。
UPROPERTY(BlueprintReadWrite)
UObject* SomethingInstance;
在调用接口函数时也更加方便,因为Execute方法传入的时UObject:
// I'm assuming here that we checked the object supported the interface before saving
// it to the variable; if not we should check for that as well as nulls
if (SomethingInstance)
{
int Num = IDoSomeThings::Execute_GetNumberOfThings(SomethingInstance);
}