⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 13.4.4 利用 cobarray类对串行化的支持保存和加载数据.txt

📁 网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读
💻 TXT
字号:
13.4.4 利用 CObArray类对串行化的支持保存和加载数据 
CObArray类结合了 IMPLEMENT_SERIAL宏支持串行化,转储该集合类中的元素。也就是说, CObArray
这个类本身也支持串行化。下面就利用 CObArray类对串行化的支持,保存该数组中所有元素。
由于 CObArray类支持串行化,该类也应该有一个 Seria lize函数。 CGraphicDoc对象的 Serialize
函数是由框架调用的,在这个函数中,我们可以直接它的参数 ar C CArc hi ve类型〉传递给 CObArray
对象的 Serialize函数 (添加代码如例 13-24中加灰显示的那行代码所示)。注意,一定要把这句代
码调用放到 if/else ì语句的外面。
说明:首先请读者将 CGraphicDoc类的 Serialize函数中 if/else语句块内先
前添加的代码都注释起来。
例 13-24 
void CGraphicDoc : : Serialize(CArchive& ar) 

POSITION pos=GetFirstviewposition() ; 
CGraphicView * pView=(CGraphicView*)Get N extView(pos) ; 

if  (ar . I sStoring())  
{  
// TODO :  add storing code here  

else 

// TODO : add l oading code here pVieW->ffi_ obArray . Serialize(ar) ; 
运行 Graphic程序,首先选择相应菜单绘制一些图形,接着单击【文件\保存】菜单命令,并选择一
个保存目标文件。之后关闭程序。然后再次运行程序,单击【文件\打开】菜单命令,并选择同一个
文件打开,然后在程序窗口中就可以看到刚才绘制的图形了。
下面让我们看看 MFC的源代码,了解 CObArray类实现串行化的过程。 CObArray类的 Serialize函
数的实现位于 ARRAY_O.CPP文件中,源代码如例 13-25所示。 
19IJ 13-25 

// Seriali zation 
void CObArray : : Serialize(CArchive& ar) 
ASSERT VALID(this) : 
CObject::Serialize(ar); 
if (ar.IsStoring ( ) ) 
ar.WriteCount(m_nSize) ; 
for (int i = 0; i < m_nSize; i++) 
ar << m_pData[i]; 
else 
DWORD nOldSize = ar.ReadCount(); 
SetSize(nOldSize); 
for (int i = 0; i < m_nSize; i++) 

ar >>m_pData[i]; 
在上述例 13-25所示 CObArray类的 Serialize函数中,首先调用基类 (CObject)的 Serialize函
数,接着判断参数 CArchive对象的状态,如果是保存数据,则调用 WriteCount函数。在浏览程序
代码时,如果编码比较规范的话,对有些函数,就不用去看它是如何实现的,根据其名称大概就能
猜测到它的功能。像 WriteCount这个函数,我们一看就知道它是将数组中元素的数目写入到文件中。
接下来, CObArray类的 Serialize函数利用一个 for循环将数组中所有元素依次写入到文件中。可
以看到,这个 Serialize函数的这种调用与我们上面第一次编写的代码很类似,也是先将数组中的
元素个数写入文件,接着利用一个 for循环,依次取出数组中每一个元素,然后将它们写入文件。
同样地,当加载时,首先读取写入到文件中的元素数目,然后利用 for循环依次加载数组中每一个
元素。当然,对于每一个数组元素所代表的对象来说,本例是 CGraph类型的对象,它也会去调用 
CGraph类的 Serialize函数。读者可以自己在 CObArray类的 Serialize函数处设置一个断点,然后
调试运行程序,看看其调用过程。
既然文档类是用来保存数据的,那么可以将 CObArray数组定义放到文档类中。对本例来说,也就是
为 CGraphicDoc添加 CObArray类型的成员变量: m_obArray,并将其访问权限设置为 public类型。
然后将程序中调用 CGraphicView类 m_obArray对象的地方都修改为调用 CGraphicDoc类的 
m_obArray对象。这时就需要在 CGraphicView类中访问 CGraphicDoc类的成员,因此首先就要得到
文档类的指针。我们可以看到 CGraphicView类中有一个 GetDocument函数,其实现代码如例 13-26
所示。
例 13-26 

CGraphicDoC* CGraphicView::GetDocurnent() // non-debug version is inline 

ASSERT(rn-pDocurnent->IsKindOf(RUNTIME_CLASS(CGraphicDoC))) ; 
return (CGraphicDoc*)rn-pDocurnent; 
可以看到, CGraphicView类GetDocument函数的返回值就是CGraphicDoc类的指针,也就是说,视类
中已经为我们准备好了可以获得文档类指针的函数,可以直接获得指向文档类对象的指针。这就是
MFC为我们提供的文档/框架/视类结构,它将这几个类对象之间互相调用的机制都设计好了,我们只
需要遵照该机制进行调用,获得相应对象的指针即可。所以,在 CGraphicView类的函数中需要访问
文档类对象的成员时,可以直接定义一个 CGraphicDoc类型的指针,接着调用GetDocument函数,就
可以得到指向文档类对象的指针,然后利用这个指针就可以访问文档对象内部的成员了。于是,我
们修改上述例 13-21所示CGraphicView类OnLButtonUp函数的代码,将先前调用集合类对象的Add方
法的语句 (即①符号所在语句)注释起来,然后在其后添加下述语句: 
CGraphicDoc食pDoc=GetDocument() ; 
pDoc->~obArray.Add(pGraph); 

在 CGraphicView类的 OnDraw函数中也要进行相应修改,我们可以回头看看上面例 13-23列出的 
OnDraw函数的代码,可以看到, OnDraw函数中已经调用了 GetDocument函数得到文档类对象的指针。
前面的章节己经提过,在文档/视类结构中,文档是用来保存数据和加载数据的。而在窗口绘制时,
应用程序框架将调用OnDraw函数,并且认为数据应当是从文档类对象中获取到的,于是就自动添加
了获取文挡类对象指针的调用,之后就可以利用该文档类对象指针获取文档类对象的数据,然后在
视类窗口中显示这些数据。所以,我们就可以这样修改OnDraw函数的代码,将先前调用 CGraphicView
类m_obArray对象的地方均换成调用CGraphicDoc类的ffi_obArray对象,即修改后的OnDraw函数代码
如例 13-27所示。
例13-27 

void CGraph工cView: : OnDraw(CDC* pDC) 
CGraphicDoc* pDoc = GetDocument() ; 
ASSERT_VALID(pDoc) ; 
// TODO: add draw code for native data here 

/ * 	CFont *pOldFont=pDC->SelectObject(&m_font) ; pDC->TextOut(O , O, m_ strFontName) ; 
pDC->SelectObject(pOldFont) ; 
食/ 
int 	nCount ; 
// 	nCount=m_obArray .GetSize() ; nCount=pDoc->m_obArray .GetSize() ; for( i nt i=O ; 
i<nCount ;工++) 
// 	( (CGraph*)m_obArray .GetAt(工))一>Draw (pDC) ; 
((CGraph*)pDoc->m_obArray.GetAt(i) )->Draw(pDC) ; 
~~~ 1517 


