概述

  • 简单的说,接口提供一组公共的方法,不同的对象中继承这些方法后可以有不同的具体实现。
  • 任何使用接口的类都必须实现这些接口。
  • 实现解耦
  • 解决多继承的问题

蓝图使用

使用方法

三种调用方法的区别

调用流关卡蓝图的接口函数

C++ 使用接口

本例使用一个Box Trigger 出发overlap 调用 Drone实例的接口

添加接口类

定义接口

声明蓝图可调用接口函数

  • 用UFUNCTION 宏 BlueprintCallable 声明蓝图可调用,还必须使用 BlueprintImplementableEventBlueprintNativeEvent 说明,而且函数不能为虚函数

  • 如果不想蓝图重载,只是想使用 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);
    } }

测试结果

参考

【UE4 C++ 基础知识】<9> Interface 接口的更多相关文章

  1. 【UE4 C++ 基础知识】<11>资源的同步加载与异步加载

    同步加载 同步加载会造成进程阻塞. FObjectFinder / FClassFinder 在构造函数加载 ConstructorHelpers::FObjectFinder Constructor ...

  2. 【UE4 C++ 基础知识】<12> 多线程——FRunnable

    概述 UE4里,提供的多线程的方法: 继承 FRunnable 接口创建单个线程 创建 AsyncTask 调用线程池里面空闲的线程 通过 TaskGraph 系统来异步完成一些自定义任务 支持原生的 ...

  3. 【UE4 C++ 基础知识】<3> 基本数据类型、字符串处理及转换

    基本数据类型 TCHAR TCHAR就是UE4通过对char和wchar_t的封装 char ANSI编码 wchar_t 宽字符的Unicode编码 使用 TEXT() 宏包裹作为字面值 TCHAR ...

  4. Java基础知识:Collection接口

    *本文是最近学习到的知识的记录以及分享,算不上原创. *参考文献见文末. 这篇文章主要讲的是java的Collection接口派生的两个子接口List和Set. 目录 Collection框架 Lis ...

  5. 【UE4 C++ 基础知识】<8> Delegate 委托

    概念 定义 UE4中的delegate(委托)常用于解耦不同对象之间的关联:委托的触发者不与监听者有直接关联,两者通过委托对象间接地建立联系. 监听者通过将响应函数绑定到委托上,使得委托触发时立即收到 ...

  6. java基础知识回顾之接口

    /* abstract class AbsDemo { abstract void show1(); abstract void show2(); } 当一个抽象类中的方法都是抽象的时候,这时可以将该 ...

  7. 【UE4 C++ 基础知识】<14> 多线程——AsyncTask

    概念 AsyncTask AsyncTask 系统是一套基于线程池的异步任务处理系统.每创建一个AsyncTas,都会被加入到线程池中进行执行 AsyncTask 泛指 FAsyncTask 和 FA ...

  8. 《Java基础知识》Java接口和抽象类的区别

    抽象类 抽象类必须用 abstract 修饰,子类必须实现抽象类中的抽象方法,如果有未实现的,那么子类也必须用 abstract 修饰.抽象类默认的权限修饰符为 public,可以定义为 public ...

  9. JAVA基础知识|抽象类与接口类

    一.抽象类 抽象类:拥有抽象方法的类就是抽象类,抽象类要使用abstract声明 抽象方法:没有方法体的方法,必须要使用abstract修饰 为什么要使用抽象类,抽象方法? 举例来说,如果你定义了一个 ...

随机推荐

  1. SQLServer数据库之连接查询

    SQLServer数据库之连接查询 表的连接查询的几种方法介绍: inner join on内连接,left join on 左连接 , rigth join on 右连接, full join on ...

  2. Linux下Sed命令替换文件中的所有IP

    命令: sed -ri 's/([0-9]{1,3}\.){3}[0-9]{1,3}/localhost/g' es_create_index.sh 如图:

  3. NOIP模拟22「d·e·f」

    T1:d   枚举.   现在都不敢随便打枚举了.   实际上我们只关注最后留下的矩阵中最小的长与宽即可.   所以我们将所有矩阵按a的降序排列.   从第\(n-m\)个开始枚举.   因为你最多拿 ...

  4. Python中正则表达式简介

    目录 一.什么是正则表达式 二.正则表达式的基础知识 1. 原子 1)普通字符作为原子 2)非打印字符作为原子 3) 通用字符作为原子 4) 原子表 2. 元字符 1)任意匹配元字符 2)边界限制元字 ...

  5. 【HMS Core 6.0全球上线】Toolkit,您的智能辅助编程好帮手

    HMS Core 6.0已于7月15日全球上线.本次版本中,华为HMS Toolkit向广大开发者推出了智能辅助编程助手SmartCoder,帮助开发者轻松高效地集成HMS Core,开发新功能,创建 ...

  6. JS011. 身份证号码校验(仅34行)

    身份证格式 六位数字地址码 + 八位数字出生日期码 + 三位数字顺序码 + 一位数字校验码 checkIdCard.js checkIdCard: function (idCard){ //15位和1 ...

  7. 使用 mysql 的 Docker 镜像

    使用 mysql 的 Docker 镜像 前言 之前搞了很多都是手工在操作系统的镜像中安装使用 mysql,作为自己折腾也就算了,作为实际使用实为不妥:Docker最重要的特性就是可扩展性,把各种程序 ...

  8. Java大数操作

    Java的Math包中提供了两个类用于对大数进行操作: BigInteger类,用于大整数的操作 BigDecimal类,用于大的小数操作 BigInteger类 Java中的基本类型中,表示整数的有 ...

  9. math.h库详解

    sin(double) cos(double) tan(double) 分别返回正弦,余弦,正切 #include<iostream> #include<math.h> usi ...

  10. Jmeter系列(36)- Access Log Sampler

    简介 Access Log Sampler 是个非常有用的工具,可以收集和分析真实用户操作的数据,并可用于流量分析.常见的就是我们的nginx的access.log 日志 使用 access.log ...