【UE4 C++ 基础知识】<9> Interface 接口
概述
- 简单的说,接口提供一组公共的方法,不同的对象中继承这些方法后可以有不同的具体实现。
- 任何使用接口的类都必须实现这些接口。
- 实现解耦
- 解决多继承的问题
蓝图使用
使用方法
三种调用方法的区别
调用流关卡蓝图的接口函数
C++ 使用接口
本例使用一个Box Trigger 出发overlap 调用 Drone实例的接口
添加接口类
定义接口
声明蓝图可调用接口函数
-
用UFUNCTION 宏
BlueprintCallable
声明蓝图可调用,还必须使用BlueprintImplementableEvent
或BlueprintNativeEvent
说明,而且函数不能为虚函数 -
如果不想蓝图重载,只是想使用
BlueprintCallable
以支持蓝图起到单纯的调用作用,可以通过将接口标记为UINTERFACE(meta = (CannotImplementInterfaceInBlueprint))
来解决 -
通过声明 virtual 虚函数,使得派生类可重载
代码
-
ReactToTriggerInterface.h
#pragma once #include "CoreMinimal.h" #include "UObject/Interface.h" #include "ReactToTriggerInterface.generated.h" // 无需更改 // UINTERFACE类不是实际的接口;它是一个空白类,它的存在只是为了向虚幻引擎反射系统确保可见性。 UINTERFACE(MinimalAPI) class UReactToTriggerInterface : public UInterface { GENERATED_BODY() }; //开头字母"U"必须改为"I"。 class TIPS_API IReactToTriggerInterface { GENERATED_BODY() public: // 纯虚函数,实现类必须实现接口 virtual void ReactToTrigger_PureVirtual() = 0; // 虚函数,在接口本身的 .h 或 .cpp 文件中提供默认实现.实现类可覆盖 virtual void ReactToTrigger_Virtual(); //实现类可以在蓝图和C++中实现接口 UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Trigger Reaction") void ReactToTrigger_NativeEvent1(int32 number); //实现类可以在蓝图和C++中实现接口 UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Trigger Reaction") bool ReactToTrigger_NativeEvent2(int32 number); //实现类在蓝图中实现接口 UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Trigger Reaction") void ReactToTrigger_ImplementableEvent(); };
-
ReactToTriggerInterface.cpp
#include "ReactToTriggerInterface.h" void IReactToTriggerInterface::ReactToTrigger_Virtual() { // unimplemented(); //该宏将在执行代码行时发出调试语句, 中断 UE_LOG(LogTemp, Warning, TEXT("ReactToTrigger_Virtual 被调用, From 接口本身")); }
实现接口
-
MyDrone.h 此类继承自Pawn类,无关本文主题
#include "ReactToTriggerInterface.h" #include "MyDrone.generated.h" UCLASS() class TIPS_API AMyDrone : public ADrone, public IReactToTriggerInterface { GENERATED_BODY() public: virtual void ReactToTrigger_PureVirtual() override; //可蓝图调用,貌似通用写法 UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Trigger Reaction") void ReactToTrigger_NativeEvent1(int32 number); virtual void ReactToTrigger_NativeEvent1_Implementation(int32 number) override; //蓝图可调用,,貌似和上面没区别 virtual bool ReactToTrigger_NativeEvent2_Implementation(int32 number) override; //void ReactToTrigger_ImplementableEvent();需要在蓝图实现 };
-
MyDrone.cpp
#include "MyDrone.h" void AMyDrone::ReactToTrigger_PureVirtual() { UE_LOG(LogTemp, Warning, TEXT("ReactToTrigger_PureVirtual 被调用, From MyDrone")); } void AMyDrone::ReactToTrigger_NativeEvent1_Implementation(int32 number) { UE_LOG(LogTemp, Warning, TEXT("ReactToTrigger_NativeEvent1 被调用, From MyDrone")); } bool AMyDrone::ReactToTrigger_NativeEvent2_Implementation(int32 number) { UE_LOG(LogTemp, Warning, TEXT("ReactToTrigger_NativeEvent2 被调用, From MyDrone")); return true; }
-
也可以蓝图重载
调用接口的类
-
c++ 调用接口可以先判断该类是否有实现接口
// 如果OriginalObject实现了UReactToTriggerInterface,则bisimplemated将为true。 bool bIsImplemented = OriginalObject->GetClass()->ImplementsInterface(UReactToTriggerInterface::StaticClass()); // 如果OriginalObject实现了UReactToTrigger,bIsImplemented将为true。 bIsImplemented = OriginalObject->Implements<UReactToTriggerInterface>(); // 如果OriginalObject实现了UReactToTriggerInterface,则ReactingObject将为非空。 IReactToTriggerInterface* ReactingObject = Cast<IReactToTriggerInterface>(OriginalObject);
-
原生 虚函数调用按照原生C++调用即可
-
UFUCNTION()修饰的接口函数则以
I接口名::Execute_函数名( 接口实例, 函数参数)
调用
代码
-
MyTriggerBox.h
#pragma once #include "CoreMinimal.h" #include "Engine/TriggerBox.h" #include "MyTriggerBox.generated.h" UCLASS() class TIPS_API AMyTriggerBox : public ATriggerBox { GENERATED_BODY() public: virtual void BeginPlay() override; UFUNCTION() void HandleOverlap(AActor* OverlappedActor, AActor* OtherActor ); };
-
MyTriggerBox.cpp
#include "MyTriggerBox.h" #include "Components/BoxComponent.h" #include "ReactToTriggerInterface.h" void AMyTriggerBox::BeginPlay() { //放在构造函数好像不起作用 OnActorBeginOverlap.AddDynamic(this, &AMyTriggerBox::HandleOverlap); } void AMyTriggerBox::HandleOverlap(AActor* OverlappedActor, AActor* OtherActor ) { UClass* ActorClass = OtherActor->GetClass(); if (ActorClass->ImplementsInterface(UReactToTriggerInterface::StaticClass())) { UE_LOG(LogTemp, Warning, TEXT("是否实现接口判断方法一")); IReactToTriggerInterface* ReactToTriggerInterface1 = CastChecked<IReactToTriggerInterface>(OtherActor); ReactToTriggerInterface1->ReactToTrigger_PureVirtual(); ReactToTriggerInterface1->ReactToTrigger_Virtual(); IReactToTriggerInterface::Execute_ReactToTrigger_NativeEvent1(OtherActor, 16); IReactToTriggerInterface::Execute_ReactToTrigger_NativeEvent2(OtherActor, 32); IReactToTriggerInterface::Execute_ReactToTrigger_ImplementableEvent(OtherActor); } if (OtherActor->Implements<UReactToTriggerInterface>()) { UE_LOG(LogTemp, Warning, TEXT("是否实现接口判断方法二")); IReactToTriggerInterface::Execute_ReactToTrigger_NativeEvent1(OtherActor, 16); IReactToTriggerInterface::Execute_ReactToTrigger_NativeEvent2(OtherActor, 32); } IReactToTriggerInterface* ReactToTriggerInterface2 = Cast<IReactToTriggerInterface>(OtherActor); if (ReactToTriggerInterface2) { UE_LOG(LogTemp, Warning, TEXT("是否实现接口判断方法三")); IReactToTriggerInterface::Execute_ReactToTrigger_ImplementableEvent(OtherActor); } }
测试结果
参考
作者:砥才人
出处:https://www.cnblogs.com/shiroe
本系列文章为笔者整理原创,只发表在博客园上,欢迎分享本文链接,如需转载,请注明出处!