第13

然后在上述例 13-24所示CGraphicDoc类的Serialize函数中,将先前我们自己添加的代码(即加灰显
示的那行代码〉注释起来。因为现在m_obArray变量就是CGraphicDoc类的成员变量,所以可以直接
使用。添加下面如例 13-28所示加灰显示的这条语句。
例 13-28 

void CGraphicDoc : :Serialize(CArchive& ar) POSITION pos=GetFirstViewPosition(); 
CGraphicView *pView=(CGraphicView*)GetNextView(pos) ; if (ar . IsStoring()) / / TODO : add 
storing code here else // TODO : add loading code here //pView->m_obArray .Serialize(ar) ; 
m_obArray.Serialize(ar) ; 
运行Graphic程序,绘制一些图形,然后保存。接着打开菜单项,选择同一个文件,可以看到先前绘
制的内容在窗口中显示出来了。
飞令·细iR眉让我们再回顾一下 DocumentJView结构: 
( 1 )在 MFC中,文档类负责管理数据,提供保存和加载数据的功能。视类负责数据的显示,以及给
用户提供对数据的编辑和修改功能。 
(2) MFC给我们提供 DocumentJView结构,将一个应用程序所需要的"数据处理与显示"的函数空壳都
设计好了,这些函数都是虚函数,我们可以在派生类中重写这些函数。有关文件读写的操作在
CDocument的 Serialize函数中进行,有关数据和图形显示的操作在CView的OnDraw函数中进行。我
们在其派生类中,只需要去关注Serialize和 OnDraw函数就可以了,其他的细节,我们不需要去理
会,程序就可以良好地运行。 

(3)
在单击"文件\打开"菜单命令后,应用程序框架会激活"文件打开"对话框,让用户指定将要打开的文
件名,然后程序自动调用 CGraprucDoc类的 Seria1ize函数读取该文件。应用程序框架还会调用
CGraphicView类的OnDraw函数,传递一个显示DC,以便重新绘制窗口内容。 

(4) MFC提供 DocumentJView结构,是希望程序员将精力放在数据结构的设计和数据显示的操作上,
而不要把时间和精力花费在对象与对象之间、模块与模块之间的通信上。 


( 5 )一个文档对象可以与多个视类对象相关联,而一个视类对象只能与一个文档对象相关联。
518 I份'静,



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -