日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

串行化的机制和原理

發(fā)布時(shí)間:2025/4/16 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 串行化的机制和原理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

今天終于把Seralization 的基本框架搭好了,簡(jiǎn)單的測(cè)試了一下,存儲(chǔ)沒(méi)問(wèn)題,讀取好像還有點(diǎn)問(wèn)題.由于現(xiàn)在還沒(méi)有寫由Object派生出來(lái)的類,測(cè)試不出什么東西,等把場(chǎng)景管理的部分完成后再回來(lái)改.

?

由于整個(gè)Seralization的機(jī)制比較煩瑣,我今天把整個(gè)思路整理一下,一是作為交流,另外也作為CoagelEngine的開(kāi)發(fā)文檔.

?

Seralization 又叫串行化,簡(jiǎn)單的講,就是一種保存當(dāng)前運(yùn)行程序的狀態(tài),下次運(yùn)行程序時(shí)可以將被保存的狀態(tài)提取出來(lái),這樣就可以從上次保存的狀態(tài)開(kāi)始往后運(yùn)行.在游戲設(shè)計(jì)中,這也就是所謂的存檔/讀檔功能.

?

那么Seralization如何才能實(shí)現(xiàn)呢. 在結(jié)構(gòu)化的程序設(shè)計(jì)中,函數(shù)(方法)和數(shù)據(jù)是相互獨(dú)立的.

我們需要將當(dāng)前內(nèi)存塊中的每個(gè)變量數(shù)據(jù)都保存到文件(后者是一個(gè)內(nèi)存塊,這點(diǎn)在下文提到),然后下次運(yùn)行時(shí)在將這些數(shù)據(jù)都提取出來(lái),付給每個(gè)變量. 比如說(shuō)我的程序有兩個(gè)全局變量Ea,Eb.有兩個(gè)局部變量a,b. 其中a,b都是函數(shù)Fun 的局部變量.那么我需要保存這4個(gè)變量的值. 并且我要知道a,bFun的局部變量,Ea,Eb是全局變量. 并且我需要知道程序執(zhí)行到哪一步了. 這是個(gè)復(fù)雜且難以完成的工作. 因此Seralization 都是在OOP 面向?qū)ο蟮脑瓌t下進(jìn)行的. 甚至有的人直接稱其為類的串行化.

?

基于OOP原則的程序, 類是數(shù)據(jù)和方法的集合. 我們只需要保存當(dāng)前生存著的每個(gè)類中的數(shù)據(jù), 類與類之間的關(guān)系, 當(dāng)然如果有全局變量也需要保存. 下次還原時(shí)我們還原被保存的這些信息, 就還原了程序的狀態(tài).

?

這里就引入了幾個(gè)問(wèn)題.

1. 我們知道類繼承機(jī)制中的虛函數(shù)機(jī)制可以動(dòng)態(tài)的決定調(diào)用哪個(gè)函數(shù). 比如:

Class A

{

Public:

??? Visual void fun() { return 1;};

}

?

Class B : public A

{

? Public:

??? Virtual void fun(){ return 2;};

}

?

我定義一個(gè)指針 A* p = new B;

注意這里雖然p是一個(gè)A* 類的指針,但他實(shí)際上指向的是一個(gè)class B.

因此調(diào)用p->func 其實(shí)調(diào)用的是 B::func();

?

回到剛才的話題.類的成員函數(shù)如果被聲明是虛函數(shù)的話,可以動(dòng)態(tài)的決定調(diào)用哪個(gè)類的函數(shù).但是類的創(chuàng)建必須要寫成 A p = new A, 這里我們不能利用虛函數(shù)來(lái)實(shí)現(xiàn)動(dòng)態(tài)的決定創(chuàng)建的是什么類.因?yàn)閯?chuàng)建時(shí)程序還不知道p到底值向什么類.創(chuàng)建A類就必須寫成new A,創(chuàng)建B類就必須寫成new B. 這就是問(wèn)題所在了.這個(gè)問(wèn)題又被分為兩個(gè)方面.首先,我們必須在保存類的信息時(shí)同時(shí)保存該類的類型

(是class A,還是 class B.這點(diǎn)可以利用RTTI的機(jī)制來(lái)實(shí)現(xiàn).RTTI的原理很簡(jiǎn)單,我們?cè)诿總€(gè)類中都添加一個(gè)字符串,這個(gè)字符串記錄的這個(gè)類的類型名字.比如class A的字符串就是”A”,class B的字符串就是”B”.當(dāng)我們保存的時(shí)候,我們把這個(gè)字符串也保存起來(lái).這樣當(dāng)我們讀取的時(shí)候就知道現(xiàn)在讀取的數(shù)據(jù)是屬于什么類的了.

?

然后我們需要解決的問(wèn)題就是如果創(chuàng)建這個(gè)類了.前面說(shuō)了.我們不能利用new 來(lái)創(chuàng)建,因?yàn)檫@里的創(chuàng)建是程序執(zhí)行時(shí)動(dòng)態(tài)決定的.我們事先不知道哪些類需要?jiǎng)?chuàng)建.這個(gè)問(wèn)題我們利用object factory的思想來(lái)解決.我們?yōu)槊糠N類都定義一個(gè)static factoryFunc();由于是static

的,所以該類的所以實(shí)例都共享這個(gè)方法,同時(shí)這個(gè)factoryFunc()是類相關(guān)的,不是實(shí)例相關(guān)的,因此在類還沒(méi)被實(shí)例化之前就存在了(可以想像成全局的,從程序運(yùn)行開(kāi)始一直存在到程序結(jié)束). 我們將每個(gè)類的factoryFunc和該類的類型名(A,B)一起添加到一個(gè)map

