Is it not possible to have parameterized constructors?

In my project, I have an abstract base class “ATerrain” which will be the basis for terrain tiles in my game. The world will generate an large grid of these terrain tiles based on this abstract base class, which comes with some intrinsic data. Let’s say for the sake of this question that my intrinsic variables are ClimateHarshness, ResourceAbundance, and ExpMultiplier.

I want to be able to instantiate this class like so:

ATerrain HarshDesert(
	9, // ClimateHarshness: Scales the effects of this environment on the player
	7, // ResourceAbundance: Scales the amount of resources that can be found here
	2, // ExpMultiplier: Player gains twice as much experience here
);

However, my problem is that there doesn’t seem to be an intuitive way to declare a parameterized constructor in a UCLASS. Here is my code in the class header:

UCLASS()
class MYGAME_API ATerrain : public AActor
{
	GENERATED_BODY()
public:
	ATerrain(int32 ClimateHarshness, int32 ResourceAbundance, int32 ExpMultiplier);
private:
	int32 ClimateHarshness_;
	int32 ResourceAbundance_;
	int32 ExpMultiplier_;
};

And here is the constructor definition in my class .cpp:

ATerrain::ATerrain(int32 ClimateHarshness, int32 ResourceAbundance, int32 ExpMultiplier) :
	int32 ClimateHarshness_(ClimateHarshness),
	int32 ResourceAbundance_(ResourceAbundance),
	int32 ExpMultiplier_(ExpMultiplier)
{
	// ...
}

I get the following compiler error:

You have to define ATerrain::ATerrain() or ATerrain::ATerrain(const FObjectInitializer&). This is required by UObject system to work correctly.

Which is strange because earlier I was getting a separate error with the same code:

Error: no instance of constructor “ATerrain::ATerrain” matches the argument list

It is possible.
You must have default constructor and whatever count parameterized. The trick is that in parameterized constructor you need to call default constructor initializator.
Assuming we have ATerrain::ATerrain() and ATerrain::ATerrain(int32, int32, int32) definition of second one need to be like this:

ATerrain::ATerrain(int32 ClimateHarshness, int32 ResourceAbundance, int32 ExpMultiplier) :
    ATerrain(), // Goes first
    int32 ClimateHarshness_(ClimateHarshness),
    int32 ResourceAbundance_(ResourceAbundance),
    int32 ExpMultiplier_(ExpMultiplier)
{
    //...
}

Tried this but getting an error a delegating constructor cannot have other mem-initializers

I declared ATerrain() and ATerrain(int32, int32, int32) in the header and defined ATerrain() as blank and the second one as you showed. I get that error from Intellisense and then additional errors when compiling, stating that the variables have “already been initialized”.

I fixed this by reversing the order of my constructor declaration. My solution is similar to what you showed me, just the other way around. So now my default constructor with no parameters calls the parameterized constructor with arguments of 0:

// Parameterized constructor
ATerrain::ATerrain(int32 ClimateHarshness, int32 ResourceAbundance, int32 ExpMultiplier) :
	int32 ClimateHarshness_(ClimateHarshness),
	int32 ResourceAbundance_(ResourceAbundance),
	int32 ExpMultiplier_(ExpMultiplier),
	SquareSectors_(3),
	SectorSquareMeters_(100)
{
 	// ...
}
// Default constructor
ATerrain::ATerrain() :
	ATerrain(0, 0, 0)
{
	// ...
}

I’m not sure even if you do get your class to compile with a parametered constructor, if its useful. Actors are usually spawned using the UWorld::SpawnActor function which doesn’t give you an option to include constructor parameters. What is the reason you want to pass the parameters in the constructor, rather than right after construction?

If you want certain values to be set before OnConstruction or BeginPlay or another initialization related function, you can use deferred actor spawning to do this. Spawning an actor causes it to not finish initialization immediately, allowing you to set values before OnConstruction, BeginPlay etc are called. Check out UWorld::SpawnActorDeferred or search for deferred actor spawning. Would that method be satisfactory for you?

What if you try to call ATerrain() inside ATerrain(int32, int32, int32)…
Or you can either just do as compiler says: define ATerrain(), only define, then create ATerrain(int32, int32, int32) and use it… No you can’t do that, default constructor will always be called when actor spawned, after that you can’t use parametrized constructor.
I was really sure it would work, but it’s not, my bad.
Zhi Kang Shao tells the right thing, is it really necessary to assign values before actor OnConstruction and BeginPlay called?
You can create method like GrandInitialize(int32, int32, int32) and call it after spawning terrain, all initialization operations goes there.

This approach will definitely work and it’s the one I’ve been using up until now. I was just trying a different approach where instead of spawning each Terrain unit one by one in the world, I would procedurally generate a grid of these terrain units behind-the-scenes in one single “Realm” class, and then spawn the entire generated landscape with a single method call.

I’m still not at all sure if this approach is even viable, but I’ve been reading up on GOF design patters and just trying some different approaches. Thank you for the SpawnActorDeferred suggestion; I may end up using that instead.

Interesting, how do you currently create your Terrain instances then? Using NewObject?

Well to be honest I hadn’t really gotten that far yet, but I was planning on using NewObject yes. I’ve been more focused on the architecture of the code right now to go along with my reading material. So the terrain class is pure state right now to just test the patterns. Like I said I’m not even sure if it will end up working with the way the Unreal Engine is set up, it’s more of an exercise.