如何将STL结合到MFC (一)

    技术2022-05-11  112

    如何将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());

    }

    ,在下一回里我将说明非连续容器的序列化方法.

     


    最新回复(0)