`
helpbs
  • 浏览: 1163492 次
文章分类
社区版块
存档分类
最新评论

新手指南-序列化篇之三

 
阅读更多

序列化初步之三(翻译)

http://www.codeproject.com/cpp/serialization_primer3.asp
在前两部分,我们学习了在通常情况下,如何为序列化提供有力的支持。在这一部分,我们将学习序列化任何一种对象时的特殊的规则。这里有四个常用的参考例子。每个例子都由前一个构成。

Ø 序列化一个简单类

Ø 序列化一个派生类

Ø 序列化一个同源的聚集类

Ø 序列化一个异源的聚集类

我们的Searialize()方法将返回以下状态码之一:

l Success

l InvalidFormat

l UnsupportedVersion

l ReadError

l WriteError

序列化一个简单类<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

一个“简单类”的定义是:一个即没有父类,也没有聚集类的对象。序列化一个简单的类需要以下步骤:

1. 序列化对象签名和版本

2. 序列化对象成员(如果有)

在下面的例子中,类Point包含两个int型变量,表示点的坐标。对象的签名和版本定义成静态成员(m_strSignaturem_nVersion),所以每个Point类的实例都共享它们。

int Point::serialize

(CArchive* pArchive)

{

ASSERT (pArchive != NULL);

// Step 1: Serialize signature and version

int nVersion;

try {

if (pArchive->IsStoring()) {

(*pArchive) << Point::m_strSignature;

(*pArchive) << Point::m_nVersion;

} else {

CString strSignature;

(*pArchive) >> strSignature;

if (strSignature != Point::m_strSignature)

return (Status::InvalidFormat);

(*pArchive) >> nVersion;

if (nVersion > Point::m_nVersion;)

return (Status::UnsupportedVersion);

}

// Step 2: Serialize members

if (pArchive->IsStoring()) {

(*pArchive) << m_nX;

(*pArchive) << m_nY;

} else {

(*pArchive) >> m_nX;

(*pArchive) >> m_nY;

}

}

catch (CException* pException) {

// A read/write error occured

pException->Delete();

if (pArchive->IsStoring())

return (Status::WriteError);

return (Status::ReadError);

}

// Object was successfully serialized

return (Status::Success);

}

序列化一个派生类

派生类是指派生于一个简单类,并且不是一个聚集类的类。序列化一个派生类需要以下步骤:

1. 序列化对象签名和版本

2. 序列化对象的基类<<额外的步骤

3. 序列化对象的成员(如果有)

在下面的例子中,类ColoredPointPoint类派生,并且增加一个叫做m_nColorint型变量,表示点的颜色。如同所有序列化的类一样,ColoredPoint类也定义一个静态签名和版本。

int ColoredPoint::serialize

(CArchive* pArchive)

{

ASSERT (pArchive != NULL);

// Step 1: Serialize signature and version

int nVersion;

try {

if (pArchive->IsStoring()) {

(*pArchive) << ColoredPoint::m_strSignature;

(*pArchive) << ColoredPoint::m_nVersion;

} else {

CString strSignature;

(*pArchive) >> strSignature;

if (strSignature != ColoredPoint::m_strSignature)

return (Status::InvalidFormat);

(*pArchive) >> nVersion;

if (nVersion > ColoredPoint::m_nVersion;)

return (Status::UnsupportedVersion);

}

// Step 2: Serialize the base class

int nStatus = Point::serialize (pArchive);

if (nStatus != Status::Success)

return (nStatus);

// Step 3: Serialize members

if (pArchive->IsStoring())

(*pArchive) << m_nColor;

else

(*pArchive) >> m_nColor;

}

catch (CException* pException) {

// A read/write error occured

pException->Delete();

if (pArchive->IsStoring())

return (Status::WriteError);

return (Status::ReadError);

}

// Object was successfully serialized

return (Status::Success);

}

序列化一个同源的聚集类

同源聚集类常常用来存储数量不定的多个同类型对象。序列化同源聚集类需要以下步骤:

1. 序列化对象签名和版本

2. 序列化对象的基类(如果有)

3. 序列化聚集对象的数量<<额外的步骤

4. 序列化每个聚集对象<<额外的步骤

5. 序列化对象的其它成员(如果有)

在下面的例子中,类ColoredPointList是一个ColoredPoint对象的聚集。为了简单,ColoredPointList类使用CPtrArray来存储对象。如同所有序列化类一样,ColoredPointList类也定义了一个静态签名和版本。以下是ColoredPointList类的示例:

class ColoredPointList

{

// Construction/destruction

public:

ColoredPointList::ColoredPointList();

virtual ColoredPointList::~ColoredPointList();

// Attributes

public:

static const CString m_strSignature;

static const int m_nVersion;

// Operations

public:

int serialize (CArchive* pArchive);

// Members

protected:

CPtrArray m_coloredPoints;

}

下面是我们如何序列化它:

int ColoredPointList::serialize

(CArchive* pArchive)

{

ASSERT (pArchive != NULL);

int nStatus = Status::Success;

// Step 1: Serialize signature and version

int nVersion;

try {

if (pArchive->IsStoring()) {

(*pArchive) << ColoredPointList::m_strSignature;

(*pArchive) << ColoredPointList::m_nVersion;

} else {

CString strSignature;

(*pArchive) >> strSignature;

if (strSignature != ColoredPointList::m_strSignature)

return (Status::InvalidFormat);

(*pArchive) >> nVersion;

if (nVersion > ColoredPointList::m_nVersion;)

return (Status::UnsupportedVersion);

}

// Step 2: Serialize base class (if any)

//

// Nothing to do since ColoredPointList isn't derived from anything.

// But if it was derived from BaseColoredPointList, we'd do:

//

// nStatus = BaseColoredPointList::serialize (pArchive);

// if (nStatus != Status::Success)

// return (nStatus);

// Step 3: Serialize number of items in collection

int nItems = 0;

if (pArchive->IsStoring())

(*pArchive) << m_coloredPoints.GetSize();

else

(*pArchive) >> nItems;

// Step 4: Serialize each object in collection

for (int nObject=0; (nObject < nItems); nObject++) {

// 4a: Point to object being serialized

ColoredPoint* pColoredPoint = NULL;

if (pArchive->IsStoring())

pColoredPoint = (ColoredPoint *) m_coloredPoints.GetAt (nObject);

else

pColoredPoint = new ColoredPoint();

ASSERT (pColoredPoint != NULL);

// 4b: Serialize it

nStatus = pColoredPoint->serialize (pArchive);

if (nStatus != Status::Success)

return (nStatus);

if (!pArchive->IsStoring())

m_coloredPoints.Add (pColoredPoint);

}

// Step 5: Serialize object's other members (if any)

//

// Nothing to do since ColoredPointList doesn't have any other

// members. But if it contained an int (m_nSomeInt) and a Foo

// object (m_foo), we'd do:

//

// if (pArchive->IsStoring())

// (*pArchive) << m_nSomeInt;

// else

// (*pArchive) >> m_nColor;

//

// nStatus = m_foo::serialize (pArchive);

// if (nStatus != Status::Success)

// return (nStatus);

}

catch (CException* pException) {

// A read/write error occured

pException->Delete();

if (pArchive->IsStoring())

return (Status::WriteError);

return (Status::ReadError);

}

// Object was successfully serialized

return (Status::Success);

}

序列化一个异源聚集类

异源聚集类常常用来存储数量不定的多个不同类型对象。序列化一个异源聚集类需要以下步骤:

1. 序列化对象签名和版本

2. 序列化对象的基类(如果有)

3. 序列化聚集对象的数量

4. 对于每一个聚集对象

a. 序列化对象签名<<额外的步骤

b.序列化对象

5. 序列化对象的其它成员(如果有)

你会注意到在序列化中一个仅有的额外步骤是4(a),在序列化每个对象自身前,将先序列化每个对象的签名。这样以后读取数据就比较方便。当序列化一个同源聚集类时,我们处理同类型的对象(前一个例子中的ColoredPoint)。为了读取一个ColoredPoint类,我们在堆中构造它,并且调用它的Searialize()方法。

ColoredPoint* pColoredPoint = new ColoredPoint();

nStatus = pColoredPoint->serialize (pArchive);

当我们处理异源聚集类时,在序列化对象之前,我们需要知道我们读取的对象的类型。这个信息来自于对象的签名。由于我们在序列化对象时已经保存了对象的签名,因此读取时我们可以根据对象的类型构造合适的对象。

// Read object signature

CString strSignature;

pArchive >> strSignature;

// Construct object of appropriate type

ISerializable* pObject = NULL;

if (strSignature == ColoredPoint::m_strSignature)

pObject = new ColoredPoint();

else

if (strSignature == Line::m_strSignature)

pObject = new Line();

else

if (strSignature == Rectangle::m_strSignature)

pObject = new Rectangle();

else

return (Status::InvalidFormat);

ASSERT (pObject != NULL);

// Read it back in

nStatus = pObject->serialize (pArchive);

在上面的代码片段中,ColoredPointLineRectangle都是(最终)派生于一个公共的基类ISerializable。这个类除了纯虚函数外没有比一个抽象基类更多的内容(换句话说,是一个“接口” )。ISerializable定义方法getSignature()getVersionSerialize()

class ISerializable

{

// Construction/destruction

public:

ISerializable::ISerializable()

{ }

virtual ISerializable::~ISerializable()

{ }

// Operations

public:

// Get the object's signature

virtual CString getSignature() = 0;

// Get the object's version

virtual int getVersion() = 0;

// Serialize the object

virtual int serialize (CArchive* pArchive) = 0;

}

好,让我们序列化异源聚集类。在下面的例子中,类ShapeList是可变数量的ColoredPointLineRectangle对象的聚集,它们都派生于ISerializable。你可以将这些类看做是“ISerializable接口的实现”。

int ShapeList::serialize

(CArchive* pArchive)

{

ASSERT (pArchive != NULL);

int nStatus = Status::Success;

// Step 1: Serialize signature and version

int nVersion;

try {

if (pArchive->IsStoring()) {

(*pArchive) << ShapeList::m_strSignature;

(*pArchive) << ShapeList::m_nVersion;

} else {

CString strSignature;

(*pArchive) >> strSignature;

if (strSignature != ShapeList::m_strSignature)

return (Status::InvalidFormat);

(*pArchive) >> nVersion;

if (nVersion > ShapeList::m_nVersion;)

return (Status::UnsupportedVersion);

}

// Step 2: Serialize base class (if any)

//

// Nothing to do since ShapeList isn't derived from anything.

// But if it was derived from BaseShapeList, we'd do:

//

// nStatus = BaseShapeList::serialize (pArchive);

// if (nStatus != Status::Success)

// return (nStatus);

// Step 3: Serialize number of items in collection

int nItems = 0;

if (pArchive->IsStoring())

(*pArchive) << m_shapes.GetSize();

else

(*pArchive) >> nItems;

// Step 4: Serialize each object in collection

for (int nObject=0; (nObject < nItems); nObject++) {

// 4a: First serialize object's signature

CString strSignature;

if (pArchive->IsStoring())

(*pArchive) << pObject->getSignature();

else

(*pArchive) >> strSignature;

//

// 4b: Then serialize object

//

// 4b (1): Point to object being serialized

ISerializable* pObject = NULL;

if (pArchive->IsStoring())

pObject = (ISerializable *) m_shapes.GetAt (nObject);

else {

if (strSignature == ColoredPoint::m_strSignature)

pObject = new ColoredPoint();

else

if (strSignature == Line::m_strSignature)

pObject = new Line();

else

if (strSignature == Rectangle::m_strSignature)

pObject = new Rectangle();

else

return (Status::InvalidFormat);

}

ASSERT (pObject != NULL);

// 4b (2): Serialize it

nStatus = pObject->serialize (pArchive);

if (nStatus != Status::Success)

return (nStatus);

if (!pArchive->IsStoring())

m_shapes.Add (pColoredPoint);

}

// Step 5: Serialize object's other members (if any)

//

// Nothing to do since ShapeList doesn't have any other

// members. But if it contained an int (m_nSomeInt) and

// a Foo object (m_foo), we'd do:

//

// if (pArchive->IsStoring())

// (*pArchive) << m_nSomeInt;

// else

// (*pArchive) >> m_nColor;

//

// nStatus = m_foo::serialize (pArchive);

// if (nStatus != Status::Success)

// return (nStatus);

}

catch (CException* pException) {

// A read/write error occured

pException->Delete();

if (pArchive->IsStoring())

return (Status::WriteError);

return (Status::ReadError);

}

// Object was successfully serialized

return (Status::Success);

}

类工厂

你可以用一个基于签名的“类工厂”来提供一个新的对象实例以替换在代码片段中丑陋的if申明。这里有一些关于类工厂的参考文章:

虽然文章是复杂多样的,但在这之后的基本思想是一样的。一个类工厂和类没有多大差别,它提供一个适当的指定的静态方法(例如:create()),这个方法提供一个特殊类型的对象。通过工厂的create()方法,你可以隐藏令人厌恶的if申明。稍微整理一下代码:

...

// Construct object of appropriate type

ISerializable* pObject = MyClassFactory::create (strSignature);

ASSERT (pObject != NULL);

...

分享到:
评论

相关推荐

    SQL Server 2008商业智能完美解决方案 3/3

    SQL Server 2008商业智能完美解决方案 3/3 SQL Server 2008 2010 商业智能完美解决方案 作者:兰吉特(Lynn Langit) 出版社:人民邮电出版社; 第1版 (2010年8月1日) ISBN:7115231117, 9787115231116 页码:545 ------...

    SQL Server 2008商业智能完美解决方案 1/3

    第三部分 Microsoft SQL Server 2008 Integration Services开发人员指南 第14章 Microsoft SQL Server 2008 Integration Services的架构组件 329 14.1 Integration Services架构概述 329 14.2 Integration Services...

    SQL Server 2008商业智能完美解决方案 2/3

    SQL Server 2008商业智能完美解决方案 2/3 SQL Server 2008 2010 商业智能完美解决方案 作者:兰吉特(Lynn Langit) 出版社:人民邮电出版社; 第1版 (2010年8月1日) ISBN:7115231117, 9787115231116 页码:545 ------...

    SQL Server 2008 商业智能完美解决方案(3)

    SQL Server 2008商业智能完美解决方案 3/3 SQL Server 2008 2010 商业智能完美解决方案 作者:兰吉特(Lynn Langit) 出版社:人民邮电出版社; 第1版 (2010年8月1日) ISBN:7115231117, 9787115231116 页码:545 ...

    asp.net知识库

    泛型的序列化问题 .NET 2.0 泛型在实际开发中的一次小应用 C#2.0 Singleton 的实现 .Net Framwork 强类型设计实践 通过反射调用類的方法,屬性,字段,索引器(2種方法) ASP.NET: State Server Gems 完整的动态加载/卸载...

    Visual C++ 2010入门经典(第5版)--源代码及课后练习答案

    大家一致认为,他的著作独具风格,无论是编程新手,还是经验丰富的编程人员,都很容易理解其内容。在个人实践中,Ivor Horton也是一名系统顾问。他从事程序设计教学工作已经超过了25年。  苏正泉,1995年毕业于解放...

    Tcl_TK编程权威指南pdf

    Tcl_TK编程权威指南pdf 内容简介回到顶部↑Tcl/Tk是第一种能通过Windows、Macintosh和Solaris等主要平台处理企业级任务的脚本语言。本书共分为55章,依次详细讲述了Tcl基础、Tcl高级特性、TK基础、TK组件、TK详解、...

    head first c#.pdf

    之後,你會學到有關類別與物件導向編程、繪製圖形與動畫、使用 LINQ 查詢資料以及將資料序列化到檔案的一切知識。另外,你將透過建造真實專案、實際打造遊戲及解決謎題來學習各種知識。完成本書閱讀之際,你將成為一...

    java源码包---java 源码 大量 实例

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    micropython-samples:各种各样的代码提示以及其他存储库的索引

    micropython样本此仓库的第一部分包含... 3.1编写弹性WiFi代码的指南3.2 MicroPython的四个序列化库的序列化回顾3.3 快速模拟信号的相对时序和相位的测量对于Pyboard。 代码样本带有前缀Pyboard的样本是特定于Pyb

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    密钥 Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存...

    Learning-Kibana-7-Second-Edition:Packt出版的Learning Kibana 7,第二版

    如果您是该工具的新手,或者想了解Kibana 7中引入的最新功能,则这本书是完美的初学者指南。 您将学习如何设置和配置Elastic Stack,并了解Kibana在架构中的位置。 随着您的前进,您将学习如何使用Beats或Logstash...

    CuteFTP9简易汉化版

    一种上传软件很简单对于新手FTP用户,然而强大的足以让有经验的用户。 友好的用户界面使您可以轻松地更新和维护复杂的网站。 你可以用一种上传软件维护关键任务文件传输的安全特性。 你甚至可以计划和脚本使用转让...

    spring security 参考手册中文版

    4.样品和指南(从这里开始) 28 5. Java配置 29 5.1 Hello Web安全Java配置 29 5.1.1 AbstractSecurityWebApplicationInitializer 31 5.1.2 AbstractSecurityWebApplicationInitializer不存在Spring 31 5.1.3使用...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    密钥 Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存...

    JAVA上百实例源码以及开源项目

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JAVA上百实例源码以及开源项目源代码

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    java源码包3

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    Keras中文手册

    模块性:模型可理解为一个独立的序列或图,完全可配置的模块以最少的代价自由组合在一起。具 体而言,网络层、损失函数、优化器、初始化策略、激活函数、正则化方法都是独立的模块,你可 以使用它们来构建自己的模型...

Global site tag (gtag.js) - Google Analytics