如何将STL结合到MFC (一)
汤 浩
1.1 STL连续容器的序列化
如何将STL方便的在MFC中利用起来, 的确是VC++程序员无法回避的问题, 我将结合自己实际工作中的一些做法和编程心得, 写出一个系列出来, 希望和大家好好交流和讨论.
第一回我想探讨一下怎样将MFC的序列化功能利用到STL容器上, 也就是当STL容器作为类的成员如何将其序列化的问题.
1.1.1 MFC的做法
我们知道MFC自己本身带有CARRAY, CLIST以及CMAP三个容器, 他们的父类都是COBJECT并且又都实现了void Serialize(CArchive & ar) 方法, 所以当这些容器作为类的成员变量时, 非常容易序列化例如当我们声明如下的成员时:
CArray<int,int> m_aInt;
CList<int, int> m_lInt;
CMap<int, int, int, int> m_mInt;
序列化函数如下:
void CExampleDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
}
else
{
}
m_aInt.Serialize(ar);
m_lInt.Serialize(ar);
m_mInt.Serialize(ar);
}
可是当我们STL容器作为成员变量也需要被序列化时, 我们可以怎样做了?
1.1.2 序列化一般的做法
我们知道STL容器分成连续的和非连续的两种. 非连续容器中插入对象的位置和对象的值相关, 所以应该单独来处理. 那么就先来谈谈连续容器的序列化.他们包括vector deque 以及list等.
其实序列化是一个相当简单的操作. 如果我们申明了一个成员如下:
std::vector<int> m_vInt;
那么我们可以这样序列化它
void CExampleDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_vInt.size();
for( vector<int>::iterator it = m_vInt.begin()
; it != m_vInt.end()
; ++it ) {
ar << *it;
}
}
else
{
long nSize;
ar >> nSize;
m_vInt.resize(nSize);
for( vector<int>::iterator it = m_vInt.begin()
; it != m_vInt.end()
; ++it ) {
ar >> *it;
}
}
}
1.1.3 可以引入函数对象的做法
可以看到这样针对每个容器对象中的每一个ITEM去做序列化的工作的确比较麻烦.
所以我们可以这样做首先定义一个函数对象:
template<class T> struct MySerialize
: public std::unary_function<T,void>
{
MySerialize(CArchive & ar) : m_ar(ar) { }
void operator() ( T & info)
{
if (m_ar.IsStoring())
{
m_ar << info;
}
else
{
m_ar >> info;
}
}
CArchive & m_ar;
};
然后在序列化时就可以这样用了:
void CExampleDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_vInt.size();
}
else
{
long nSize;
ar >> nSize;
m_vInt.resize(nSize);
}
for_each(m_vInt.begin(),m_vInt.end(), MySerialize< int>(ar));
}
1.1.4 所有的工作一次完成的做法
但是, 这样还是存在着一部分游离的代码, 去处理容器大小的问题.
如何把那部分代码也结合进来呢? 其实, 可以再加入一个模版函数, 如下所示.
template<class TYPE, class CONTAINER_TYPE>
void ContainerSerialize(CArchive & ar, CONTAINER_TYPE & con , TYPE tmp)
{
if (ar.IsStoring())
{
ar << con.size();
}
else
{
long nSize;
ar >> nSize;
con.resize(nSize);
}
for_each(con.begin(), con.end(), MySerialize<TYPE>(ar));
};
那么我们的序列化代码就可以这样写了:
void CExampleDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
}
else
{
}
ContainerSerialize(ar, m_vInt, int());
}
好,在下一回里我将说明非连续容器的序列化方法.