前两节模拟实现了MFC的运行时类识别与动态创建,就是为了这节做工作的。因为我们的目的就是把对象中的数据转化成字符串,前提是我们对对象的结构是未知的,通过一种通用的方式方便快捷无重复的实现我们的想法。
首先简单介绍下MFC序列化。MFC把DECLARE_SERIAL与IMPLEMENT_SERIAL做为序列化初始化宏与实现宏。两个宏在动态创建基础上重写了>>运算符,通过调用虚函数Serialize(Carchive&ar)对成员变量进行读取及写入。如果我们像MFC序列化一样把自己成员也通过一个虚函数读取写入也是可以实现的。但是这样我们首先要写这个虚函数,而且要一遍写入一遍读取,无疑增加了很多重复性代码,我们目的就是尽量简化后续操作,尽可能通过宏来实现。这时联想到消息映射宏。
消息映射是通过一个map表把消息类型和对应消息指针一一对应。我们只需要把消息指针换成我们的成员变量地址就可以完成映射工作。下面就列出代码:
#define DECLARE_MEMBER_MAP() TDDECLARE_DYNCREATE()\
public:\
AFX_MEMBERMAP* GetMeberMap();
为了减少操作我们把消息映射与动态创建宏合并成DECLARE_MEMBER_MAP()做为初始化宏。
#define BEGIN_MEMBER_MAP(class_name) TDIMPLEMENT_DYNCREATE(class_name)\
AFX_MEMBERMAP* class_name::GetMeberMap()\
{ \
AFX_MEMBERMAP memberEntries[] = \
{
#define END_MEMBER_MAP() \
{"",NULL}\
}; \
int loop = 0;\
while(true)\
{\
if(memberEntries[loop].name==VARIANT(_variant_t("")))break;\
loop++;\
}\
AFX_MEMBERMAP* memberEntrie = newAFX_MEMBERMAP[loop+1];\
for(inti=0;i<loop+1;i++){memberEntrie[i].name=memberEntries[i].name;\
memberEntrie[i].address=memberEntries[i].address;}\
return memberEntrie; \
}
上面代码等同于消息映射的BEGIN_MESSAGE_MAP与END_MESSAGE_MAP用于实现GetMeberMap函数。{"",NULL}做为结尾的标示。
#define INSERT_MEMBER(member_name)\
private:\
_variant_t member_name;\
public:\
_variant_t get_##member_name(){returnmember_name;}\
void set_##member_name(_variant_tmember){member_name = member;}
上面几行对成员变量初始化,并实现set与get方法,_variant_t是ADO提供的泛型解决了不同类型传递造成的问题,为了方便后面数据库的操作我们使用ADO。
#define ON_MEMBER(member_name)\
{ #member_name,&member_name },
上面两行代码是添加成员变量名与其地址的映射。
最后只需要在我们基类实现增删改查操作即可(做为测试这里仅添加查询当前类的成员变量情况的函数show)。子类继承基类并在初始化是使用DECLARE_MEMBER_MAP()与所有INSERT_MEMBER(成员变量名),实现类中使用BEGIN_MEMBER_MAP(类名)、ON_MEMBER(成员变量名)与END_MEMBER_MAP()。
下面进行测试:
TDPerson类没有对show改写
TDCar类也没有对show改写
两个类都调用show函数
两个类都得到了各自的成员变量名称和对应的值。成功的将两个类进行序列化。这样我们就可以把类模型序列化成我们想要的字符串,就可以方便我们动态实现数据库操作了,对于大批量数据库操作而言我们是不是相当的便利,我们的目标也完成一半了。我们的目标既要实现类模型序列化,也要把信息提交到http服务器进行数据操作。当然目前还没完成数据库操作模版,下一章节我们就来实现这个期待已久的模版。
源码下载 http://download.csdn.net/detail/u011736517/9761659