Skip to content

Defining a C++ Interface

You can register a C++ interface with the engine by using the UINTERFACE macro. A registered interface is recognized by the editor and can be used to enforce structure to common functionality even through Blueprint classes.

You can create a new interface through the editor by selecting Tools > New C++ Class... from the main menu and then picking Unreal Interface. You could also manually create a new header file in either the Public or Private directory of your module and define the interface there.

Add New Unreal Interface

Example

The following is an example of how to define a simple interface in C++ for interactable objects in the game world. The declaration looks slightly different depending on whether you want to expose the interface to Blueprint classes or not.

Interactable.h
#pragma once

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

UINTERFACE(MinimalAPI/* (1)! */)
class UInteractable/* (2)! */ : public UInterface {
    GENERATED_BODY()
};

class MODULENAME_API IInteractable/* (3)! */ {
    GENERATED_BODY()

public:
    virtual void Interact(); // Could also have gone with pure virtual.
};
  1. The class only needs to exist so that the editor can recognize the interface. There is no point in exposing it to other modules. See external linkage for more info.
  2. This class purely exists so that the editor can recognize the interface. It does not need to have any members or methods.
  3. The actual interface is defined here. Per naming convention, the interface class should be prefixed with an I.
Interactable.h
#pragma once

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

UINTERFACE(MinimalAPI/* (1)! */, Blueprintable)
class UInteractable/* (2)! */ : public UInterface {
    GENERATED_BODY()
};

class MODULENAME_API IInteractable/* (3)! */ {
    GENERATED_BODY()

public:
    UFUNCTION(BlueprintNativeEvent/* (4)! */, BlueprintCallable/* (5)! */)
      void Interact();
};
  1. The class only needs to exist so that the editor can recognize the interface. There is no point in exposing it to other modules. See external linkage for more info.
  2. This class purely exists so that the editor can recognize the interface. It does not need to have any members or methods.
  3. The actual interface is defined here. Per naming convention, the interface class should be prefixed with an I.
  4. Allows us to override the method in both C++ and Blueprints. See BlueprintNativeEvent for more info.
  5. Makes little sense to expose the interface to Blueprint classes if the method is not BlueprintCallable.
Interactable.h
#pragma once

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

UINTERFACE(MinimalAPI/* (1)! */, Blueprintable)
class UInteractable/* (2)! */ : public UInterface {
    GENERATED_BODY()
};

class MODULENAME_API IInteractable/* (3)! */ {
    GENERATED_BODY()

public:
    UFUNCTION(BlueprintImplementableEvent/* (4)! */, BlueprintCallable/* (5)! */)
      void Interact();
};
  1. The class only needs to exist so that the editor can recognize the interface. There is no point in exposing it to other modules. See external linkage for more info.
  2. This class purely exists so that the editor can recognize the interface. It does not need to have any members or methods.
  3. The actual interface is defined here. Per naming convention, the interface class should be prefixed with an I.
  4. The method can only be implemented in Blueprints. See BlueprintImplementableEvent for more info.
  5. Makes little sense to expose the interface to Blueprint classes if the method is not BlueprintCallable.

Now, we can have any class implement the interface. For example, a Door class could implement the Interactable interface.

Door.h
UCLASS()
class MODULENAME_API ADoor : public AActor, public IInteractable/* (1)! */ {
    GENERATED_BODY()

public:
    ADoor();

    virtual void Interact() override;
};
  1. Note that you must inherit from IInteractable, not UInteractable.
Door.h
UCLASS()
class MODULENAME_API ADoor : public AActor, public IInteractable/* (1)! */ {
    GENERATED_BODY()

public:
    ADoor();

    virtual void Interact_Implementation/* (2)! */() override;
};
  1. Note that you must inherit from IInteractable, not UInteractable.
  2. The _Implementation suffix is added due to the use of BlueprintNativeEvent specifier.

Interact in Blueprints

Finally, other actors (e.g., a pawn) can check if an object is interactable and call the Interact method if it is.

MyPawn.cpp
void AMyPawnActor::MaybeInteract(AActor* OtherActor) {
    if (auto Interface = Cast<IInteractable>(OtherActor)) {
        Interface->Interact();
    }
}
MyPawn.cpp
void AMyPawnActor::MaybeInteract(AActor* OtherActor) {
    if (OtherActor->Implements/* (1)! */<UInteractable>()) {
        IInteractable::Execute_Interact(OtherActor);
    }
}
  1. Courtesy of the UObject base class, the method returns true if the object implements the specified interface.
MyPawn.cpp
void AMyPawnActor::MaybeInteract(AActor* OtherActor) {
    if (OtherActor->Implements/* (1)! */<UInteractable>()) {
        IInteractable::Execute_Interact(OtherActor);
    }
}
  1. Courtesy of the UObject base class, the method returns true if the object implements the specified interface.

UNITERFACE

Specifiers

UINTERFACE(Blueprintable)

Exposes the interface so that it can be implemented by a Blueprint class.

Blueprintable Interface

UINTERFACE(BlueprintType)

Exposes this class as a type that can be used for variables in Blueprints.

UINTERFACE(Category="Some Category")

Associates a category to the interface.

Categories can be nested by separating them with a pipe (|) without spaces, e.g., Main Category|Subcategory.

UINTERFACE(MinimalAPI)

Indicates that only the class's type information to be exported. See External Linkage for more info.

Meta Specifiers

UINTERFACE(meta=(DisplayName="Some Name"))

Specifies an alternate name for the interface to be displayed in the editor. UE will use the interface's name otherwise.

UINTERFACE(meta=(CannotImplementInterfaceInBlueprint))

Prevents Blueprint classes from implementing the interface. The interface would still be visible in the editor, and Blueprint classes could still call methods defined in the interface.

Pointers

While it is perfectly fine to use a UObject pointer to hold a reference to an object that extends an interface, you can also explicitly indicate that a pointer is expected to implement an interface by using the TScriptInterface template.

UPROPERTY(BlueprintReadWrite)
  TScriptInterface<IInteractable> Interactable;

You can assign an object that may implement the interface to the pointer. If the assigned object does not implement the interface, Interactable will evaluate to false in a boolean context. Otherwise, you can call any of the methods defined in the interface on the object:

Interactable = OtherActor;
if (Interactable) {
    Interactable->Interact();
}

Warning

The TScriptInterface wrapper only works if the object's class (or one of its ancestors) implements the interface in C++. Pure Blueprint implementations will not work with this wrapper.