Sequence preliminary three (translation)
Http://www.codeproject.com/cpp/serialization_primer3.asp In the first two parts, we have learned how to provide strong support for serialization. In this part, we will learn the special rules that serialize any of the objects. Here are four common reference examples. Each example is composed of the previous one.
Ø Serialization a simple class
Ø Serialized a derived class
Ø Serialized a homologous gathering class
Ø Serialized a heterologous gathering class
Our searialize () method will return one of the following status codes:
l success
l invalidformat
l UnsupportedVersion
l Readerror
l writeerror
Serialization a simple class
A "simple class" is the definition of: one is not a parent class, and there is no object of the aggregation class. Serialization A simple class requires the following steps:
1. Serialized object signatures and versions
2. Serialized object members (if any)
In the following example, class Point contains two INT type variables, indicating the coordinates of the point. The signature of the object is defined as a static member (m_strsignature, and m_nversion), so each Point class instance is shared.
INT Point :: serialize
(CARCHIVE * PARCHIVE)
{
Assert (Parchive! = Null);
// Step 1: Serialize Signature and Version
Int nversion;
Try {
IF (Parchive-> isstoring ()) {
(* PARCHIVE) << Point :: m_strsignature;
(* parchive) << Point :: m_nversion;
} else {
Cstring strsignature;
(* parchive) >> STRSIGNATURE;
IF (strsignature! = Point :: m_strsignature)
Return (status :: invalformat);
(* PARCHIVE) >> NVERSION;
IF (NVersion> Point :: m_nversion;)
Return (status :: unsupporteded ";
}
// Step 2: Serialize MEMBERS
IF (Parchive-> isstoring ()) {
(* PARCHIVE) << m_nx;
(* parchive) << m_ny;
} else {
(* PARCHIVE) >> M_NX;
(* PARCHIVE) >> M_NY;
}
}
Catch (CEXCEPTION * PEXCEPTION) {
// a read / write error Occured
PEXCEPTION-> Delete ();
IF (Parchive-> isstoring ())
Return (Status :: WriteError);
Return (status :: readerror);
}
// Object Was SuccessFully Serialized
Return (Status :: Success);
}
Serialized a derived class
Detective class is a class that is born in a simple class and is not a class of aggregation classes. Serialized a derived class requires the following steps:
1. Serialized object signatures and versions
2. Base class of serialized object << Additional step 3. Serialized objects (if any)
In the following example, class ColoredPoint is derived from the Point class and adds an int type variable called M_NColor to represent the color of the point. As with all serialized classes, the ColoredPoint class also defines a static signature and version.
Int ColoredPoint :: Serialize
(CARCHIVE * PARCHIVE)
{
Assert (Parchive! = Null);
// Step 1: Serialize Signature and Version
Int nversion;
Try {
IF (Parchive-> isstoring ()) {
(* parchive) << coloredpoint :: m_strsignature;
(* parchive) << colorPoint :: m_nversion;
} else {
Cstring strsignature;
(* parchive) >> STRSIGNATURE;
IF (strsignature! = coloredpoint :: m_strsignature)
Return (status :: invalformat);
(* PARCHIVE) >> NVERSION;
IF (NVersion> colorPoint :: m_nversion;)
Return (status :: unsupporteded ";
}
// Step 2: Serialize The Base Class
INT NSTATUS = Point :: serialize (parchive);
IF (NSTATUS! = Status :: Success)
Return (NSTATUS);
// Step 3: Serialize MEMBERS
IF (Parchive-> isstoring ())
(* PARCHIVE) << m_ncolor;
Else
(* parchive) >> m_ncolor;
}
Catch (CEXCEPTION * PEXCEPTION) {
// a read / write error Occured
PEXCEPTION-> Delete ();
IF (Parchive-> isstoring ())
Return (Status :: WriteError);
Return (status :: readerror);
}
// Object Was SuccessFully Serialized
Return (Status :: Success);
}
Serialized a homologous gathering class
Homogenic aggregation class often uses a plurality of similar types of objects that are not stored. Serialized homologous aggregates require the following steps:
1. Serialized object signatures and versions
2. The base class of serialization (if any)
3. Serialized aggregation objects << Additional steps
4. Serialization Each aggregate object << Additional steps
5. Other members of serialization (if any)
In the following example, class ColoredPointList is a collection of ColoredPoint objects. For the sake of simplicity, the ColoredPointList class uses CPTRARRAY to store objects. As with all serialization classes, the ColoredPointList class also defines a static signature and version. The following is an example of a ColoredPointList class:
Class ColoredPointListList
{
// construction / destruction
Public: ColoredPointList :: colorPointList ();
Virtual colorPointList :: ~ colorPointList ();
// attributes
PUBLIC:
Static const cstring m_strsignature;
Static const INT m_nversion;
// Operations
PUBLIC:
Int Serialize (CARCHIVE * PARCHIVE);
//Members
protected:
CPTRARRAY M_COLOREDPOINTS;
}
Below is how we serialize it:
Int ColoredPointList :: Serialize
(CARCHIVE * PARCHIVE)
{
Assert (Parchive! = Null);
Int nstatus = status :: sucps;
// Step 1: Serialize Signature and Version
Int nversion;
Try {
IF (Parchive-> isstoring ()) {
(* parchive) << ColoredPointList :: m_strsignature;
(* parchive) << colorPointList :: m_nversion;
} else {
Cstring strsignature;
(* parchive) >> STRSIGNATURE;
IF (strsignature! = colorPointList :: m_strsignature)
Return (status :: invalformat);
(* PARCHIVE) >> NVERSION;
IF (NVersion> ColoredPointList :: m_nversion;)
Return (status :: unsupporteded ";
}
// Step 2: Serialize Base Class (if any)
//
// Nothing to do since colorPointList isn't derived from anything.
// But if it is deact, we'DPointList, We'D do:
//
// nStatus = basecoloredPointList :: serialize (parchive);
// if (nStatus! = status :: success)
// Return (NSTATUS);
// Step 3: Serialize Number of Items in Collection
INT NITEMS = 0;
IF (Parchive-> isstoring ())
(* parchive) << m_coloredpoints.getsize ();
Else
(* PARCHIVE) >> NITEMS;
// Step 4: Serialize Each Object in Collection
For (int NOBJECT = 0; (NOBJECT // 4a: Point to Object Being Serialized ColoredPoint * PcoloredPoint = NULL; IF (Parchive-> isstoring ()) PcoloredPoint = (colorPoint *) m_coloredpoints.getat (nobject); ElsepColoredPoint = New colorPoint (); Assert (pcoloredpoint! = Null); // 4b: Serialize IT NSTATUS = PcoloredPoint-> Serialize (PARCHIVE); IF (NSTATUS! = Status :: Success) Return (NSTATUS); IF (! parchive-> isstoring ()) m_coloredpoints.add (pcoloredpoint); } // Step 5: Serialize Object's Other Members (if any) // // Nothing to do Since ColoredPointList Doesn't Have Any Other //Members. But if it contact an int (m_nsomeint) and a foo // Object (m_foo), We'D do: // // if (Parchive-> isstoring ()) // (* parchive) << m_nsomeint; // else // (* parchive) >> m_ncolor; // // nStatus = m_foo :: serialize (parchive); // if (nStatus! = status :: success) // Return (NSTATUS); } Catch (CEXCEPTION * PEXCEPTION) { // a read / write error Occured PEXCEPTION-> Delete (); IF (Parchive-> isstoring ()) Return (Status :: WriteError); Return (status :: readerror); } // Object Was SuccessFully Serialized Return (Status :: Success); } Serialized a heterologous gathering class His heterologous aggregates often use multiple different types of different types of objects that are not necessarily stored. Serialized a heterologous aggregation class requires the following steps: 1. Serialized object signatures and versions 2. The base class of serialization (if any) 3. Serialized aggregation object 4. For each gathering object a. Serialized Object Signature << Additional Steps b. Serialized object 5. Other members of serialization (if any) You will notice that one of the only steps in serialization is 4 (a), before serializing each object itself, sequentially sequentially sequentially sequentially sequentially. This is more convenient to read data later. When serializing a homologous aggregation class, we handle the same type of object (ColoredPoint in the previous example). To read a ColoredPoint class, we constructed it in the heap and call its searialize () method. ColoredPoint * pcoloredpoint = new colorPoint (); NSTATUS = PcoloredPoint-> Serialize (PARCHIVE); When we deal with the heterologous aggregation class, we need to know the type of object we read. This information comes from the signature of the object. Since we have saved the object's signature when serialized, we can construct a suitable object according to the type of object. // read Object Signature Cstring strsignature; PARCHIVE >> STRSIGNATURE; / / CONSTRUCT OBJECT OF Appriate Type ISerializable * pObject = NULL; IF (strsignature == colorpoint :: m_strsignature) POBJECT = New colorPoint (); Else IF (strsignature == line :: m_strsignature) POBJECT = New line (); Else IF (strsignature == Rectangle :: m_strsignature) POBJECT = New Rectangle (); Else Return (status :: invalformat); Assert (POBject! = Null); // r r i NSTATUS = POBJECT-> Serialize (parchive); In the above code snippet, ColoredPoint, Line and Rectangle are all (finally) derived from a public base class iSerializable. In addition to the pure virtual functions, this class is not more than a abstract base class (in other words, it is an "interface"). ISerializable Definition Method GetSignature (), getversion, and serialize (). Class iSerializable { // construction / destruction PUBLIC: ISerializable :: iSerializable () {} Virtual iSerializable :: ~ iSerializable () {} // Operations PUBLIC: // Get The Object's Signature Virtual cstring getSignature () = 0; // Get the Object's Version Virtual int getversion () = 0; // serialize the object Virtual Int Serialize (CARCHIVE * PARCHIVE) = 0; } Ok, let us serialize the heterologous gathering class. In the following example, class ShapeList is a variable number of ColoredPoint, Line, and Rectangle objects, which are delivered in iSerializable. You can see these classes as the "ISerializable interface implementation". Int Shapelist :: Serialize (CARCHIVE * PARCHIVE) { Assert (Parchive! = Null); Int nstatus = status :: sucps; // Step 1: Serialize Signature and Version Int nversion; Try { IF (Parchive-> isstoring ()) { (* parchive) << shapelist :: m_strsignature; (* parchive) << shapelist :: m_nversion; } else { Cstring strsignature; (* parchive) >> STRSIGNATURE; IF (strsignature! = shapelist :: m_strsignature) Return (status :: invalformat); (* PARCHIVE) >> NVERSION; IF (NVersion> ShapeList :: m_nversion;) Return (status :: unsupporteded "; } // Step 2: Serialize Base Class (if any) // // Nothing to do since shapelist isn't derived from anything. // But if it is deact from baseshapelist, we'D do: // // nStatus = BASESHAPELIST :: Serialize (PARCHIVE); // if (nStatus! = status :: success) // Return (NSTATUS); // Step 3: Serialize Number of Items in Collection INT NITEMS = 0; IF (Parchive-> isstoring ()) (* parchive) << m_shapes.getsize (); Else (* PARCHIVE) >> NITEMS; // Step 4: Serialize Each Object in Collection For (int NOBJECT = 0; (NOBJECT // 4a: First Serialize Object's Signature Cstring strsignature; IF (Parchive-> isstoring ()) (* parchive) << pObject-> getSignature (); Else (* parchive) >> STRSIGNATURE; // // 4b: THEN Serialize Object // // 4b (1): Point to Object Being Serialized ISerializable * pObject = NULL; IF (Parchive-> isstoring ()) POBJECT = (iSerializable *) m_shapes.getat (nobject); Else { IF (strsignature == colorpoint :: m_strsignature) POBJECT = New colorPoint (); Else IF (strsignature == line :: m_strsignature) POBJECT = New line (); Else IF (strsignature == Rectangle :: m_strsignature) POBJECT = New Rectangle (); Else Return (status :: invalformat); } Assert (POBject! = Null); // 4b (2): Serialize IT NSTATUS = POBJECT-> Serialize (parchive); IF (NSTATUS! = Status :: Success) Return (NSTATUS); IF (! parchive-> isstoring ()) m_shapes.add (pcoloredpoint); } // Step 5: Serialize Object's Other Members (if any) // // Nothing to do since shapelist doesn't have any other // members. But if it contact an int (m_nsomeint) and // a foo object (m_foo), We'D do: // // if (Parchive-> isstoring ()) // (* parchive) << m_nsomeint; // else // (* parchive) >> m_ncolor; // // nStatus = m_foo :: serialize (parchive); // if (nStatus! = status :: success) // Return (NSTATUS); } Catch (CEXCEPTION * PEXCEPTION) { // a read / write error Occured PEXCEPTION-> Delete (); IF (Parchive-> isstoring ()) Return (Status :: WriteError); Return (status :: readerror); } // Object Was SuccessFully Serialized Return (Status :: Success); } Factory factory You can use a signature-based "class factory" to provide a new object instance to replace the ugly IF declaration in the code snippet. Here have some reference articles on the factory: Generic Class Factory by Robert A. T. Káldy THE FACTORY METHOD (CREATIONAL) Design Pattern by Gopalan Suresh Raj Abstract Factory Pattern by Mark Grand Although the article is complex and diverse, the basic thinking after this is the same. A class factories and classes don't have much difference, which provides an appropriate specified static method (for example: CREATE ()), which provides a special type of object. Through the factory's Create () method, you can hide the disgusting IF declaration. Slightly finishing the code: ... // Construct Object of ApproPriate Type ISerializable * POBject = MyclassFactory :: Create (strsignature); Assert (POBject! = Null); ...