?? ch22.htm
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><HTML><HEAD> <META NAME="GENERATOR" Content="Symantec Visual Page Mac 1.1"> <TITLE>Teach Yourself Visual C++® 5 in 24 Hours -- Hour 22 -- Serialization</TITLE></HEAD><BODY TEXT="#000000" BGCOLOR="#FFFFFF"><H1 ALIGN="CENTER"><IMG SRC="../button/sams.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM"BORDER="0"><BR><FONT COLOR="#000077">Teach Yourself Visual C++® 5 in 24 Hours</FONT></H1><CENTER><P><A HREF="../ch21/ch21.htm"><IMG SRC="../button/previous.gif" WIDTH="128" HEIGHT="28"ALIGN="BOTTOM" ALT="Previous chapter" BORDER="0"></A><A HREF="../ch23/ch23.htm"><IMGSRC="../button/next.gif" WIDTH="128" HEIGHT="28" ALIGN="BOTTOM" ALT="Next chapter"BORDER="0"></A><A HREF="../index.htm"><IMG SRC="../button/contents.gif" WIDTH="128"HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A> <HR></CENTER><H1 ALIGN="CENTER"><FONT COLOR="#000077">- Hour 22 -<BR>Serialization</FONT></H1><P>Serialization is the method used by MFC programs to read and write applicationdata to files. In this hour, you will learn about<UL> <LI>Persistence and serialization <LI>Serialization support in commonly used MFC classes <LI>Macros and other MFC features that are used when implementing serialization</UL><P>You will also create an example that uses serialization in a Document/View application.<H2><FONT COLOR="#000077"><B>What Is Serialization?</B></FONT></H2><P><FONT COLOR="#000077"><B>New Term:</B></FONT><B> </B><I>Serialization</I> is theprocess of storing the state of an object for the purpose of loading it at anothertime.</P><P><FONT COLOR="#000077"><B>New Term:</B></FONT><B> </B>The property of an objectto be stored and loaded is <I>persistence</I>, which is also defined as the capabilityof an object to remember its state between executions.</P><P>Serialization is the way in which classes derived from <TT>CDocument</TT> storeand retrieve data from an archive, which is usually a file. Figure 22.1 shows theinteraction between a serialized object and an archive.</P><P><A NAME="01"></A><A HREF="01.htm"><B>Figure 22.1.</B></A> <I><BR>Serializing an object to and from an archive.</I></P><P>When an object is serialized, information about the type of object is writtento the storage along with information and data about the object. When an object isdeserialized, the same process happens in reverse, and the object is loaded and createdfrom the input stream.<H2><FONT COLOR="#000077"><B>Why Use Serialization?</B></FONT></H2><P>The goal behind serialization is to make the storage of complex objects as simpleand reliable as the storage of the basic data types available in C++. You can storea basic type, such as an <TT>int</TT>, in a file in the following way:</P><PRE><FONT COLOR="#0066FF"><TT>int nFoo = 5;</TT><TT>fileStream << nFoo;</TT></FONT></PRE><P>If a file contains an <TT>int</TT> value, it can be read from the stream in thefollowing way:</P><PRE><FONT COLOR="#0066FF"><TT>fileStream >> nFoo;</TT></FONT></PRE><P>A persistent object can be serialized and deserialized using a similar syntax,no matter how complicated the object's internal structure. The alternative is tocreate routines that understand how every object is implemented and handle the processof storing and retrieving data from files.</P><P>Using serialization to store objects is much more flexible than writing specializedfunctions that store data in a fixed format. Objects that are persistent are capableof storing themselves, instead of relying on an external function to read and writethem to disk. This makes a persistent object much easier to reuse because the objectis more self-contained.</P><P>Persistent objects also help you easily write programs that are saved to storage.An object that is serialized might be made up of many smaller objects that are alsoserialized. Because individual objects are often stored in a collection, serializingthe collection also serializes all objects contained in the collection.<H2><FONT COLOR="#000077"><B>A Document/View Serialization Example</B></FONT></H2><P>Using AppWizard, create an MDI project named Customers. This project uses serializationto store a very simple list of customer names and email addresses, using a persistentclass named <TT>CUser</TT>. This project will serve as the basis for examples andsource code used in the remainder of this hour.<H3><FONT COLOR="#000077"><B>Serializing the Customers Project</B></FONT></H3><P>In Hour 1, "Introducing Visual C++ 5," you used the insertion operator,or <TT><<</TT>, to output a value to the screen. This operator is actuallythe C++ left-shift operator, but it is overloaded so that whenever an output objectand variable are separated by a <TT><<</TT>, as in the following code line,the variable is written to the output object:</P><PRE><FONT COLOR="#0066FF"><TT>file_object << data</TT></FONT></PRE><P>In a similar way, whenever input is performed and the objects are separated bya <TT>>></TT>, as in the following code line, a new value for the variableis retrieved from the input object:</P><PRE><FONT COLOR="#0066FF"><TT>file_object >> data</TT></FONT></PRE><P>In C++, unlike some other languages, input and output are controlled by the interactionbetween file and variable objects. The exact process used for input and output iscontrolled by the way in which the classes implement the <TT>>></TT> and <TT><<</TT>operators.</P><P>For the topics in this hour, you create a persistent class named <TT>CUser</TT>,along with the helper functions required to serialize a collection of <TT>CUser</TT>objects. Each <TT>CUser</TT> object contains a customer name and email address.<H3><FONT COLOR="#000077"><B>The MFC Classes Used for Serialization</B></FONT></H3><P>You use two MFC classes to serialize objects:<UL> <LI><TT>CArchive</TT> is almost always a file and is the object that other persistent objects are serialized to or from.<BR> <BR> <LI><TT>CObject</TT> defines all the interfaces used to serialize objects to or from a <TT>CArchive</TT> object.</UL><P>Objects are serialized in one of two ways. As a rule of thumb, if an object isderived from <TT>CObject</TT>, that object's <TT>Serialize</TT> member function iscalled in the following way:</P><PRE><FONT COLOR="#0066FF"><TT>myObject.Serialize( ar );</TT></FONT></PRE><P>If the object isn't derived from <TT>CObject</TT>--such as a <TT>CRect</TT> object--youshould use the inser-tion operator in the following way:</P><PRE><FONT COLOR="#0066FF"><TT>ar << rcWnd;</TT></FONT></PRE><P>This insertion operator is overloaded in the same way it is for <TT>cout</TT>,<TT>cin</TT>, and <TT>cerr</TT>, which were used in the first two hours for consolemode input and output.<H4><FONT COLOR="#000077">Using the CObject Class</FONT></H4><P>You must use the <TT>CObject</TT> class for all classes that use the MFC classlibrary's built-in support for serialization. The <TT>CObject</TT> class containsvirtual functions that are used during serialization. In addition, the <TT>CArchive</TT>class is declared as a "friend" class for <TT>CObject</TT>, providing itaccess to private and protected member variables.</P><P>The most commonly used virtual function in <TT>CObject</TT> is <TT>Serialize</TT>,which is called to serialize or deserialize the object from a <TT>CArchive</TT> object.This function is declared as virtual so that any persistent object can be calledthrough a pointer to <TT>CObject</TT> in the following way:</P><PRE><FONT COLOR="#0066FF"><TT>CObject* pObj = GetNextObject();</TT><TT>pObj->Serialize( ar );</TT></FONT></PRE><P>As discussed later in the section "Using the Serialization Macros,"when you're deriving a persistent class from <TT>CObject</TT>, you must use two macrosto help implement the serialization functions.<H4><FONT COLOR="#000077">The CArchive Class</FONT></H4><P>The <TT>CArchive</TT> class is used to model a generic storage object. In mostcases, a <TT>CArchive</TT> object is attached to a disk file. In some cases, however,the object might be connected to an object that only seems to be a file, like a memorylocation or another type of storage.</P><P>When a <TT>CArchive</TT> object is created, it is defined as used for either inputor output but never both. You can use the <TT>IsStoring</TT> and <TT>IsLoading</TT>functions to determine whether a <TT>CArchive</TT> object is used for input or output,as shown in Listing 22.1.<H4><FONT COLOR="#000077">TYPE: Listing 22.1. Using the CArchive::IsStoring functionto determine the serialization direction.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>CMyObject:Serialize( CArchive& ar )</TT><TT>{</TT><TT> if( ar.IsStoring() )</TT><TT> // Write object state to ar</TT><TT> else</TT><TT> // Read object state from ar</TT><TT>}</TT></FONT></PRE><H3><FONT COLOR="#000077"><B>Using the Insertion and Extraction Operators</B></FONT></H3><P>The MFC class library overloads the insertion and extraction operators for manycommonly used classes and basic types. You often use the insertion operator, <TT><<</TT>,to serialize--or store--data to the <TT>CArchive</TT> object. You use the extractionoperator, <TT>>></TT>, to deserialize--or load--data from a <TT>CArchive</TT>object.</P><P>These operators are defined for all basic C++ types, as well as a few commonlyused classes not derived from <TT>CObject</TT>, such as the <TT>CString</TT>, <TT>CRect</TT>,and <TT>CTime</TT> classes. The insertion and extraction operators return a referenceto a <TT>CArchive</TT> object, enabling them to be chained together in the followingway:</P><PRE><FONT COLOR="#0066FF"><TT>archive << m_nFoo << m_rcClient << m_szName;</TT></FONT></PRE><P>When used with classes that are derived from <TT>CObject</TT>, the insertion andextraction operators allocate the memory storage required to contain an object andthen call the object's <TT>Serialize</TT> member function. If you don't need to allocatestorage, you should call the <TT>Serialize</TT> member function directly.</P><P>As a rule of thumb, if you know the type of the object when it is deserialized,call the <TT>Serialize</TT> function directly. In addition, you must always call<TT>Serialize</TT> exclusively. If you use <TT>Serialize</TT> to load or store anobject, you must not use the insertion and extraction operators at any other timewith that object.<H3><FONT COLOR="#000077"><B>Using the Serialization Macros</B></FONT></H3><P>There are two macros that you must use when creating a persistent class basedon <TT>CObject</TT>. Use the <TT>DECLARE_SERIAL</TT> macro in the class declarationfile and the <TT>IMPLEMENT_SERIAL</TT> macro in the class implementation file.<H4><FONT COLOR="#000077">Declaring a Persistent Class</FONT></H4><P>The <TT>DECLARE_SERIAL</TT> macro takes a single parameter: the name of the classto be serialized. An example of a class that can be serialized is provided in Listing22.2. Save this source code in the Customers project directory in a file named <TT>Users.h</TT>.<BLOCKQUOTE> <P><HR><B> </B><FONT COLOR="#000077"><B>Time Saver:</B></FONT><B> </B>A good place to put the <TT>DECLARE_SERIAL</TT> macro is on the first line of the class declaration, where it serves as a reminder that the class can be serialized. <HR></BLOCKQUOTE><H4><FONT COLOR="#000077">TYPE: Listing 22.2. The CUser class declaration.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>#ifndef CUSER</TT><TT>#define CUSER</TT><TT>class CUser : public CObject</TT><TT>{</TT><TT> DECLARE_SERIAL(CUser);</TT><TT>public:</TT><TT> // Constructors</TT><TT> CUser();</TT><TT> CUser( const CString& szName, const CString& szAddr );</TT><TT> // Attributes</TT><TT> void Set( const CString& szName, const CString& szAddr );</TT><TT> CString GetName() const;</TT><TT> CString GetAddr() const;</TT><TT> // Operations</TT><TT> virtual void Serialize( CArchive& ar );</TT><TT> // Implementation</TT><TT>private:</TT><TT> // The user's name</TT><TT> CString m_szName;</TT><TT> // The user's e-mail addresss</TT><TT> CString m_szAddr;</TT><TT>};</TT><TT>#endif CUSER</TT></FONT></PRE><H4><FONT COLOR="#000077">Defining a Persistent Class</FONT></H4><P>The <TT>IMPLEMENT_SERIAL</TT> macro takes three parameters and is usually placedbefore any member functions are defined for a persistent class. The parameters for<TT>IMPLEMENT_SERIAL</TT> are the following:<UL> <LI>The class to be serialized <LI>The immediate base class of the class being serialized <LI>The schema, or version number</UL><P>The schema number is a version number for the class layout used when you're serializingand deserializing objects. If the schema number of the data being loaded doesn'tmatch the schema number of the object reading the file, the program throws an exception.The schema number should be incremented when changes are made that affect serialization,such as adding a class member or changing the serialization order.</P><P>The member functions for the <TT>CUser</TT> class, including the <TT>IMPLEMENT_SERIAL</TT>macro, are provided in Listing 22.3. Save this source code in the Customers projectdirectory as <TT>Users.cpp</TT>.<H4><FONT COLOR="#000077">TYPE: Listing 22.3. The CUser member functions.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>#include "stdafx.h"</TT><TT>#include "Users.h"</TT><TT>IMPLEMENT_SERIAL( CUser, CObject, 1 );</TT><TT>CUser::CUser() { }</TT><TT>CUser::CUser( const CString& szName, const CString& szAddr )</TT><TT>{</TT><TT> Set( szName, szAddr );</TT>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -