Providing construction time critical state to a parent from the Child

Prof. Berrier
Sun, 24 Sep 2023 15:56:17 +0000
Programming & Scripting

There’s a fairly common pattern in C++ that I cannot figure out how to implement when my class is a UObject. Let me describe the pattern first (I don’t think it has a name):

The parent has a critical piece of state that can be specified when the object is constructed.

This piece of state is only used during construction but we do want to preserve it so it is stored as a member, but marked private (to ensure it does not get accessed or changed even by a child). We might even mark it const to indicate the immutable nature of this value.

Since it is relevant during construction, it gets exposed as a constructor parameter and the child, when it invokes the parent’s constructor, can send a specific value to it through this parameter.

The child might even expose the value in its own constructor parameters, or it might send a fixed value to the parent and remove it from the overall object interface (for simplicity).

Nothing fancy here, but this kind of flexibility at construction time is important and useful! I can’t figure out how to do something like this for a UObject WITHOUT wrapping it in a Blueprint and adjusting the class defaults. To me, the fact that this IS possible from a Blueprint means there must be some C++ mechanism for it too, but I cannot unravel the UObject initialization black box enough to find it.

In the past, when something important like this needs to get customized, I have occasionally been able to do it from the child’s constructor. Just overwrite the parent’s variable and hope that it isn’t used by the parent until say, BeginPlay() or maybe PostInitProperties(). But that actually depends on the designers of your super class making a mistake (AFAIC). They SHOULD have marked a critical variable like that private (and maybe even const) and I don’t want to depend on bad encapsulation to work around this.

As it so happens, the folks working in the Learning Agents plugin did NOT make this mistake. There is a critical piece of state in the LearningAgentManager that is used to allocate memory during PostInitProperties() and they have it marked private. I cannot find ANY way to provide a value to this piece of state (MaxAgents) from my child class. I can only do it from a Blueprint using the class defaults because the variable is a UPROPERTY with the EditDefaultsOnly setting but I want to be able to (SHOULD be able to) avoid using Blueprint here.

There’s got to be a way to do this entirely from C++! I have imagined it will involve something with the FObjectInitializer system and its archetype, or maybe just clever coordination of the PostInitiProperties() functions, but for now, it is eluding me. Beyond the specific problem with the Learning Agents plugin, I’m wondering how the UObject system enables this kind of pattern where a value is needed at construction time but, due to UObject’s very specific construction and initialization restrictions, the vanilla C++ solution is not viable.

2 posts - 1 participant