Monday, December 21, 2009

Serialization in VC++

Reading and Writing Documents—SDI Applications
 Serialization: What Is It?

The term "serialization" might be new to you, but it's already seen some use in the world of object-oriented programming. The idea is that objects can be persistent, which means they can be saved on disk when a program exits and then can be restored when the program is restarted. This process of saving and restoring objects is called serialization. In the MFC library, designated classes have a member function named Serialize(). When the application framework calls Serialize() for a particular object, for example, an object of class CStudent, the data for the student is either saved on disk or read from disk. In the MFC library, serialization is not a substitute for a database management system. All the objects associated with a document are sequentially read from or written to a single disk file. It's not possible to access individual objects at random disk file addresses. If you need database capability in your application, consider using the Microsoft Open Database Connectivity (ODBC) software or Data Access Objects (DAO). The MFC framework already uses structured storage (for database) for container programs that support embedded objects. 

Reading and Writing Documents—SDI Applications
Disk Files and Archives

How do you know whether Serialize() should read or write data? How is Serialize() connected to a disk file? With the MFC library, objects of class CFile represent disk files. A CFile object encapsulates the binary file handle that you get through the Win32 function CreateFile(). This is not the buffered FILE pointer that you'd get with a call to the C runtime fopen() function; rather, it's a handle to a binary file. The application framework uses this file handle for Win32 ReadFile(), WriteFile(), and SetFilePointer() calls.

If your application does no direct disk I/O but instead relies on the serialization process, you can avoid direct use of CFile objects. Between the Serialize() function and the CFile object is an archive object of class CArchive, as shown in Figure 1.

The CArchive object buffers data for the CFile object, and it maintains an internal flag that indicates whether the archive is storing (writing to disk) or loading (reading from disk). Only one active archive is associated with a file at any one time. The application framework takes care of constructing the CFile and CArchive objects, opening the disk file for the CFile object and associating the archive object with the file. All you have to do (in your Serialize() function) is load data from or store data in the archive object. The application framework calls the document's Serialize() function during the File Open and File Save processes. 




Reading and Writing Documents—SDI Applications
Figure 1: The serialization process.

A serializable class must be derived directly or indirectly from CObject. In addition (with some exceptions), the class declaration must contain the DECLARE_SERIAL macro call, and the class implementation file must contain the IMPLEMENT_SERIAL macro call. See the Microsoft Foundation Class Reference for a description of these macros. This module's CStudent class example is modified from the class in Module 10 to include these macros. 

Reading and Writing Documents—SDI Applications
Writing a Serialize Function

In Module 10, you saw a CStudent class, derived from CObject, with these data members:

public:
CString m_strName;
int m_nGrade;

Now, your job is to write a Serialize() member function for CStudent. Because Serialize() is a virtual member function of class CObject, you must be sure that the return value and parameter types match the CObject declaration. The Serialize() function for the CStudent class is below.

void CStudent::Serialize(CArchive& ar)
{
TRACE("Entering CStudent::Serialize\n");
    if (ar.IsStoring())
      {
         ar << m_strName << m_nGrade;
       }
else 
Reading and Writing Documents—SDI Applications
     {
        ar >> m_strName >> m_nGrade;
     }


Reading and Writing Documents—SDI Applications
Most serialization functions call the Serialize() functions of their base classes. If CStudent were derived from CPerson, for example, the first line of the Serialize() function would be:

CPerson::Serialize(ar);

The Serialize() function for CObject (and for CDocument, which doesn't override it) doesn't do anything useful, so there's no need to call it. Notice that ar is a CArchive reference parameter that identifies the application's archive object. The CArchive::IsStoring member function tells us whether the archive is currently being used for storing or loading. The CArchive class has overloaded insertion operators (<<) and extraction operators (>>) for many of the C++ built-in types, as shown in the following table.


Reading and Writing Documents—SDI Applications
Type
Description
BYTE
8 bits, unsigned
WORD
16 bits, unsigned
LONG
32 bits, signed
DWORD
32 bits, unsigned
float
32 bits
double
64 bits, IEEE standard
int
32 bits, signed
short
16 bits, signed
char
8 bits, unsigned
unsigned
32 bits, unsigned
Table 1
 


Reading and Writing Documents—SDI Applications
The insertion operators are overloaded for values; the extraction operators are overloaded for references. Sometimes you must use a cast to satisfy the compiler. Suppose you have a data member m_nType that is an enumerated type. Here's the code you would use:

ar << (int) m_nType;
ar >> (int&) m_nType;

MFC classes that are not derived from CObject, such as CString and CRect, have their own overloaded insertion and extraction operators for CArchive.



Reading and Writing Documents—SDI Applications




No comments:

Post a Comment

Note: Only a member of this blog may post a comment.