1. 程式人生 > >MFC CArchive Serialize 序列化類 設計和使用

MFC CArchive Serialize 序列化類 設計和使用

序列化的出發點在於,一個物件的當前狀態應該可以永久地儲存起來,這些當前狀態主要用它的成員變數來表示。然後,這個物件可以通過讀取檔案或者反序列化重新構造出來。序列化包含了處理所有物件指標細節以及在序列化物件過程中使用的物件的迴圈引用。序列化的一個關鍵點在於一個物件負責自己狀態的讀寫,因此,一個可序列化的類必須實現基本的序列化操作。就像在序列化系列文章中看到的,在一個類中加上序列化功能的過程是不復雜的。MFC把CArchive 類作為了要序列化物件與儲存介質之間的橋接者。CArchive 類物件總是與一個CFile物件聯絡在一起(CFile檔案可能是一個磁碟檔案也可能是一個記憶體檔案,也可能是一個剪貼簿檔案!

),從CFile物件中,CArchive 類物件可以獲得必要的序列化資訊,這其中包括儲存檔名和要進行的操作是讀還是寫。一個物件可以使用CArchive物件進行序列化操作,這個過程是儲存介質無關的。

一、設計一個可序列化類的五個步驟:
  1. 從CObject類派生出自己的類
  2. 過載Serialize()函式
  3. 在類的申明中使用DECLARE_SERIAL 巨集
  4. 定義一個無引數的建構函式(重建物件的時候要用)
  5. 在類的實現檔案中新增IMPLEMENT_SERIAL巨集
如果你直接使用Serialize()函式,並不使用CArchive的<<和>>操作符,就可以省去後面的3步。 一個例項
如下:一個CPerson類,有兩個資料成員
class CPerson : public CObject  1  
{
public:
    DECLARE_SERIAL( CPerson ) 3
    // empty constructor is necessary
    CPerson(){}; 4

    CString m_name;
    WORD   m_number;

    void Serialize( CArchive& archive ); 2
    
    // rest of class declaration
};
以下新增在.cpp檔案中
IMPLEMENT_SERIAL( CPerson, CObject, 1
) 5
void CPerson::Serialize( CArchive& archive )
{
    // call base class function first
    // base class is CObject in this case

    CObject::Serialize( archive );
    // now do the stuff for our specific class
    if( archive.IsStoring() )
        archive << m_name << m_number;
    else
        archive >> m_name >> m_number;
}
IMPLEMENT_SERIAL巨集中的前兩個引數很容易理解了,第三個引數是一個版本碼,當將資料讀到記憶體中的時候,系統會去檢查這個版本碼,如果磁碟和記憶體中的版本碼不同,系統就會丟擲一個CArchiveException異常,防止你的程式讀到不正確的物件資料版本。
備註:解決讀多個版本資料問題!!!
二、建立一個CArchive物件
建立一個CAchive物件有兩種方式:1.使用MFC的document/View框架中內的Serialize函式,這稱為隱式建立。2.顯示建立就是直接申明一個與CFile物件相關聯的物件。
    隱式方法就是直接使用框架中CMyDocument類的Serialize(),這裡要強調的是,如果CMyDocumen-t中有內嵌的類成員,那麼,這個類也應該是有序列化能力的,否則使用者要自己加上這個功能;怎麼建立一個可序列化的類在上面已經講的很清楚了!顯示建立的方法步驟如下:
    1.開啟一個另存為的對話方塊,獲取檔名稱
    2.申明一個CFile物件開啟這個檔案
    3.申明一個CArchive物件,關聯這個CFile物件
    4.呼叫Serialize()函式,將這個CArchive物件作為引數傳遞
說得很抽象,以下是一個具體的例子:
const char szFilter[] = "MIMA Files (*.cy)|*.cy|; *.cy||";        CFileDialog fileDlg(false,".cy","mmmanager",OFN_HIDEREADONLY|OFN_OVERWRITEP ROMPT,szFilter); 1        CString strFileName;        CFile file;        if(IDOK == fileDlg.DoModal())        {            strFileName = fileDlg.GetFileName();            file.Open(strFileName,CFile::modeCreate | CFile::modeWrite); 2            CArchive ar(&file,CArchive::store); 3            m_objMM.Serialize(ar); 4        }
第四步中要指出的是,這個Serialize()函式只要能在此呼叫就可以,不管是誰的。
一般的Serialize()函式模板長這個樣子:
void CPerson::Serialize(CArchive& ar)
{
    CObject::Serialize(ar);
    if (ar.IsStoring())
    {
        // TODO:  add storing code here
        ar<<....
    }
    else
    {
    // TODO:  add loading code here
        ar>>...
   }
}
三、序列化CObject物件
        <<和>>操作符只用於一些簡單的資料型別,要是序列化一個物件(或者物件的指標),就直接使用這個物件的Serialize()函式。