To create a class of Base objects that supports persistence and
that can be stored and restored using the
SaveBase
and LoadBase
modules (see Section 8.2, “Composing, Storing and Retrieving Base
Objects”), the following
steps can be taken (this is an alternative to the TreeNode
persistence mechanism):
Derive your custom class from Base
or
another class derived from Base
(
Section 2.1.2.3, “Base
Field”
).
Include
mlAbstractPersistenceStream.h
in your header
file.
Overwrite the virtual methods
writeTo()
and
readFrom()
.
Overwrite the virtual method
implementsPersistence()
to return true for the persistence interface(s) that you implement. This is a new requirement so that other instances can decide which persistence interface to use.
Assign a version number to your class by using the macro
ML_SET_ADDSTATE_VERSION(VersionNumber)
in
your public class header.
This is the same as in the TreeNode
interface
Add the ML_CLASS_HEADER(ClassName)
macro in the header.
Add the ML_CLASS_SOURCE(ClassName, SuperClassName)
macro in the cpp.
Call YourClass::initClass()
in the
project's init.cpp file.
The following example shows how to implement persistence to a
simple class SegmentedObject
. The class
SegmentedObject
is derived from
BaseItem
which is derived from
Base
:
Base (abstract class, no members) | BaseItem (name, id) | SegmentedObject (objectGrayValue, voxelCount, boundingBox)
Example 8.2. How to Implement Persistence for Base
Objects
Header file of a class
SegmentedObject
:
class SegmentedObject : public BaseItem { ... public: //! announce supported persistence interfaces virtual bool implementsPersistence(PersistenceInterface iface) const { return (iface == PersistenceByStream); } //! Implement export functionality (as used by the SaveBase module): virtual void writeTo(AbstractPersistenceOutputStream* stream) const; // Set current version number ML_SET_ADDSTATE_VERSION(1); //! Implement import functionality (as used by the LoadBase module): virtual void readFrom(AbstractPersistenceInputStream* stream, int version); private: //! ML runtime system related stuff ML_CLASS_HEADER(SegmentedObject); // Members to be (re-)stored: //! The identifying gray value of this object long _objectGrayValue; //! Number of voxels long _voxelCount; //! Bounding box respective to original image SubImageBox* _boundingBox; ... }
Source file of class
SegmentedObject
:
Writing the object state to the stream:
//! Implement export functionality: void SegmentedObject::writeTo(AbstractPersistenceOutputStream* stream) const { // Add superclass members: ML_WRITETO_SUPER(BaseItem, stream); // Add this class' members: stream->write(_objectGrayValue, "ObjectGrayValue"); stream->write(_voxelCount, "VoxelCount"); // The bounding box is optional, do not write if the pointer is NULL: if (_boundingBox) { // start a new sub-structure stream->startStruct("BoundingBox"); stream->write(_boundingBox->v1, "v1"); stream->write(_boundingBox->v2, "v2"); stream->endStruct(); } }
Reading the object state from the stream:
//! Implement import functionality: void SegmentedObject::readFrom(AbstractPersistenceInputStream* stream, int version) { // Read super class members: ML_READFROM_SUPER(BaseItem, stream); // Handle version differences: // In this example, version 0 used a different tag for _objectGrayValue // and did not write the VoxelCount value. switch (version) { case 0 : // Read object gray value from old tag name parent->read(_objectGrayValue, "GrayValue"); break; case 1 : parent->read(_objectGrayValue, "ObjectGrayValue"); break; default: // Throw exception: A version upgrade was performed without adapting the version handling // Note that this exception only needs to be thrown if you want to be on the safe side. // The persistence framework outputs a warning on its own if a newer version than that // from ML_SET_ADDSTATE_VERSION is encountered. throw PersistenceStreamFormatException("Unsupported version"); } // Handle version difference (voxelCount available or not) // by calling the macro readOptional which sets // the given variable to a default value (second parameter) // in case the tag "VoxelCount" was not found. stream->readOptional(_voxelCount, 0, "VoxelCount"); // Bounding box is optional: // However, startStruct can not be called optionally, // hence we have to check beforehand if there is an element with the correct name: if (stream->isNextInStruct("BoundingBox")) { try { ML_CHECK_NEW(_boundingBox, new SubImageBox()); stream->startStruct("BoundingBox"); stream->read(_boundingBox->v1, "v1"); stream->read(_boundingBox->v2, "v2"); stream->endStruct() } catch (const PersistenceStreamException& e) { // make sure to delete bounding box again: ML_DELETE(_boundingBox); // re-throw exception throw; } } }
Registering the class in the runtime type system:
ML_CLASS_SOURCE(SegmentedObject, BaseItem)
© 2024 MeVis Medical Solutions AG