Simple data types are flattened by writing the data type to the stream using the stream's ::Write member function. References to other instances are flattened by recursively calling the FlattenPointer routine with the parameters that were passed in.
For example, if class C is descended from classes A and B, has a member instance d of class D, has a member long, a member char, and a pointer to an E instance (e), its Flatten routine looks like this:
TStream& C::operator>>=(TStream* towhere) { WriteVersion(towhere); A::operator>>=(towhere); B::operator>>=(towhere); d.operator>>=(towhere); fLong >>= towhere; fChar >>= towhere; towhere.FlattenPointer(e); return towhere; }
NOTE Remember to write out the "version number" associated with this instance. These version numbers are updated whenever the external representation of the instance changes. Your stream in operator looks at this when reading and take the appropriate action. You must read in all old versions.
The stream in member function is called by the Resurrect procedure as well as directly by yourself to restore an instance from its flattened form. For example, if class C is descended from classes A and B, has a member instance d of class D, has a member long, a member char, and a pointer to an E instance (e), its Expand routine looks like this:
TStream& C::operator<<=(TStream* fromwhere) { VersionInfo v = ReadVersion(fromwhere); if (v == kNewVersion) { A::operator<<=(fromwhere); B::operator<<=(fromwhere); d.operator<<=(fromwhere); fLong <<= fromwhere; fChar <<= fromwhere; e = (E*) fromwhere.Resurrect(); } else { //read the old version ... } return fromwhere; }