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 {
// Read employee name and id
(* PArchive)> m_strName;
(* PArchive)> m_nId;
}
}
CATCH_ALL (pException)
{
NStatus = ERROR;
}
END_CATCH_ALL
Return (nStatus );
}
This code has a problem. What if we mistakenly read non-existing information from the data file? If the data file is not an integer after the CString, The serialize () function returns ERROR. This is good, but if we can locate the error and return a more detailed error message, such as INVALID_DATAFILE, it would be better. We can use the object signature to confirm that we are reading a valid data file.
Object Signature
Object signature is to use a string to identify an object. 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
};
The signature is stated in Foo. cpp:
// Static constants
Const CString CFoo: Signature = "FooObject ";
Next, we modify the serialize () function to serialize the signature before serializing the data member of the object. If an invalid signature is encountered or the signature is lost, we can think that we are trying to read a data store that does not contain a Cfoo object. The process for reading signed objects is as follows:
The following is the process implementation code:
Int CFoo: serialize
(CArchive * pArchive)
{
Int nStatus = SUCCESS;
Bool bSignatureRead = 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 invalid
CString strSignature;
(* PArchive)> strSignature;
BSignatureRead = true;
If (strSignature. Compare (getSignature ())! = 0 ){
Return (INVALID_DATAFILE );
}
// Read employee name and id
(* PArchive)> m_strName;
(* PArchive)> m_nId;
}
}
CATCH_ALL (pException)
{
NStatus = bSignatureRead? ERROR: INVALID_DATAFILE;
}
END_CATCH_ALL
Return (nStatus );
}
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, it is very helpful to add an object signature registration step within the company. On the other hand, developers will not use the same signature for different objects. If you want to make your data files more difficult to reverse, you should use a signature that has no obvious relationship with the object name.
Version
If you upgrade the product within its lifecycle, you may need to add or delete data members to modify the Cfoo class structure. If you only release a new version for Cfoo and try to read objects of the old version from the data storage, it will fail. This is obviously unacceptable. Any version of Cfoo should be able to restore an earlier version.
In other words, the serialization method of Cfoo should be forward compatible. This problem is easily solved by adding a version to the object. Like adding a signature to an object, we add an integer constant to specify the version number of the 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 object version number is stated in Foo. cpp.
// Static constants
Const CString CFoo: Signature = "FooObject ";
Const int CFoo: Version = 1;
Next, we modify the serialize () function to serialize the version of the data member of the object after the signature is serialized. If we try to read a version that is not supported by an object in an updated version, then in the following example, we will return a status flag UNSUPPORTED_VERSION.
Int CFoo: serialize
(CArchive * pArchive)
{
Int nStatus = SUCCESS;
Bool bSignatureRead = 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;
}
<