天天看點

C++通過操作記憶體模拟序列化---實作多種類型的序列化(2)

昨天晚上寫了部分序列化,結果睡着了....今天繼續完善.. 明天的四級反正是裸考了,無所謂了 。。。。

昨天寫的那個隻能實作單一類型的簡單序列化 ,但是原理卻是一樣..

今天這個可以實作不同的類的序列化,但是注意的一點是我們發現前天的序列化類實作了模闆 ..可以正常的序列化反序列化 

如果我們将其抽象出來從一個基類派生,那麼模闆就顯得不好處理了,這裡最笨的方法使用到多重繼承 實作多個基類.然後再将這些基類進行進一步的抽象成一個更高的基類.讓我們的類從這個繼承樹最頂層繼承,我不知道微軟在MFC 和Sun在  java的對象流中是如何處理這些泛型類的 ...但是

如果像我上面這樣處理泛型 ,可能需要寫很多份代碼...雖然說實際開發中對于模闆的使用 泛型化參數不會很多 ,但是這樣的問題總是需要一個更好的解決方案來處理各種情況 。  我是想不出來,求神解答。。。。

由于對于泛型化類的處理不是一時半刻能弄出來 ,下面我接着昨晚上的做 ,我這裡隻處理C++中的非泛化的類 ,或許哪天我就明白了 。。。

昨天  JXXXXXXXX提出說隻能實作一個類.于是我修改了下 ,隻要繼承自Base的類都可以實作序列化 ......具體代碼如下

還有的一點從檔案---->記憶體--------->對象的恢複 沒有構造函數的調用 ,這一點很神奇 。。。

我們成功的恢複了2個對象但是卻沒有發生構造函數的調用...之是以我這種序列化方式能成功 ,肯定是在編譯器内部對于這種方式做了某種

支撐是以我說微軟MFC的序列化方式可能是這種方式。。。

C++通過操作記憶體模拟序列化---實作多種類型的序列化(2)

#include <iostream>

#include <fstream>

#include <string>

using  namespace std ;

class Base

public:

   /*  Base類型提供了統一的實作 ,所有需要序列化的類必須繼承自Base類 包括成員對象

   *   LoadObject  LoadObject 在這裡不需要多态機制 單獨作為功能的實作

   *   length 為對象的實際長度 為了避免在記憶體重配置設定過多的記憶體浪費空間

   *   long length=sizeof(*obj) ;  //不可以這樣做因為 我們發現實際上sizeof這個運算符

   *    在操作的時候擷取的是目前運作時類型所指對象的大小 如果向上轉型那麼會進行窄化處理 獲得的大小是1 是以這裡要傳遞實際大小

   *   LoadObject  LoadObject作為Base的靜态方法分别提供序列化和反序列化的功能

   */

    static void StoreObject(Base *obj,string file,int length)  

    {  

       cout<<"對象寫入到檔案..."<<endl ;

        ofstream *o=new ofstream(file.c_str()) ;

     o->write((char*)obj,length) ;

  o->close() ;

  delete o ;

    }

    static Base* LoadObject(string file,int length) 

  {

   cout<<"從檔案恢複對象..."<<endl ; 

   if(Base::tem_object!=NULL)

      return Base::tem_object ;

         char *buf=new char[length] ;

      ifstream i(file.c_str()) ;

      i>>buf ;

      Base *p=(Base*)buf ;

   Base::tem_object=p ;

   i.close() ;

   return (p);

  }

 /*

 * 構造器用做一些初始化操作

 */

 Base()

 {

 cout<<"基類構造中..."<<endl; }

 *  釋放反序列化時候配置設定的空間

 virtual ~Base()

  if(NULL==Base::tem_object)

   delete Base::tem_object ;

  Base::tem_object=NULL ;

 }

private:

 *  暫存加載的對象,對于同一個對象無論LoadObject多少次 加載的永遠隻是

 *  傳回的同一份記憶體即同一個對象,直到這個對象的聲明周期完畢,那麼再次加載會是不同的對象

  static Base *tem_object;

};

Base * Base::tem_object=NULL ;  //必須初始化靜态指針

//序列化類Data

class Data  :public Base

{   

private :

 int data ;

    Data(int x)

    {

 cout<<"Data構造中..."<<endl ;

 this->data=x;

    void OutPut()

     cout<<"Data.data="<<this->data<<endl ;

} ;

//序列化類MyObject

class MyObject :public Base

{

public :

  MyObject(int x)

  {  

 cout<<"MyObject 構造中.."<<endl;

      this->x=x ;

  ~MyObject()

  {

  MyObject ShowX()  //一段最簡單的代碼

  cout<<"x="<<x<<endl ;

  return (*this) ;

 int x ;

}  ;

int main()

{  

    string file1="c:\\data.txt" ;

    string file2="c:\\myobject.txt" ;

 int len1=sizeof(Data) ;

 int len2=sizeof(MyObject) ;

 *  序列化測試

 //測試對象1 ...

    Data *d=new Data(8);

    Base::StoreObject(d,file1,len1) ;

 //測試對象2

 MyObject *obj=new MyObject(33) ;

 Base::StoreObject(obj,file2,len2) ;  

  /*

 *  反序列化測試。。

 ((Data*)Base::LoadObject(file1,len1))->OutPut() ;

 ((MyObject*)Base::LoadObject(file2,len2))->ShowX()  ;

 delete d ;

 delete obj ;

 return 0 ;

}

操蛋的是睡覺之前出BUG了 ,明天要帶着BUG裸考了 。。

BUG1    同時序列化 2個以上的對象  如果序列化和反序列化放在一起了 就像下面的代碼

   Data *d=new Data(43);

  MyObject *obj=new MyObject(13) ;

 Base::StoreObject(obj,file2,len2) ;

 ((MyObject*)Base::LoadObject(file2,len2))->ShowX()  ;  

發現Data類的域中的x的值居然和MyObject類的成員資料是一樣的 。。。 但是如果像下面這樣一次處理一個 就不會有問題  。

  Data *d=new Data(43);

BUG2     如果先調用如下

然後把上述代碼注釋掉,在調用如下,在從檔案加載 就會出現值的亂碼 

相反的 如果一次性把序列化和反序列化寫在一起 ,那麼即使下次調用多次也不會出問題,,,

算了考完試再繼續Debug吧...哪位願意幫忙調試下。。。

C++通過操作記憶體模拟序列化---實作多種類型的序列化(2)