Using class variables

What’s the proper way to use class variables and actually create objects from the variable?

My specific problem appears to be that I’m trying to create an object in a constructor; NewObject() gives the error “NewObject can’t be used to create default subobjects (inside of UObject derived class constructor) as it produces inconsistent object names. Use ObjectInitializer.CreateDefaultSuobject<> instead.”. However, CreateDefaultSuobject is not an option because the class is passed in through the template, meaning it must be a specific type, and I can’t use a class for dynamic object creation.

What I’m trying to accomplish with this is streamlining the mesh components. Right now I have mesh component declared in the abstract class Weapon, however since it’s abstract, Weapon itself will not have a mesh. What I want to do is basically, in Weapon, “Create a mesh specified by a variable, attach to root, set properties on that mesh”. It looks like if I can’t do this, I would need to copy/paste this code into every single subclass that I make.

I’m still new to this so it’s possible that my approach is completely off. Any assistance would be appreciated. Thanks.

Yeah, I had this same problem and couldn’t find a way to do this in the constructor.
I ended up creating a virtual function (which can be overridden by subclasses) which was called from OnConstruction().

OnConstruction() doesn’t technically form part of the construction routine (it’s execution doesn’t originate from the constructor - it is called later by some other Unreal-specific code, similar to BeginPlay()).

I do have a question for you:

Is the component you’re trying to create always e.g. a SkeletalMeshComponent?
If so, you can always still create the component in the constructor, but use the OnConstruction() approach to set the actual mesh (i.e. MeshComponent->SetSkeletalMesh(yourmesh). You can use ObjectFinder to find the mesh from a text reference.

I also wrote a fairly detailed forum post about my findings here if you’re interested in some more details.

The component is always the same class, i.e. UStaticMeshComponent. I considered that, but I don’t think it will work for the same reason I can’t just set it while NULL.

It’d be something like:

Mesh = GetSomePlaceholderMesh();
Mesh->bCastDynamicShadow = false;
Mesh->AttachParent = RootComponent;
//...
Mesh = GetTheRealMesh();

I’d like to be able to assign variables on the mesh without setting it, but since it’s an actual object, GetTheRealMesh() would just “overwrite” any changes I had made.

If you do it in the constructor, yes. The reason is that you have no control over when parent constructors are called, it always goes:

  • Execute Base Class Constructor from start to finish
  • Execute First Child Class Constructor from start to finish
  • Execute Second Child Class Constructor from start to finish
  • Etc

When you do it in a virtual function (which is not part of the formal construction routine, like OnConstruction() or BeginPlay()), you do have control over when Superclass functions are called. E.g.

In YourParentClass.cpp:

void ParentClass::OnConstruction()
{
	Super::OnConstruction();
	CustomInit();
}

void ParentClass::CustomInit()
{
	// Get the mesh to use
	UStaticMeshComponent* meshToUse = GetMesh();
	
	// Set mesh
	Mesh->SetStaticMesh(meshToUse);
	
	// Set attributes
	SetMeshAttributes();
}

UStaticMeshComponent* ParentClass::GetMesh()
{
	return someDummyMesh;
}

void ParentClass::SetMeshAttributes()
{
	Mesh->bCastDynamicShadow = false;
	...
}

Now, in YourChildClass.cpp:

void ChildClass::SetMeshAttributes()
{
    // Not calling Super here!
	Mesh->bCastDynamicShadow = true;
	...
}
	
UStaticMeshComponent* ChildClass::GetMesh()
{
	// You can also use a class reference here, as the child class value of such a property would be in effect at this point in time.
	return theRealMesh;
}

Or am I missing this entirely?

I think this would work, but wouldn’t reflect the changes fully in the editor, which is what I was hoping to accomplish by putting it in the constructor in the first place.

I’m just going to assume that I’m doing this wrong, and try to find a completely different approach for this.

Thanks.