[pascal]TPersistentObject = class
public
constructor Create; virtual;
destructor Destroy; override;
procedure Save(aStream: TStream); virtual;
procedure Load(aStream: TStream); virtual;
procedure Assign(var aObj: TPersistentObject); virtual;
end;

TPersistentObjectClass = class of TPersistentObject;[/pascal]

Now you can can have a system where you can register you objects for persistence. Since TPersistentObject has a virtual constructor you can do stuff like this:

[pascal]function InitObject(aObj: TPersistentObjectClass): TPersistantObject;
begin
Result := aObj.Create; // works because of the virtual constructor
end;

obj := InitObject(TMyDerivedPersistentObject);[/pascal]

My point is that by having a persistent object and taking advantage of virtual constructors you can create instances of objects without full knowledge of them. If you had a bunch of objects saved to a stream, you would be able to load them all back into memory.

How can this help you with your problem? Assuming that you have a good hierarchy of streamable classes prepared and registered with your streaming system, to duplicate any persistent class would simply be a matter of saving to a temp stream, then creating an instance of this class off the stream and it would be duplicated without knowledge of the classes that it's derived from. The streaming system helps to make it less complex moving forward.

I hope you can see the underlying logic of my point. Inside the Assign method you create a temp stream, save the object off to it, then create an instance of it and assign it to aObj. Now no matter how complex it maybe, if you've setup things where the object can save/load itself from the stream it will be recreated. Plus you have the advantage of a general object persistence system.

In one project I was able to save all the game objects to a stream (including objects that happen to be exploding at the time) and was able to load all of them back and those objects continued exploding. That was freakishly cool.

Now you have to decide on how complex you want your streaming system. In my case I manually saved all the relevant data to and from the stream from inside the Save/Load methods. You can have things where you can define which fields gets saved and loaded so that it's more automatic sort of like what Delphi does with published properties. I just needed the framework in place and when Save/Load gets called either directly by me or from some another class you just have to make sure the proper data will get saved and can be loaded. It worked really well for me in the past and I will be using this system for PyroGine SDK.

Maybe this can be a possible solution for you as well.