【问题标题】:Why am I having trouble with polymorphism and interfaces in Unreal Engine为什么我在虚幻引擎中遇到多态性和接口问题
【发布时间】:2026-01-20 15:45:01
【问题描述】:

我一直在尝试在我的游戏中进行互动,但我做错了,我不知道在哪里!我将在下面包含一堆代码并省略不相关的部分。

我在引擎中创建接口。生成的类称为IInteract。它只包含一个名为 void Interact(ACharacterBase* Caller) 的函数。 ACharacterBase 只是我项目的默认棋子。这是 IInteract 的头文件。

#pragma once

#include "STRGZR/Characters/CharacterBase.h"

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Interact.generated.h"

// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UInteract : public UInterface
{
    GENERATED_BODY()
};

/**
 * 
 */
class STRGZR_API IInteract
{
    GENERATED_BODY()

    // Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
    void Interact(ACharacterBase* Caller);
};

现在,我创建了另一个名为 AInteractable 的类,并在 AInteractable 中实现了 IInteract。然后我从界面声明了 Interact(ACharacterBase* Caller) 。这是 AInteractable 的代码。

#pragma once

#include "Interact.h"
#include "STRGZR/Characters/CharacterBase.h"

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Interactable.generated.h"

UCLASS()
class STRGZR_API AInteractable : public AActor, public IInteract
{
    GENERATED_BODY()

public: 
    // Sets default values for this actor's properties
    AInteractable();

protected:
    UFUNCTION(BlueprintCallable)
    void Interact(ACharacterBase* Caller);

public:
};

这是 void Interact(ACharacterBase* Caller) 的定义。

#include "Interactable.h"

// Sets default values
AInteractable::AInteractable()
{

}

void AInteractable::Interact(ACharacterBase* Caller)
{
    Destroy();
}

我想我的第一个问题是,我应该在 AInteractable 中的交互功能上在哪里使用 virtualoverride 关键字互动

现在,我设置键绑定,以便在按下交互键时调用 ACharacterBase 中的 OnInteract。这是 ACharacterBase 的代码文件。

#include "GameFramework/CharacterMovementComponent.h"
#include "STRGZR/Interactable/Interact.h"

#include "CharacterBase.h"

// Sets default values
ACharacterBase::ACharacterBase()
{   
    LineTraceLength = 2000.f;
}

// Called to bind functionality to input
void ACharacterBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // Set up gameplay key bindings
    check(PlayerInputComponent);

    // Bind Interact event
    PlayerInputComponent->BindAction("Interact", IE_Pressed, this, &ACharacterBase::OnInteract);
}

FHitResult ACharacterBase::LineTraceForward()
{
    FHitResult HitResult;
    FCollisionQueryParams CollisionQueryParams;
    FVector CharacterLocation;
    FRotator CharacterRotation;

    GetActorEyesViewPoint(CharacterLocation, CharacterRotation);

    FVector Start = CharacterLocation;
    FVector End = CharacterLocation + (CharacterRotation.Vector() * LineTraceLength);


    ActorLineTraceSingle(HitResult, Start, End, ECC_Visibility, CollisionQueryParams);

    return HitResult;
}

void ACharacterBase::OnInteract()
{
    AActor* InteractedActor = LineTraceForward().GetActor();

    IInteract* Interface = Cast<IInteract>(InteractedActor);

    if (Interface)
    {
        UE_LOG(LogTemp, Warning, TEXT("Cast successful"))
    }
}

这也是 ACharacterBase 的头文件。

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "CharacterBase.generated.h"

UCLASS()
class STRGZR_API ACharacterBase : public ACharacter
{
    GENERATED_BODY()

public:
    // Sets default values for this character's properties
    ACharacterBase();

protected:
    UFUNCTION(BlueprintCallable, Category = "Interaction")
    FHitResult LineTraceForward();

    UFUNCTION(BlueprintCallable, Category = "Input")
    void OnInteract();

public: 
    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};

我不知道为什么,但演员在这里失败了:

AActor* InteractedActor = LineTraceForward().GetActor();

    IInteract* Interface = Cast<IInteract>(InteractedActor);

    if (Interface)
    {
        UE_LOG(LogTemp, Warning, TEXT("Cast successful"))
    }

我的第二个问题是为什么这个演员不起作用,有没有更好的方法在 AInteractable 上调用 Interact(ACharacterBase* Caller)

感谢您的帮助!

【问题讨论】:

    标签: c++ unreal-engine4


    【解决方案1】:

    关于virtualoverride

    下面是动态多态的基本用法:

    class IInterface {
    public:
    virtual void method() = 0;
    };
    
    class CClass : public IInterface {
    public:
    void method() override { // do smth }
    };
    
    int main() { 
        IInterface* ptr = new CClass();
        ptr->method();
    }
    

    (不要忘记删除ptr或使用引用计数)

    您可以在此处阅读有关虚拟方法的信息:

    https://en.cppreference.com/w/cpp/language/virtual

    https://en.cppreference.com/w/cpp/language/override

    至于Cast&lt;T&gt; - 我不熟悉虚幻引擎,但是appears 是某种dynamic_cast&lt;T&gt;。如果没有内部具有虚拟表的类,则无法执行多态转换,这是由virtual 方法的定义提供的(https://en.cppreference.com/w/cpp/language/object#Polymorphic_objects https://en.cppreference.com/w/cpp/language/dynamic_cast)。

    【讨论】:

    • IInterfaces 不完全是接口,Cast 不完全是 dynamic_cast,Unreal 也不是完全 c++。
    【解决方案2】:
    • 您应该将UFUNCTION(BlueprintCallable) 说明符放在IInteract 内的函数声明上,而不是在实现actor 上。

    • 实施参与者应使用此声明覆盖:

      void Interact_Implementation(ACharacterBase* Caller) override;

    • 你不应该通过使用Cast来检查一个actor是否实现了一个接口,而是通过调用:

      actor-&gt;Implements&lt;UInteract&gt;()

    • 您应该使用以下方式调用接口方法:

      IInterface::Execute_Interact(someInteractable, caller)

    所以你永远不应该有理由强制转换为接口。

    另外,您还没有验证您的线路跟踪实际上是在击中AInteractable 演员。

    【讨论】:

    • 我做了你所说的一切,但是当我将override 添加到Interact_Implementation 时,我得到了一个member function declared with 'override' does not override a base class member。代码在没有override 关键字的情况下编译并运行良好。此外,我似乎无法使用 `IInterface::Execute_Interact(someInteractable, caller)' 在 Interactable 上调用 Interact。代码编译,但调用该行时没有任何反应。我想知道这两件事是否以某种方式联系在一起。谢谢!
    • 我重新检查了一下,我的语法是基于将接口中的方法设置为UFUNCTION(BlueprintNativeEvent)。我不确定BlueprintCallable 会是什么。我会尝试将基本方法标记为virtual,并在没有_Implementation 后缀的情况下覆盖它。