Download

Is TSubclassOf<> possible with interfaces?

I have a C++ actor interface:



UINTERFACE(MinimalAPI, Blueprintable)
class USpawnableCreature : public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

class ISpawnableCreature
{
	GENERATED_IINTERFACE_BODY()

	// Functions here
}


And a C++ CreatureSpawner class with this property:



UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSubclassOf<USpawnableCreature> CreatureClass;


What I’m trying to achieve is that in the editor I can select CreatureClass from a dropdown menu of all C++ classes that implement ISpawnableCreature. So I’m only talking about C++ classes that implement the interface that are known at compile-time. What I’ve noticed is that you can’t do TSubclassOf. You will get this error:



'StaticClass' : is not a member of 'ISpawnableCreature'


I assume the type of TSubclassOf must inherit from UObject, which is why I’m now trying with USpawnableCreature. With this the code compiles and a drop down menu appears in the editor, except that its empty while I do have C++ that implement the interface. Does anyone know what I might be doing wrong? Is TSubclassOf possible with interfaces?

Some more things that I would like down the road. If anyone can shed some light on this that would be awesome:

  • Can I get blueprint classes that inherit from a C++ class that implements ISpawnableCreature to appear in the dropdown?
  • And how about blueprint classes that implement the interface themselves?

Unfortunately I don’t think this is currently possible. It seems to me that UE4 interfaces are rather limited at the moment - for example, I don’t believe it’s possible to get an interface pointer in C++ to an object of a blueprint type which implements that interface, unless the blueprint’s native (C++) ancestor itself implements the interface. This issue has led me to basically pass on using interfaces for the moment.

As to your issue, right, TSubclassOf works on UObjects, so you can’t use your ISpawnableCreature. And if you use USpawnableCreature, you won’t get anything in the dropdown, because nothing actually does inherit from USpawnableCreature - all the objects of interest inherit from both AActor (presumably, or anyway from UObject) and ISpawnableCreature. So you’re kinda stuck!

I think there are two options, neither very good.

  1. Create an ASpawnableCreature class derived from AActor. No doubt though there are inheritance tree reasons why you didn’t want to do this, which was why you tried to use an interface in the first place.
  2. Just make your property a TSubclassOf< AActor >, and do your checking for interface compliance at runtime. This kind of sucks for obvious reasons.

Hi kamrann, I have the same suspicions and if we’re right thats really too bad. Right now I’m using option 1, having an actor base class but that rules out some future options that I shouldn’t have to rule out.

Thanks for your input. :slight_smile:

Hi NisshokuZK.

The way you are doing it in your example is pretty much the only way to do TSubclassOf with interfaces at the moment. It’s not pretty or practical but it should work. Unfortunately it makes the workflow of interfaces rather unnatural and rather limiting. When you decorate a class with your IInterface type, it will infact test positive for inheriting the associated UInterface type. I really hope Epic offers up a more practical implementation of interfaces that is more runtime friendly :frowning:

Agreed, for various purposes it would be awesome to be able to select from a dropdown that only shows C++ classes that implement a certain UInterface. Even more if that dropdown also shows classes that only implement the interface at the blueprint level although I can see how achieving that would be very difficult, since their C++ base class is not known to implement the interface at compile-time.

Found a solution to this.

UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (MustImplement = "MyInterfaceName") )
TSubclassOf&lt;AActor&gt; MyInterfaceClass;

Just to be clear, “MyInterfaceName” is the exposed or “blueprint” name, not the C++ name. So if in c++ you define UFoo and IFoo as the interface classes then MustImplement = “Foo”.

Took me awhile to figure that one out.

Great find, thanks for posting. I’d seen what looked like support for this in the engine source code but never came across the meta specifier that triggered it.

I tried that but it does not work, neither with the I interface or the U interface.


UPROPERTY(EditAnywhere, meta = (MustImplement = "USelectable"))
TSubclassOf<UObject> Selected;


UPROPERTY(EditAnywhere, meta = (MustImplement = "ISelectable"))
TSubclassOf<UObject> Selected;

Dropdown list contains every UObject in both cases.

I think you need to drop the prefix:


MustImplement = "Selectable"

Great Solution !