容器中,一個(gè)類型名對(duì)應(yīng)一個(gè)factoryFunc. factoryFunc封裝了類的new 操作.這樣我讀取存檔的時(shí)候.我只需要先讀取類的類型名,然后到map里去查找這個(gè)類型名對(duì)應(yīng)的factoryFunc,然后調(diào)用它來(lái)創(chuàng)建這個(gè)類就行了.偽代碼如下

?

Read(stream, classname);

factoryFunc = Map->find(classname)

object* p = factoryFunc();

?

這樣就實(shí)現(xiàn)了類的動(dòng)態(tài)創(chuàng)建.

?

2.如何保存類之間的關(guān)系

這里我說(shuō)類之間的關(guān)系就是指類的指針成員指向的其它類.由于我設(shè)計(jì)的引擎是以OOP為基礎(chǔ)的.我定義了一個(gè)Object 類,并且認(rèn)為其它一切的類都是這個(gè)類的派生類.注意最開(kāi)始我們提到的保存機(jī)制保存了類的指針.但是如果我們新創(chuàng)建了一個(gè)類,那這個(gè)類的指針是系統(tǒng)自動(dòng)分配的,和上次保存的地址是不一樣的.因此不能簡(jiǎn)單的將當(dāng)前類的指針成員的值保存下來(lái),然后在讀取出來(lái)重新付給它(因?yàn)楝F(xiàn)在這個(gè)值代表的內(nèi)存塊里的數(shù)據(jù)和上次不一樣了).我們需要一個(gè)映射機(jī)制,能將舊的指針值和新的指針值對(duì)應(yīng)起來(lái).我這里也是利用的map來(lái)實(shí)現(xiàn).

?

?

整個(gè)Seralization機(jī)制流程如下:

?

主要是2個(gè)類.Object , Stream

其中Stream里面有一個(gè)vector<object*> top,用來(lái)保存場(chǎng)景中的主要物體.這里需要解釋一下.我的設(shè)計(jì)思路是場(chǎng)景中的物體是有關(guān)聯(lián)關(guān)系的.比如一輛汽車,它有4個(gè)子物體――輪子.如果這輛汽車沒(méi)有父節(jié)點(diǎn),那汽車就是一個(gè)主要物體.而輪子不是主要物體.這個(gè)容器的作用是用來(lái)遞歸的調(diào)用Object的方法.

Stream的第2個(gè)容器是static map<string,factortFunc*> factory, 就是上面提到的,將factoryFunc和類的類型名對(duì)應(yīng)起來(lái).

Stream的第3個(gè)容器是map<Object*,Link*> ?mLink ,Link是一個(gè)自定義的類,它有一個(gè)object*

,用來(lái)表示它是哪個(gè)實(shí)例的Link,還有一個(gè)vector<object*>,里面保存這個(gè)實(shí)例的指針成員數(shù)據(jù).

?

Stream的第4個(gè)容器是vector<Object*> order,用來(lái)保存場(chǎng)景中所有的實(shí)例指針.

?

Stream提供SaveLoad兩個(gè)方法.

?

Save: 首先將order清空,然后對(duì)top中的每個(gè)實(shí)例都調(diào)用object::register.這個(gè)方法是將該實(shí)例的指針添加到order中,并遞歸的調(diào)用這個(gè)實(shí)例的子實(shí)例.這樣order就保存了所有實(shí)例的指針值了.

   然后對(duì)每個(gè)實(shí)例都調(diào)用Object::Save 當(dāng)然,這里Save 和 register都是虛函數(shù).

Save的作用是將類的類型名,類的指針,類的名字,類的數(shù)據(jù)成員,類的成員指針都保存起來(lái).如果這個(gè)實(shí)例是主物體,那就在類的類型名前加一個(gè)”Top”.

?

?

?

Load: 首先將order, mLink清空,依次讀出每一塊數(shù)據(jù),根據(jù)數(shù)據(jù)中類的類型名,去factory中找到對(duì)應(yīng)的方法,創(chuàng)建這個(gè)類,然后把類的名字,類的數(shù)據(jù)成員都從數(shù)據(jù)塊中讀出付給新的類.接下來(lái)是重點(diǎn)了,創(chuàng)建這個(gè)類(實(shí)例)以后,要把它跟一個(gè)Link類聯(lián)系起來(lái).把這個(gè)實(shí)例現(xiàn)在的指針付個(gè)LinkObject*,并且將數(shù)據(jù)塊中的關(guān)于成員指針的數(shù)據(jù)都加入到Linkverctor中.注意這里vector中還是舊的指針數(shù)據(jù)哦.最后讀出數(shù)據(jù)塊中這個(gè)類的指針值,將它作為關(guān)于這個(gè)類的標(biāo)示,和Link一起放入mLink中.于是mLink就成了用舊指針值作索引,用保存了這個(gè)實(shí)例的新指針值和這個(gè)實(shí)例的就指針成員的Link作值的hash表.

上面的步驟結(jié)束后.我們從頭查找m_link,對(duì)每一個(gè)LinkObject* ,我們都調(diào)用虛函數(shù)

Object::Link(),并把該Link作為參數(shù)傳給Link()Object::Link會(huì)根據(jù)Linkvector里面的每個(gè)值作索引,去m_link里面找到他對(duì)應(yīng)的Link,并把Linkobject* 傳回來(lái),作為該Object新的成員指針.

?

大體的流程就是這樣,過(guò)幾天有空我會(huì)畫一張?jiān)敿?xì)的流程圖

?

轉(zhuǎn)載于:https://www.cnblogs.com/badkeeper/articles/123723.html

總結(jié)

以上是生活随笔為你收集整理的串行化的机制和原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。