The PersistentObject class (See Figure 3.22) should be used as the base class of all the objects in the persistent storage.
This class provides the mechanism for storing and obtaining the run-time type information of a persistent object. The only member variable objectID can serve as the identifier for the type of the object.
In constructors of a derived class, the objectID is set as the unique value for the class. The assignment mechanism of the values are not implemented in the current version of the persistent storage.
The accessor getID() just returns the objectID of the object. The following is a sample usage of the run-time type information mechanism.
enum OID { OID_DerivedObject = 1, ...}; // assign ObjectIDs class DerivedObject: public PersistentObject { public: DerivedObject(...): PersistentObject(OID_DerivedObject) { ... } ... }; PersistentPointer pp = something; PersistentObject *obj; obj = (PersistentObject *)pp.grab(); switch (obj->getID()) { // obtain the ObjectID case OID_DerivedObject: // the type of obj is detected ((DerivedObject *)obj)->doSomethingOnDerivedObject(...); ... };
Unfortunately, the built-in virtual function mechanisms in C++ corrupt in the persistent storage, for the pointers to the virtual tables are included in all the objects that implement virtual functions. The pointers become meaningless in the persistent storage.
There are two types of solutions for these limitations. One has just been described above. The other solution is not portable but more powerful. The purpose is the avoidance of the corruption of the virtual tables. If the pointers to the virtual tables are adjusted at the address conversions, i.e., the grabbing operations, the reference pointers handed to the user can be used as virtual pointers.
The implementation of virtual functions in the compiler greatly affects the implementation of this mechanism, and is not portable. More profound analysis is required for the run-time type information mechanisms.