How to load an object from binary without knowing its exact class?

I’m trying to follow along with Rama’s guide to saving to binary. I’ve hit a wall in my understanding though, and could use some help.

I have an increasingly complicated class hierarchy, and I want to be able to save/load them to/from disk, ideally by passing in the parent class object rather than creating separate functions for every single child class.

Suppose I have an hierarchy like this:


class Parent
{
Variable1
Variable2
Variable3
}

class ChildA : public Parent
{
ChildAVariable1
}

class ChildB: public ChildA
{
ChildBVariable1
}


I have a whole library of objects (UObject) which will each be one of the above classes. I want to be able to save them all to disk in my own file format (let’s call it .customfile).

The place my thinking is breaking down is understanding how to deal with all the different subclasses. According to Rama’s tutorial, it seems like each individual variable in the class needs to be put into binary separately (is that correct?), and in the right order. So if I was just saving the Parent class, it would be easy. But do I need to do some conditional stuff inside the saving function to test what class I’m passing in, and save all the child class variables, or is there a better way?

And when loading back, suppose I have a folder of saved files like this:


Object1.customfile
Object2.customfile
Object3.customfile

I don’t initially know whether they are Parent, ChildA, or ChildB classes, so how do I know what to pass into the function to receive the data? Does the class perhaps need to have a variable for what class it’s creating? For example, ChildA would have:


UClass* ObjectClass = ChildA::StaticClass();

If that was the first variable saved/loaded from disk/binary, then it could run the rest of the loading operation conditionally based on that variable. Would that work? Is there a better way? A bit confused and could use some help!

That tutorial only explains how to manually serialize properties. To automatically serialize all UProperties on a class you can use:



Ar << ObjectClass;

if (Ar.ArIsLoading)
    Object = NewObject<UObject>(ObjectClass, ...);

if (Ar.WantBinaryPropertySerialization())
    ObjectClass->SerializeBin(Ar, Object);
else
    ObjectClass->SerializeTaggedProperties(Ar,Object,...);


These will iterate through the UProperties in the class and either write binary (fast but difficult or impossible to save delta properties during development) or tagged properties (slower but allows delta properties). So the idea is to first serialize the object class using Ar << ObjectClass; then spawn an instance of that class (if loading), then serialize the properties using the class and instance.

Be aware that UE4 packager won’t know about the properties you’re serializing here, so references to assets won’t be seen during packaging and will possibly be left out of the build altogether, you’ll have to force them to package somewhere else (e.g by using the “always package directory” settings). Also UObject has a bunch of properties that will be serialized but might cause problems if you load them back up again on top of an already constructed object, I have only ever used this strategy on UStructs.

Thanks for your response, it’s useful to know that.

I’ve actually ended up building a system where the first thing serialised is an enum used to identify the actual specific class. It reads that back first, then creates an object of that class and runs through some logic to load/save the correct properties. Got it working perfectly, so don’t think I’ll change anything now. But thanks anyway!