USTRUCT and inheritance

Hello, I found out something very strange. A USTRUCT can inherit a struct, only if it is a base struct.
For instance the following snippet does not work:


#pragma once

#include "CoreMinimal.h"

#include "FMinimumExample.generated.h"

struct TEDIUM_API FSubClassIntVector : public FIntVector
{
};

USTRUCT()
struct TEDIUM_API FMinimumExample : public FSubClassIntVector
{
    GENERATED_BODY()
};

This gives compile error : ‘struct’: Can’t find struct ‘FSubClassIntVector’. At the same time, if you directly extends from FIntVector works. Any idea why this limitation exists?
Is there a way around it?

Although this probably doesn’t answer the why. It’s probably just how the UHT tool is designed.

Here are 2 proposed alternatives.

As you said, your original example doesn’t work.

This works for me.


USTRUCT()
struct FSubClassIntVector : public FIntVector
{
    GENERATED_BODY()
};


USTRUCT()
struct FMinimumExample : public FSubClassIntVector
{
    GENERATED_BODY()
};


This leads me to believe UHT can’t handle multiple inheritance for things that everything isn’t a USTRUCTs.
Which means if you want to have part of your game ‘inside UE4’ and some ‘outside UE4’ You totally can, but you just need to separate the layers more distinctly and not be 1/2 in and a 1/2 out. Either go fully in with USTRUCTS or have a clearly defined communication layer to the outside.

Alterantively,

If FSubClassIntVector is out of your control to edit. You can go with a composition approach instead. Then just pass off the internal struct at the appropriate place instead. It requires a slightly different approach in other areas depending on the project.
This works for me too.



struct FSubClassIntVector : public FIntVector
{
};

USTRUCT()
struct FMinimumExample{

    GENERATED_BODY()

    FSubClassIntVector SubClassIntVector;
};


This is by design, but you can get around it in special cases. Typically - Reflection requires that the primary type your inherit from must also be a reflected type. You can use multiple inheritance, but the additional types that you inherit from cannot be reflected types.

However there are cases where it’s legitimate to declare a new reflected type but also inherit from a non-reflected type - particularly for USTRUCT(). For obvious reasons you can’t expose this to the reflection system, but using the #if CPP pre-processor macro you can tell UHT to skip certain lines which will allow these cases to compile. This is how I am able to use an interface class for these two structs:



class IST_ComboBoxItem
{
public:
    virtual ~IST_ComboBoxItem() {}

    virtual FText GetDisplayText() const = 0;
};

USTRUCT(BlueprintType)
struct FOption_StringValue
#if CPP
    : public IST_ComboBoxItem
#endif
{};

USTRUCT(BlueprintType)
struct FOption_DiscreteValue
#if CPP
    : public IST_ComboBoxItem
#endif
{}


12 Likes

Sorry for resurrecting this thread, but thought I’d just add that this works for me in UE5. Not sure if it has been a recent addition, but here is my USTRUCT inheritance structure that works fine.

USTRUCT(BlueprintType)
struct FInventoryItem : public FTableRowBase { GENERATED_BODY() }

USTRUCT(BlueprintType)
struct FInventoryItemEquipment : public FInventoryItem { GENERATED_BODY() }

USTRUCT(BlueprintType)
struct FInventoryItemWeapon : public FInventoryItemEquipment { GENERATED_BODY() }

That works fine because all of the types you are inheriting are reflected base types.

Ah that makes sense, looks like I misinterpreted the initial question. Thanks for replying!

amazing thank you