串行化的应用

串行化是什么?我们在编程中常常遇到这类问题,如何将对象保存到永久存储介质上(一般是硬盘),当程序下一次启动时在从永久存储介质上读取该对象。一般,要整个存储对象是不可能的,也没有必要,因为一个对象不仅有成员变量,也有成员方法,那我们要如何做到这一点,这就是这篇文章所讲的技术——串行化!

串行化是将对象的所有特征保存起来,以便下次读取该特征时可以将该对象还原出来。

一个对象要串行化,对应的类必须支持可串行化,支持可串行化的类必须有5个要求:(假设我们创建了CGraph类)
1.该类必须从CObject类继承;
2.重载Serialize(CArchive& ar)函数;
3.在类的声明处使用DECLARE_SERIAL(CGraph)声明该类可串行化;
4.定义一个不带参数的构造函数;
5.在源文件中使用IMPLEMENT_SERIAL(CGraph,CObject,1)实现该类可串行化;(1代表了版本号,写入对象和读取对象的版本号必须一致)

下面以一个实例讲解:
1.新建单文档工程,命名为Serialize;
2.在工程中添加新类CGraph,其基类为CObject,如下
class CGraph : public CObject                         //1.从CObject继承
{
public:
DECLARE_SERIAL(CGraph)                          //3.声明可串行化
CGraph();                                                       //4.一个不带参数的构造函数,下面会介绍其用处
CGraph(CPoint OriginPoint,CPoint NewPoint,int GraphType);
void Serialize(CArchive& ar);                          //2.重载Serialize函数
virtual ~CGraph();
private:
CPoint OriginPoint;
CPoint NewPoint;
int GraphType;
public:
void OnDraw(CDC* pDC);
};
在该类的源文件中加入
IMPLEMENT_SERIAL(CGraph,CObject,1)      //5.实现该类可串行化
3.在CGraph类中的带参数的构造函数中加入:
//OriginPoint,NewPoint,GraphType都是要存储和使用的成员变量
CGraph::CGraph(CPoint OriginPoint,CPoint NewPoint,int GraphType)
{
this->OriginPoint=OriginPoint;
this->NewPoint=NewPoint;
this->GraphType=GraphType;
}
在Serialize()中加入:
void CGraph::Serialize(CArchive& ar)
{
if(ar.IsStoring())
{
   ar<<OriginPoint<<NewPoint<<GraphType;//存储成员变量
}
else
{
   ar>>OriginPoint>>NewPoint>>GraphType;//打开成员变量
}
}
在自定义函数OnDraw()中加入:
//在视图类中以一定格式显示数据
void CGraph::OnDraw(CDC* pDC)
{
switch(GraphType)
{
case 1:
   pDC->MoveTo(OriginPoint);
   pDC->LineTo(NewPoint);
   break;
case 2:
   pDC->Rectangle(CRect(OriginPoint,NewPoint));
   break;
default:
   break;
}
}
4.在CSerializeView类中处理直线和矩形的绘制和显示:
void CSerializeView::OnLButtonDown(UINT nFlags, CPoint point)
{
// 记录鼠标的起点
OriginPoint=point;
CView::OnLButtonDown(nFlags, point);
}

void CSerializeView::OnLButtonUp(UINT nFlags, CPoint point)
{
// 鼠标释放时处理两点间的图形
CClientDC dc(this);
CBrush* pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//透明画刷
CBrush* pOldBrush=dc.SelectObject(pBrush);
switch(GraphType)
{
case 1:
   dc.MoveTo(OriginPoint);
   dc.LineTo(point);
   break;
case 2:
   dc.Rectangle(CRect(OriginPoint,point));
   break;
default:
   break;
}

CSerializeDoc* pDoc = GetDocument();//得到文档指针,所有数据存在文档的m_ObArray中
//必须在堆中建立数据,或其他长久保持数据的方法
CGraph* pGraph=new CGraph(OriginPoint,point,GraphType);
pDoc->m_ObArray.Add(pGraph);

dc.SelectObject(pOldBrush);
CView::OnLButtonUp(nFlags, point);
}

void CSerializeView::OnLine()
{
// 直线菜单命令
GraphType=1;
}

void CSerializeView::OnRentangle()
{
// 矩形菜单命令
GraphType=2;
}
在该类的OnDraw()函数中加入:
void CSerializeView::OnDraw(CDC* pDC)
{
CSerializeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
   return;

CBrush* pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
CBrush* pOldBrush=pDC->SelectObject(pBrush);
for(int i=0;i<pDoc->m_ObArray.GetSize();i++)
   ((CGraph*)pDoc->m_ObArray.GetAt(i))->OnDraw(pDC);//调用CGraph类的显示函数
pDC->SelectObject(pOldBrush);
// TODO: 在此处为本机数据添加绘制代码
}
5,最后在CSerializeDoc类中的Serialize()加入:
void CSerializeDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
   int len=m_ObArray.GetSize();
   ar<<len;
   for(int i=0;i<len;i++)
    ar<<m_ObArray.GetAt(i);//存储CGraph对象,相当于调用CGraph::Serialize(CArchive& ar)的ar<<;
}
else
{
   m_ObArray.RemoveAll();
   int len;
   ar>>len;
   CGraph* pGraph;
   for(int i=0;i<len;i++)
   {//这里只定义指针,便可以接收对象数据,正是有不带参数的构造函数的功劳
    //在执行ar>>pGraph;时自动为批pGraph分配内存,每次都重新分配,便可以打开所有对象数据了
    ar>>pGraph;//打开CGraph对象,相当于调用CGraph::Serialize(CArchive& ar)的ar>>;
    m_ObArray.Add(pGraph);
   }
}
}
其中m_ObArray是CObArray类变量,它和CPtrArray很相识。
这样,便可以完成存储和加载对象的功能了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值