Serialization preliminary (translation)
Original: http://www.codeproject.com/cpp/serialization_primer2.asp
In the first part, we learned how to serialize a simple object through the Serialize () function of the CARCHIVE class. Like the following program:
Int cfoo :: serialize
(CARCHIVE * PARCHIVE)
{
INT NSTATUS = SUCCESS;
// Serialize the Object ...
Assert (Parchive! = Null);
Try
{
IF (Parchive-> isstoring ()) {
// Write Employee Name and ID
(* parchive) << m_strname;
(* parchive) << m_nid;
}
Else {
// r rEee name and id
(* PARCHIVE) >> M_STRNAME;
(* PARCHIVE) >> M_NID;
}
}
Catch_all (pexception)
{
NSTATUS = Error;
}
END_CATCH_ALL
Return (NSTATUS);
}
This code has a problem, if we are wrong from reading the information that does not exist in the data file? If the data file is not an integer after CString, then the serialize () function will return Error. This is also good, but if we can give the wrong position and return a more detailed error message, such as invalid_datafile, it is better. We can confirm that we are reading a valid data file through an object signature.
Object signature
Object Signature is to identify an object with a string. We modify the definition of the CFOO class to add a signature:
Class Cfoo
{
...
//Methods
PUBLIC:
...
CString getSignature ();
// Data MEMBERS
...
protected:
Static const cstring signature; // Object Signature
}
Signature in foo.cpp:
// static constants
Const cstring cfoo :: signature = "fooObject";
Next, we modify the serialize () function, first serialize this signature before the data of the serialized object. If you encounter an invalid signature, or if the signature is missing, we can think that we are trying to read a data store that does not contain a Cfoo object. The following is the process of reading an object with a signature:
The following is the process implementation code:
Int cfoo :: serialize
(CARCHIVE * PARCHIVE)
{
INT NSTATUS = SUCCESS;
Bool bsignatureauRead = false;
// Serialize the Object ...
Assert (Parchive! = Null);
Try
{
IF (Parchive-> isstoring ()) {
// Write Signature
(* PARCHIVE) << getSignature ();
// Write Employee Name and ID
(* parchive) << m_strname;
(* parchive) << m_nid;
}
Else {
// read signature - Complain if INVALIDCSTRING STRSIGNATURE
(* parchive) >> STRSIGNATURE;
BsignatureRead = True;
IF (strsignature.Compare (getSignature ())! = 0) {
Return (Invalid_DataFile);
}
// r rEee name and id
(* PARCHIVE) >> M_STRNAME;
(* PARCHIVE) >> M_NID;
}
}
Catch_all (pexception)
{
NSTATUS = BSIGNATUREAD? Error: invalid_datafile;
}
END_CATCH_ALL
Return (NSTATUS);
}
You must make sure that all your objects have a unique signature. The specific signature content is not important. If you are developing a batch of products, adding an object signature registration step in the company is very helpful. On the other hand, developers will not use the same signature to different objects. If you want your data file more difficult to be refused, then you should use a signature that does not have any obvious relationship with the object name.
version
If you upgrade in the life cycle of the product, then you may want to modify the CFOO class structure by adding or deleting data members. If you just post a new version for CFOO, try to read the old version of the old version from the data store, it will fail. This is obviously unacceptable. Any version of Cfoo should be able to restore an older version.
In other words, the serialization method of CFOO should be compatible forward. This problem is easy to complete by adding versions to an object. In the same way as an increase in object, we add an integer constant to specify the version number of this object.
Class Cfoo
{
...
//Methods
PUBLIC:
...
CString getSignature ();
Int getversion ();
// Data MEMBERS
...
protected:
Static const cstring signature; // Object Signature
Static const Int version; // Object Version
}
The version number of the object is in foo.cpp
// static constants
Const cstring cfoo :: signature = "fooObject";
Const int cfoo :: Version = 1;
Next, we modify the serialize () function, after serializing the signature, serialized the data member's data member. If you encounter an updated version, we try to read an object that does not support, then in the following example, we return a status flag Unsupported_Version.
Int cfoo :: serialize
(CARCHIVE * PARCHIVE)
{
INT NSTATUS = SUCCESS;
Bool bsignatureauRead = false;
Bool BversionRead = false;
// Serialize the Object ...
Assert (Parchive! = Null);
Try
{
IF (Parchive-> isstoring ()) {
// Write Signature and Version
(* PARCHIVE) << getSignature ();
(* parchive) << getVersion ();
// Write Employee Name and ID (* parchive) << m_strname;
(* parchive) << m_nid;
}
Else {
// read signature - Complain if INVALID
Cstring strsignature;
(* parchive) >> STRSIGNATURE;
BsignatureRead = True;
IF (strsignature.Compare (getSignature ())! = 0) {
Return (Invalid_DataFile);
}
// read version - Complain if unsupported
Int nversion;
(* PARCHIVE) >> NVERSION;
BversionRead = true;
IF (NVersion> getVersion ()) {
Return (unsupported_version);
}
// r rEee name and id
(* PARCHIVE) >> M_STRNAME;
(* PARCHIVE) >> M_NID;
}
}
Catch_all (pexception)
{
NSTATUS = BSIGNATUREAD && BVERSIONREAD? Error: invalid_datafile;
}
END_CATCH_ALL
Return (NSTATUS);
}
Cfoo's version 1 contains two data members: a cstring type (m_strname) and an int type (m_nid). If we add a third member (for example, int m_ndept) in version 2. Then we have to decide, when reading an old version, M_ndEPT should initialize how much. In the following example, we initialize m_ndept to 1, means that the department of the staff is "unknown".
Class Cfoo
{
...
// Data MEMBERS
PUBLIC:
CString M_StrName; // Employee Name
INT M_NID; // Employee ID
INT m_ndept; // Department Code (-1 = unknown)
}
We need to change the version number of the object in foo.cpp to 2.
Const int cfoo :: Version = 2;
Finally, we modify the part of the object in the serialize () function, if we read an old version of the data file, initialize m_ndept into -1. Note that files are always available in the latest version.
Int cfoo :: serialize
(CARCHIVE * PARCHIVE)
{
...
// Serialize the Object ...
Assert (Parchive! = Null);
Try
{
IF (Parchive-> isstoring ()) {
...
// Write Employee Name, ID and Department Code
(* parchive) << m_strname;
(* parchive) << m_nid;
(* parchive) << m_ndept;
}
Else {
...
// r rEee name and id
(* PARCHIVE) >> M_STRNAME;
(* PARCHIVE) >> M_NID;
// read department code (new in version 2) if (nversion> = 2) {
(* PARCHIVE) >> M_NDEPT;
}
Else {
m_ndept = -1; // unknown
}
}
}
Catch_all (pexception)
{
NSTATUS = BSIGNATUREAD && BVERSIONREAD? Error: invalid_datafile;
}
END_CATCH_ALL
Return (NSTATUS);
}