I’m having trouble understanding how to properly call an interface function in C++ from blueprint objects that don’t implement the interface in code, but rather in the blueprint editor.
In general I’m using this method right now to call interface function of classes that implement the interface via code.
for (TObjectIterator<UObject> Object; Object; ++Object)
{
// Check if the object implements the interface
if (Object->Implements<UMyInterface::ThisClass>())
{
if (!IsValid(*Object)) continue;
if (Object->IsEditorOnly()) continue;
if (Object->HasAnyFlags(RF_ArchetypeObject | RF_ClassDefaultObject | RF_NeedInitialization | RF_DefaultSubObject | RF_Transient)) continue;
TScriptInterface<IMyInterface> Interface = *Object;
if (Interface)
{
Interface->SaveOwningObject();
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Object %s does not implement the interface"), *Object->GetName())
}
}
}
From what I understand TScriptInterface will only work with classes that implement the interface in code because it uses vtable lookup to find the interface address. Blueprint classes do not have this luxury, so how can we call those interface function on those classes?
Also, I’m not trying to do Execute_FunctionName but rather to call a virtual function in the interface, not a UFUNCTION().
That does not work. I even made some code to directly pass the blueprint instance deriving from AActor implementing the interface in blueprints just to make sure that nothing funky was going on with TObjectIterator.
This is not possible to do for blueprint generated classes. You will not be able to call a virtual function for a blueprint generated class defining the interface via blueprints. The reason is because interfaces declared in blueprints are constructed from the default object of the interface in the engine. This default object has a vtable and thus the virtual function is findable. But interfaces declared in blueprints only generate UFUNCTION declared functions for the class because that code can be generated.
You are correct, I thought this would be possible by “manually” calling the original function, since blueprint implementers cannot override virtuals. Something like ((ITestInterface*)Object)->ITestInterface::SaveOwningObject() which is the syntax used to call a base virtual function for a possibly-derived object. It does work to call the function, but once you are in the interface you can’t do much as your this pointer is now wrong. You could theoretically cast back UObject* Obj = (UObject*)this for that specific case, but then it wouldn’t work anymore for the regular case where this actually points to the interface’ vtable. GCC has a solution for that but as far as I figured, MSVC does not.
That’s actually a pretty good solution. Does solve my actual issue which is having a defined implementation for objects that implement the interface so there can be some kind of save all feature that always saves the object who owns the interface, but having the code live in the interface itself - and not have it blueprint visible. Thanks!