Custom Generic Components

C++ does not have Generics like in C#, but the concept in C++ that is most similar to what you are talking about is “Templates”, usually expressed as Class<T>

these are a mechanism for dynamically allowing for a type to be chosen partially at runtime (because they have an overhead cost due to that strongly typed nature of C++, and the performance gained from pre-compilation), but mostly done at compile time.

Templates are already used throughout the Engine basically any time you see <VariableType> that is a template function or Template class (for example the TArray<T> or any Engine class that has a leading character of “T” for that matter. (technically the Cast<T> breaks this rule but that is because it is a special wrapper on dyncamic_Cast<T> for consistency and friendlier integration on other platforms.

for implementing them in your game you can look at things like TArray (in like VS you can right-click the TArray and pick “Go To Definition”) though realistically I would strongly discourage making your own Template class as they can be very tedious, and you might need to incorporate many edge cases. my suggestion would be to either use “Interface” based inheritance, or “pure inheritance”:

in the pure inheritance approach you would create a “Generic” UGenericInventoryComponent that has the bare minimum needed, but also includes some kind of enumeration, or type identifier for “more precision”
give it the “needed” functions marked as Virtual and in the function declaration instead of giving it a function body put = 0 before the semicolon

public:
    // and classes with functions function marked as "virtual" and set "=0" cannot be instantiated only the child classes
    virtual GetCurrentItem() = 0;

then in the classes that inherit from UGenericInventoryComponent you would put

public
    virtual GetCurrentItem() override;

then give the implementation to the function there

then you can still have a member pointer of say TSubclassOf<UGenericInventoryComponent> or pass a UGenericinventoryComponent* as an argument

the reason for the enumeration of other Type identifier is in the event something needs to be strictly cast to a type you can go into a Switch-Case on an enum rather then then multiple if statements like:

if ( MyType1 var1 = Cast<MyType1>(TestCastingVariable))
{
}
else if ( MyType2 var1 = Cast<MyType2>(TestCastingVariable))
{
}
...

*the other option is interfaces: these are more a set of function promises, and C++ technically allows for you to give them data members (similar to how C++ allows you to give structs functions). this is how C++ gets into “technically” having “multi-inheritance”

this way you can do tricks where say in your interaction to “pick up” you can do you collision or trace out of the OtherComponent, or HitComponent you can test if it “implements Interface”

you will still need to implement the functions of the interface similar to the pure inheritance, but this is one other option.