<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>
SW系统的根是SObject,顾名思义是对普遍意义上的对象的抽象。其主要的支持有:
- 运行时刻类信息(RuntimeClass)
运行时刻类信息是经典程序结构中一个极其重要的部分。MFC、VCL、OWL、TurboVision都支持运行时刻类信息。它可能也是经典Object类中唯一比较实用的东西。而同时它也是Object类最容易让人感到迷惑的地方。简单地说,运行时刻类信息主要有两个用途:
a)创建对象
b)确定对象的类型
其实RuntimeClass的实现机制一点也不神秘。它无非是通过类注册方式将类名与其父类、实例创建函数联系起来。
SW系统的运行时刻类信息定义为:
typedefSObject*(*FNBUILDER)();
structSRuntimeClass
{
LPCTSTRm_lpszClassName;//类名
SRuntimeClass*m_lpBaseClass;//父类
FNBUILDERm_fnCreator;//实例创建
SRuntimeClass*m_lpPrevClass;
};
每一个SW系统的类都对应有一个SRuntimeClass实例来描述该类。可以用__typeid(Class)来找到定位该类RuntimeClass信息。此宏与MFC的RUNTIME_CLASS(Class)宏完全相同。
注意到SRuntimeClass有一个成员m_lpPrevClass,它只是用于在系统维护RuntimeClass链表。从而可以让用户通过类的名字来查询一个类的运行时刻类信息,并且创建该类的对象。例如下面的序列化技术就需要这样做。
SW系统的运行时刻类信息相关函数和宏主要有:
__typeid(Class)//定位一个类的运行时刻类信息
DECLARE_CLASS(Class)//声明一个类
IMPLEMENT_CLASS(Class,BaseClass)//注册一个类
SObject* gCreateObject(LPCTSTRszClassName);
//根据一个类的类名,创建该类的一个实例
constSRuntimeClass* SObject::GetRuntimeClass()const;
//确定一个对象的RuntimeClass信息
BOOLSObject::IsKindOf(constSRuntimeClass*pRC)const;
//判断一个对象是否是pRC描述的类或者其派生类的实例
它们的实现代码相当简单,不详细解释:
#define__typeid(Class)(&Class::x_theRuntimeClass)
#defineDECLARE_CLASS(Class)
constSRuntimeClass*Class::GetRuntimeClass()const;
staticconstSRuntimeClassx_theRuntimeClass;
staticSObject*x_CreateObject();
#defineIMPLEMENT_CLASS(Class,BaseClass)
constSRuntimeClass*Class::GetRuntimeClass()const
{
return__typeid(Class);
}
constSRuntimeClassClass::x_theRuntimeClass(
_T(#Class),
__typeid(BaseClass),
Class::x_CreateObject
);
SObject*Class::x_CreateObject()
{
returnnewClass;
}
constSRuntimeClass*x_lpRuntimeClassListHead=NULL;
SRuntimeClass::SRuntimeClass(
LPCTSTRszClassName,
constSRuntimeClass*lpBaseClass,
FNBUILDERfnCreator)
{
m_szClassName=szClassName;
m_lpBaseClass=lpBaseClass;
m_fnCreator=fnCreator;
m_lpPrevClass=x_lpRuntimeClassListHead;
x_lpRuntimeClassListHead=this;
}
SObject*gCreateObject(LPCTSTRszClassName)
{
constSRuntimeClass*pRC=x_lpRuntimeClassListHead;
for(;pRC;pRC=pRC->m_lpPrevClass)
if(!_tcscmp(szClassName,pRC->m_szClassName))
returnpRC->fnCreateObject();
returnNULL;
}
BOOLSObject::IsKindOf(constSRuntimeClass*pBaseClass)const
{
SRuntimeClass*pRC=this->GetRuntimeClass();
for(;pRC;pRC=pRC->m_lpBaseClass)
if(pRC==pBaseClass)
returnTRUE;
returnFALSE;
}
- 序列化(Serialization)
序列化是建立在运行时刻类信息(RuntimeClass)之上的一个应用。所谓序列化是指通过一个自动化机制将对象保存到磁盘,或者将对象从磁盘读出来。尽管序列化有种种的缺点,但不得不承认它是对面相对象思想的一个经典运用。如果你的程序支持序列化,那么存盘的过程你唯一要做的就是,你对应用程序说,“存盘!”而后应用程序就可以将自己保存到磁盘上。你对应用程序说,“读盘!”而后应用程序就会从磁盘中读入数据重建对象。一切就这么简单!
但是序列化是有严重缺陷的。它没有在兼容性、容错性上的保证。所以它比较适合于保存不被推广的文件格式,例如程序配置,它们可能不必考虑兼容性问题。但在对用户数据的保存上,它应该只是一个理论上的成果。所以尽管Microsoft提供了序列化,但是他自己从来都不会使用序列化去保存数据文件。
SW系统的序列化实现上与MFC完全一致。但它是在当我还在还没有接触MFC时就已经实现的一个技术。这种一致性应该说是对面向对象思想把握的必然结果。但前提是你掌握了RuntimeClass(在实现RuntimeClass上,我主要借鉴了TurboVision中的实现方式。但是对其进行了大量的简化)。
面向对象的基础思想是,当你要一个对象做一件事时,你只要向它发送相应的消息,而不必关心对象如何完成此任务。同样地,在接收到用户的存盘消息后,你只是简单地向应用程序发送存盘消息。而应用程序在保存完私有数据后继续向其所有子对象发送存盘消息,这个过程一直延续到简单对象。从而完成存盘动作。当然,为了支持序列化,SObject类要加虚函数:
virtual Serialize(SArchive &ar);
其中SArchive类是流操作类。与C++的流操作类基本类似,但它是二进制流。
在实现序列化中,实现写盘是简单的:
HRESULT SArchive::WriteObject(SObject *pOb);
主要需要解决的问题时读盘时对象的重建上。一般地,读盘时会有这样两种需求:
a)需要读取的对象已经被分配内存(即对象已经存在)。对应的读盘函数为:
HRESULT SArchive::ReadObject(SObject *pOb);
b)对象的类型未知,从而对象不可能预先创建。对应读盘函数为:
HRESULT SArchive::ReadObject(
const SRuntimeClass *pClassRequest,
SObject **ppOb);
情形a)是比较简单的,它不需要RuntimeClass的支持。MFC中没有提供此函数。现考虑情形b)。为了能够从磁盘重建对象,显然应该将一个描述对象的id值与对象的创建函数关联。这已经由RuntimeClass技术完成了。在对象id的选取上,SW系统与MFC都使用了对象的类名。但是这不是唯一的选择。这一点在后面的COM技术部分还会提到。不管怎样,我们可以说,为了能够从磁盘中重建对象,需要在保存对象具体数据之前先保存对象的类信息(RuntimeClass)。读盘时先读出类信息,由此重建对象实例。代码如下:
voidSArchive::WriteObject(SObject*pOb)
{
WriteString(pOb->GetRuntimeClass()->m_szClassName);
pOb->Write(*this);
}
对于情形a)的ReadObject:
HRESULTSArchive::ReadObject(SObject*pOb)
{
LPCTSTRlpsz=ReadString();
if(!_tcscmp(pOb->GetRuntimeClass()->m_szClassName,lpsz))
{
delete[]lpsz;
pOb->Read(*this);
returnS_OK;
}
delete[]lpsz;
returnE_FAIL;
}
对于情形b)的ReadObject:
HRESULTSArchive::ReadObject(
constSRuntimeClass*pClassReq,
SObject**ppOb)
{
LPCTSTRszReadedClass=ReadString();
*ppOb=NULL;
if(pClassReq)
{
if(!_tcscmp(szReadedClass,pClassReq->m_szClassName))
*ppOb=pClassReq->m_fnCreator();
}
else
{
*ppOb=::gCreateObject(szReadedClass);
}
delete[]szReadedClass;
if(*ppOb)
{
(*ppOb)->Read(*this);
returnS_OK;
}
returnE_FAIL;
}
在此基础上,序列化中的另一个问题是,对象间的循环引用问题。在一个复杂的数据结构中,往往有A对象引用B对象,同时B对象又引用A对象。此时用上面的序列化机制,就会出现死循环。MFC以一种巧妙的方式解决了此问题。其核心思想是引入一个Hash表,将已经保存(或即将要保存)的对象指针与对象id(由系列化机制分配)联系起来。在第二次保存此对象时只是保存对象id,这样也就中断了循环。从这一个角度讲,序列化是相当优秀的。它可以轻易地保存任何一种复杂的数据结构。
考虑了循环引用问题后的对象读写函数如下:
voidSArchive::WriteObject(SObject*pOb)
{
WriteString(pOb->GetRuntimeClass()->m_szClassName);
UINTnObIndex=-1;
if(x_pMap->Lookup(pOb,&nObIndex))
{
//如果对象已经保存!
*thisnObIndex;
}
else
{
*this(UINT)-1;
//规定-1表示对象是正常存盘
x_pMap->SetAt(pOb,::gGetObIndex(pOb));
//这里gGetObIndex是系统为pOb对象分配id号的函数
//MFC中只是简单地用一个递增编号而已。
pOb->Write(*this);
}
}
HRESULTSArchive::ReadObject(
constSRuntimeClass*pClassReq,
SObject**ppOb)
{
*ppOb=NULL;
LPCTSTRszReadedClass=ReadString();
UINTnObIndex=-1;
*this>>nObIndex;
if(nObIndex!=(UINT)-1)
{
//已经被保存过的情形!!!
if(pClassReq&&
_tcscmp(szReadedClass,pClassReq->m_szClassName))
{
delete[]szReadedClass;
returnE_FAIL;
}
delete[]szReadedClass;
*ppOb=::gGetObByIndex(nObIndex);
returnS_OK;
}
//否则,正常情形,同以前一样!!!
if(pClassReq)
{
if(!_tcscmp(szReadedClass,pClassReq->m_szClassName))
*ppOb=pClassReq->m_fnCreator();
}
else
*ppOb=::gCreateObject(szReadedClass);
delete[]szReadedClass;
if(*ppOb)
{
(*ppOb)->Read(*this);
returnS_OK;
}
returnE_FAIL;
}
分享到:
相关推荐
其中主要有:SW系统中的窗口模型、属性、SW系统的RuntimeClass支持和序列化等。在最后,我们要分析经典应用程序框架的缺陷。同时也说明由SW系统向COM转变的必然。 3、 SW系统的新方向:基于COM(组件)思想的应用...
JsonTools是一个不错的JSON序列化和反序列化功能包
数据挖掘技术与应用:提取时间序列数据信息.docx数据挖掘技术与应用:提取时间序列数据信息.docx数据挖掘技术与应用:提取时间序列数据信息.docx数据挖掘技术与应用:提取时间序列数据信息.docx数据挖掘技术与应用:...
1.对象序列化的介绍 (1).NET支持对象序列化的几种方式 二进制序列化:对象序列化之后是二进制形式的,通过BinaryFormatter类来实现的,这个类位于System.Runtime.Serialization.Formatters.Binary命名空间下。 SOAP...
C#关于treeview序列化的一个应用程序
快速 ActiveRecord 序列化程序 ActiveRecord 模型和集合(关系或对象数组)的 JSON 序列化。 也可以用最少的语法序列化任何数组或哈希。 安装 将此行添加到应用程序的 Gemfile 中: gem 'fars' 然后执行: $ ...
C# 数组与序列化C# 数组与序列化C# 数组与序列化C# 数组与序列化C# 数组与序列化C# 数组与序列化C# 数组与序列化
C++ JSON 序列化与反序列化 相关的博客文章见:http://blog.csdn.net/TragicGuy
图像类的序列化,处理图像类的序列化,方便使用!
Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。在默认配置下,当应用或系统用Fastjson对由用户可控的JSON字符串进行解析时,将可能导致远程代码执行的危害。...
java 常用序列化和反序列化框架使用demo ,java 常用序列化和反序列化框架使用demo
Xson是一个Java对象序列化和反序列化程序。支持Java对象到字节数组的序列化,和从字节数组到Java对象的反序列化。 Maven: <groupId>com.github.xsonorg</groupId> <artifactId>xson-core <version>1.0.1 ...
SerialKiller是一个易于使用的前瞻性Java反序列化库,用于保护应用程序免受不受信任的输入的侵害。 当使用Java序列化在客户端和服务器之间交换信息时,攻击者可以用恶意数据替换合法的序列化流。 受启发,...
1、包含文件和二进制两种序列化的方式 2、支持类的序列化和STL容器的序列化 3、支持序列化的流自定义(示例中使用的是std::stringstream,也可以使用其他的流)
Google Protobuf基于Qt开发序列化与反序列化用QUdpSocket传输并显示。实例。 具体可查看了解:https://blog.csdn.net/automoblie0/article/details/101363526
5.2 相关知识 5.2.1 序列化的概念 5.2.2 序列化应用 5.2.3 序列化的几种方式 5.2.4 对象实现机制 Java高级程序设计实战教程第五章-Java序列化机制全文共15页,当前为第3页。 5.2.1 序列化的概念 将在内存中的各种...
基于WindowForm应用程序C#语言通过实际案例实现将对象保存到文件及从已保存的文件中读取对象(直接保存与读取、通过序列化与反序列化方式进行对象保存与读取)
文档编写了序列化与反序列化的类,并附带了对应的XML文件,包括一个窗口按钮的触发演示,供大家学习。文档中代码主要有两个模块组成: 1.XmlSerialization:执行序列化和反序列化的类 2.serializeXML:...
序列化和反序列化实例 序列化和反序列化实例 窗体实例 序列化和反序列化实例 序列化和反序列化实例 序列化和反序列化实例 序列化和反序列化实例
ASP.NET序列化与反序列化应用demo