Download demo project - 25 Kb Download source - 3 Kb
Introduction
The methods in the MFC classes CObject
and CArchive
provide a framework for serialization but give no help when one has to serialize
complex data structures containing cyclic references.
The functions GenericSerialize
and GenericDeserialize
presented
in this article implement a general serialization algorithm. These
C++ template functions can handle any homogenous datastructure (datastructure consisting of
nodes having all the same type).
The user has to provide a so called Accessor class which is responsible for
- defining a typedef name called
Type
which gives the type of a node pointer.
- providing a member variable called
ar
which must be a reference
to an archive object.
- providing a member function
Null()
which returns the null value for Type
- serializing and deserializing a single element.
- returning the immediate neighbors of an element.
Interface
template<class Access>
void GenericSerialize(const Access& a);
template<class Access>
void GenericDeserialize(const Access& a);
struct MyAccess
{
typedef MyPointerType Type;
CArchive ar;
Type Null()
{}
void GetNeighbors(Type current,vector< pair<Type,int> >& vecNeighbors)
const
{ }
void SerializeThis(Type owner,Type current,int nTyp)const
{ }
void SetReference(Type owner,Type current,int nTyp)const
{ }
};
Example A - Serialization of a tree view control
The demo project serializes a tree view control by a call to
the following function.
void CGenericSerializeDemoView::TreeSerialize(CArchive& ar)
{
TreeAccess access(m_Tree,ar);
if (ar.IsStoring())
{
GenericSerialize(access);
}
else
{
m_Tree.DeleteAllItems();
GenericDeserialize(access);
ApplyItemStates(m_Tree.GetRootItem());
}
}
The following Accessor class is the user provided part for the serialization of a tree view control.
struct TreeAccess{
TreeAccess(CTreeCtrl& rTree,CArchive& rAr):tree(rTree),ar(rAr){}
typedef HTREEITEM Type;
#define TA_eRoot 0
#define TA_eChild 1
#define TA_eSibling 2
CTreeCtrl& tree;
CArchive& ar;
HTREEITEM Null()const {return NULL;}
void GetNeighbors(HTREEITEM current,vector< pair<Type,int> >& vecNeighbors)
const
{
if(current==NULL){
HTREEITEM hItem= tree.GetRootItem();
if(hItem){
vecNeighbors.push_back( make_pair(hItem,TA_eRoot));
}
}else{
HTREEITEM hItem= tree.GetNextSiblingItem(current);
if(hItem){
vecNeighbors.push_back(make_pair(hItem,TA_eSibling));
}
hItem= tree.GetChildItem(current);
if(hItem){
vecNeighbors.push_back(make_pair(hItem,TA_eChild));
}
}
}
void SerializeThis(HTREEITEM owner,HTREEITEM current,int nTyp)const
{
ar << tree.GetItemText(current);
ar << tree.GetItemState(current,TVIF_STATE);
}
HTREEITEM DeserializeThis(HTREEITEM owner,int nTyp)const
{
CString strItemText;
UINT nState;
ar >> strItemText;
ar >> nState;
HTREEITEM hItem;
switch(nTyp){
case TA_eRoot: hItem= tree.InsertItem(strItemText); break;
case TA_eChild: hItem= tree.InsertItem(strItemText,owner); break;
case TA_eSibling: hItem= tree.InsertItem(strItemText,
tree.GetParentItem(owner),owner); break;
}
tree.SetItemData(hItem,nState);
return hItem;
}
void SetReference(HTREEITEM owner,HTREEITEM current,int nTyp)const
{
}
};
Example B - Serialization of a general graph
The following Accessor class is the user provided part
for the serialization of a Graph consisting of nodes having the following definition
struct Graph{
Graph(int x=0,int y=0):x(x),y(y){}
int x,y;
vector<Graph*> vecConnections;
};
struct GraphAccess{
GraphAccess(vectorGraph& rGraph,CArchive& rAr):graph(rGraph),ar(rAr){}
typedef Graph* Type;
vectorGraph& graph;
CArchive& ar;
#define GA_eRoot 0
#define GA_eConnect 1
Graph* Null()const {return 0;}
void GetNeighbors(Graph* current,vector< pair<Type,int> >& vecNeighbors)const
{
if(current==NULL){
for(unsigned i=0;i<graph.size();i++){
vecNeighbors.push_back( make_pair(graph[i],GA_eRoot));
}
}else{
for(unsigned i=0;i<current->vecConnections.size();i++){
vecNeighbors.push_back( make_pair(graph[i],GA_eConnect));
}
}
}
void SerializeThis(Graph* owner,Graph* current,int nTyp)const
{
ar << current->x;
ar << current->y;
}
Graph* DeserializeThis(Graph* owner,int nTyp)const
{
int x,y;
ar >> x;
ar >> y;
graph.push_back(new Graph(x,y));
return graph[graph.size()-1];
}
void SetReference(Graph* owner,Graph* current,int nTyp)const
{
if(owner!=0 && nTyp==GA_eConnect){
owner->vecConnections.push_back(current);
}
}
};
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.