友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
富士康小说网 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

深入浅出MFC第2版(PDF格式)-第28部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!



                    43 43 69 72 63 6C 65          ;〃CCircle〃 

                    55 00 66 00 77 00             ;CPoint & radius 



                    07 00                         ;class name string length 

                    43 53 74 72 6F 6B 65          ;〃CStroke〃 

                    02 00                         ;DWordArray size 

                    28 00 35 00                   ;point 

                    28 00 35 00                   ;point 



                    0A 00                         ;class name string length 

                    43 52 65 63 74 61 6E 67 6C 65 ;〃CRectangle〃 

                    11 00 22 00 33 00 44 00       ;CRect 



                    07 00                          ;class name string length 

                    43 43 69 72 63 6C 65           ;〃CCircle〃 

                    55 00 66 00 77 00              ;CPoint & radius 



                   还算堪用。但如果考虑到屏幕卷动的问题,以及打印输出的问题,应该在最前端增加「文 



                   件大小」。另外,如果这份文件有100 条线条,50 个圆形,80 个矩形,难不成我们要记 



                   录230 个类别名称?应该有更好的方法才是。 



162 


…………………………………………………………Page 225……………………………………………………………

                                 第3章    MFC 六大關鍵技術之模擬 



      CObList m_graphList 

      CObList m_graphList 



     图3…3 一个串行,  内含三种基本图形: 线条、圆形、矩形。 



我们可以在每次记录对象内容的时候,先写入一个代码,表示此对象之类别是否曾在档 



案中记录过了。如果是新类别,乖乖地记录其类别名称;如果是旧类别,则以代码表示。 



这样可以节省文件大小以及程序用于解析的时间。啊,不要看到文件大小就想到硬盘很 



便宜,桌上的一切都将被带到网上,你得想想网络频宽这回事。 



还有一个问题。文件的「版本」如何控制?旧版程序读取新版文件,新版程序读取旧版 



文件,都可能出状况。为了防弊,最好把版本号码记录上去。最好是每个类别有自己的 



版本号码。 



下面是新的构想,也就是Serialization 的目标: 



                                                           163 


…………………………………………………………Page 226……………………………………………………………

                   第篇  勿在浮砂築高台 



                    20 03 84 03                 ;Document Size 

                    06 00                       ;CObList elements count 



                    FF FF                       ;new class tag 

                    02 00                       ;schema 

                    07 00                       ;class name string length 

                    43 53 74 72 6F 6B 65        ;〃CStroke〃 

                    02 00                       ;DWordArray size 

                    28 00 13 00                 ;point 

                    28 00 13 00                 ;point 



                    FF FF                           ;new class tag 

                    01 00                           ;schema 

                    0A 00                           ;class name string length 

                    43 52 65 63 74 61 6E 67 6C 65   ;〃CRectangle〃 

                    11 00 22 00 33 00 44 00         ;CRect 



                    FF FF                           ;new class tag 

                    01 00                           ;schema 

                    07 00                           ;class name string length 

                    43 43 69 72 63 6C 65            ;〃CCircle〃 

                    55 00 66 00 77 00               ;CPoint & radius 



                    01 80                           ;old class tag 

                    02 00                           ;DWordArray size 

                    28 00 35 00                     ;point 

                    28 00 35 00                     ;point 



                    03 80                           ;old class tag 

                    11 00 22 00 33 00 44 00         ;CRect 



                    05 80                           ;old class tag 

                    55 00 66 00 77 00               ;CPoint & radius 



                    我希望有一个专门负责Serialization 的函数,就叫作Serialize 好了。假设现在我的Document 



                    类别名称为CScribDoc,我希望有这么便利的程序方法(请仔细琢磨琢磨其便利性): 



                   void CScribDoc::Serialize(CArchive& ar) 

                   { 

                       if (ar。IsStoring()) 

                           ar 》 m_sizeDoc; 

                       m_graphList。Serialize(ar); 

                   } 



                   void CObList::Serialize(CArchive& ar) 

                   { 

                       if (ar。IsStoring()) { 



164 


…………………………………………………………Page 227……………………………………………………………

                                                     第3章    MFC 六大關鍵技術之模擬 



        ar pNext) 

            ar data; 

    } 

    else { 

        WORD nNewCount; 

        ar 》》 nNewCount; 

        while (nNewCount……) { 

            CObject* newData; 

            ar 》》 newData; 

            AddTail(newData); 

        } 

    } 

} 



void CStroke::Serialize(CArchive& ar) 

{ 

    m_ptArray。Serialize(ar); 

} 



void CDWordArray::Serialize(CArchive& ar) 

{ 

    if (ar。IsStoring()) { 

        ar  nOldSize; 

        for (int i = 0; i 《 m_nSize; i++) 

            ar 》》 m_pData'i'; 

    } 

} 



void CRectangle::Serialize(CArchive& ar) 

