Download

Any Object implementing an Interface as parameter

So, I guess this is answered in the wiki somewhere, but hey, the Wiki is gone and now I have to ask this.

The beauty of interfaces is that I don’t have to care about which class is implementing the interface, as long as it implements the functions.

So, I have a bad time figuring out how to pass any object implementing an Interface as a parameter to a function and to get it as a return value.

Just to make sure you understand my problem, I would like to do something like this:


UINTERFACE(MinimalAPI, Blueprintable)
class UMyInterface : public UInterface
{
    GENERATED_BODY()
};

/**
 *
 */
class IMyInterface
{
    GENERATED_BODY()

    UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
    void ApplyDamage(const IMyInterface InReference, IMyInterface& OutReference);
};

Does anyone know how to achieve this?

Edit: it’s possible to do it in Blueprint, so I guess It has to be possible in c++ too.

You still have to know that the object your calling the function on actually inherits from the interface - so you just call it like a normal function.

BP-Implementable Interface functions have to be called like this: IMyInterface::Exec_SomeFunction(SomeObject, FuncParams);

Thanks, but that doesn’t answer my question.

A reflected reference to an interface has to be done via TScriptInterface. See ScriptInterface.h

Seems like an odd pattern to return an interface from an interface though…

Already tried every form of


TScriptInterface<IMyInterface>

I can think of. None working so far.

That’s not what I want to do. I want to return an object implementing an interface. But I could achieve what I want without returning it, but I still need to pass my object to the function.

I’m not sure I understand what you want to do to be honest.

Given the example code you showed, you cannot just call that function on any random object. You can only call it on an object which implements the interface, and therefore you already have to know whether it implements it or not, and already have a reference to it. It’s no different in Blueprint.

Either way, both of these functions compiled fine for me - and gave me a node with an interface pin on the return. Obviously in this example the interface is null, in reality you would have to populate it with something.



UFUNCTION(BlueprintCallable, Category = "Test")
TScriptInterface<IHLLTeamInterface> GetTeamIFace() const { return TScriptInterface<IHLLTeamInterface>(); }

UFUNCTION(BlueprintNativeEvent, Category = "Test")
void GetTeamIFace(TScriptInterface<IHLLTeamInterface>& OutInterface) const;
void GetTeamIFace_Implementation(TScriptInterface<IHLLTeamInterface>& OutInterface) const { OutInterface = TScriptInterface<IHLLTeamInterface>(); }


Hi Relax,

I’ve rewritten your code slightly so that it does (what I think you want?)




UINTERFACE(MinimalAPI, BlueprintType)
class UMyInterface : public UInterface
{
    GENERATED_BODY()
};

class IMyInterface
{
    GENERATED_BODY()
public:

    UFUNCTION(Category = "Test Interfaces", BlueprintCallable, BlueprintNativeEvent)
        void ChainingCall(const TScriptInterface<IMyInterface>& InInterface, float SomeParameter, TScriptInterface<IMyInterface> & OutInterface);

};


I compiled and tested it in the latest preview of 4.25, however, it looks a little strange to me in blueprints. But, it is what it is. (other here, is just an “Actor”)

We pass pointers to interface objects in and out of functions a lot and never used “TScriptInterface”. Never even heard of it tbh…

Is TScriptInterface required because you are using a ref to an interface object and not a pointer?

edit: actually going over the code Interfaces are almost exclusively used for all game code. The “TScriptInterface” keyword is never used:



 /**
 * Get interactive actor currently selected by player.
 */
 IInteractiveBase* GetSelectedInteractiveActor();

 /**
 * Set interactive parent component this object is attached to.
 * Logs an error if this object is an actor or the object passed is not a component.
 */
virtual void SetInteractiveParentComponent(IInteractiveBase* component) = 0;


None of that will work with reflection/blueprint which is what OP asked for. Make those functions BlueprintCallable and it will no longer work.

You also can’t use pointers to IInterfaces directly unless the interface is exclusively implemented in C++, and they have no Blueprint UFUNCTIONS(). If that interface is implemented on a Blueprint asset and not in the native CPP class, casts and suchlike will fail.

I didn’t asked to call it on any object, I want to call it on any object implementing the interface. My only problem was that I coudln’t get it to compile.

Yeah, that’s pretty much why I also wanted to return it, but I think I will use a different approach, more like a state machine. But I still need to pass the interface and returning it might still be useful.

So, thanks for the correct syntax TheJamsh and Gossy, I also tried to add ‘&’ after I looked into the generated gen.cpp and at the TScriptInterface constructor, but really wasn’t sure about it.

I know TScriptInterface is required if you want to store the interface as a UPROPERTY, if you don’t use them you a compiling error:



Error: UPROPERTY pointers cannot be interfaces - did you mean TScriptInterface<ISomeInterface>?


But other than that I use a pointer to the interface in the signature of functions.
I haven’t tried to use them with blueprint functions so I can’t comment on that.

No worries, as a side note, constructing TScriptInterface and passing it back up to blueprint is a little odd, you can’t test the validity of interface types in Blueprint, so you’re best off doing it inside functions that pass them up (if there’s a chance they’ll be null)



UCLASS()
class UMyFunctionLibrary : public UBlueprintFunctionLibrary
{
    GENERATED_BODY()
public:

    UFUNCTION(Category = "Test Interfaces", BlueprintCallable)
        static void GetObjectAs(UObject * InObject, bool & IsValid, TScriptInterface<IMyInterface> & OutInterface)
    {
        OutInterface = nullptr;
        OutInterface.SetObject(InObject);
        OutInterface.SetInterface(Cast<IMyInterface>(InObject));
        IsValid = (OutInterface || (InObject && InObject->Implements<UMyInterface>()));
    };
};


You can actually cast the interface to an object to test its validity and to compare interface references.

For me, if I call a blueprint function and pass in a reference to an object that I know implements that blueprint, the Interface pointer is null but the object isn’t.

I’d think the interface pointer should be populated for us. Are we supposed to assign it manually in our C++ UFUNCTION?

You can’t assign it at all, that’s the issue and is why casting interfaces in C++ doesn’t work if they are implemented in Blueprint.

From what I can gather, implemented interfaces in Blueprint are just a list of names in the Generated Class. To determine whether a Blueprint class implements and interface, it compares all entries in that array to see if it can find a match with the reflected interface class name.

Calling functions is then handled through reflection. Essentially functions are looked up by name from the generated reflection data, and then called via ProcessEvent with the neccesary params. You can’t populate the pointer because there’s nothing to populate it with, the interface technically isn’t implemented as far as C++ is concerned.