{ 

    if (ar。IsStoring()) 

        ar 》 m_rect; 

} 



void CCircle::Serialize(CArchive& ar) 

{ 

    if (ar。IsStoring()) { 



                                                                                          165 


…………………………………………………………Page 228……………………………………………………………

                    第篇  勿在浮砂築高台 



                            ar 》 (WORD&)m_center。y; 

                            ar 》》 (WORD&)m_radius; 

                        } 

                    } 



                 每一个可写到文件或可从文件中读出的类别,都应该有它自己的Serailize  函数,负责它 



                 自己的资料读写文件动作。此类别并且应该改写》 运算子,把资料导流到 



                 archive  中。archive 是什么?是一个与文件息息相关的缓冲区,暂时你可以想象它就是 



                 文件的化身。当图3…3 的文件写入文件时,Serialize  函数的调用次序如图3…4 。 



                                  CMyDoc::Serialize 



                                   CObList::Serialize 



                                      如果串行元素是圆 

                                                          CStroke::Serialize 



                                                                CDWordArray::Serialize 



                                      如果串行元素是矩形 

                                                         CRectangle::Serialize 



                                      如果串行元素是线条 

                                                         CCircle::Serialize 



                     图3…4 图3…3 的文件内容写入文件时,Serialize 函数的调用次序。 



166 


…………………………………………………………Page 229……………………………………………………………

                                                         第3章    MFC 六大關鍵技術之模擬 



DECLARE_SERIAL / IMPLEMENT_SERIAL 宏 



     要将》 两个运算子多载化,还要让Serialize  函数神不知鬼不觉地放入类别声明 



     之中,最好的作法仍然是使用宏。 



     类别之能够进行文件读写动作,前提是拥有动态生成的能力,所以,MFC 设计了两个宏 



     DECLARE_SERIAL 和IMPLEMENT_SERIAL : 



      #define DECLARE_SERIAL(class_name)  

              DECLARE_DYNCREATE(class_name)  

              friend CArchive& AFXAPI operator》》(CArchive& ar; class_name* &pOb); 



      #define IMPLEMENT_SERIAL(class_name; base_class_name; wSchema)  

              CObject* PASCAL class_name::CreateObject()  

                      { return new class_name; }  

              _IMPLEMENT_RUNTIMECLASS(class_name; base_class_name; wSchema;  

                      class_name::CreateObject)  

              CArchive& AFXAPI operator》》(CArchive& ar; class_name* &pOb)  

                    { pOb = (class_name*) ar。ReadObject(RUNTIME_CLASS(class_name));  

                              return ar; }  



      为了在每一个对象被处理(读或写)之前,能够处理琐屑的工作,诸如判断是否第一次 



      出现、记录版本号码、记录文件名等工作,CRuntimeClass 需要两个函数Load 和Store 

                                                                                    : 

      struct CRuntimeClass 

      { 

      // Attributes 

              LPCSTR m_lpszClassName; 

              int m_nObjectSize; 

              UINT m_wSchema; // schema number of the loaded class 

              CObject* (PASCAL* m_pfnCreateObject)(); // NULL =》 abstract class 

              CRuntimeClass* m_pBaseClass; 



              CObject* CreateObject(); 

              void Store(CArchive& ar) const; 

              static CRuntimeClass* PASCAL Load(CArchive& ar; UINT* pwSchemaNum); 



              // CRuntimeClass objects linked together in simple list 

              static CRuntimeClass* pFirstClass; // start of class list 

              CRuntimeClass* m_pNextClass;     // linked list of registered classes 

      }; 



                                                                                            167 


…………………………………………………………Page 230……………………………………………………………

                    第篇  勿在浮砂築高台 



                    你已经在上一节看过Load  函数,当时为了简化,我把它的参数拿掉,改为由屏幕上获 



                    得类别名称,事实上它应该是从文件中读一个类别名称。至于Store  函数,是把类别名 



                    称写入文件中: 



                    // Runtime class serialization code 

                    CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar; UINT* pwSchemaNum) 

                    { 

                        WORD nLen; 

                        char szClassName'64'; 

                        CRuntimeClass* pClass; 



                        ar 》》 (WORD&)(*pwSchemaNum) 》》 nLen; 



                        if (nLen 》= sizeof(szClassName) || ar。Read(szClassName; nLen) != nLen) 

                                return NULL; 

                        szClassName'nLen' = '0'; 



                        for (pClass = pFirstClass; pClass != NULL; pClass = pClass…》m_pNextClass) 

                        { 

                            if (lstrcmp(szClassName; pClass…》m_lpszClassName) == 0) 

                                return pClass; 

                        } 

                        return NULL; // not found 

                    } 



                    void CRuntimeClass::Store(CArchive& ar) const 

                            // stores a runtime class description 

                    { 

                            WORD nLen = (WORD)lstrlenA(m_lpszClassName); 

                            ar 
返回目录 上一页 下一页 回到顶部 9 10
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!