2010-11-30 23 views
5

我知道我可以使用:C++保存和結構的指針加載遊戲

MyGame game; // the game object 
// 

ofstream out("mygame.bin", ios::binary); 
out.write((char *)&game, sizeof(MyGame)); 

保存和載入遊戲,但如果我有MyGame結構內的指針呢?指針是否會被保存,但不是它指向的數據?

和:如何解決這個問題?

回答

5

你不能只是寫指針流,並期望它神奇地完成。您需要在對象中實現保存/加載方法。 E.g:

class Serializable 
{ 
    virtual void save(std::ofstream& _out) const = 0; 
    virtual void load(std::ifstream& _in) = 0; 
}; // eo class Serializable 


// some game object 
class MyObject : public Serializable 
{ 
    int myInt; 
    std::string myString; 

    virtual void save(std::ofstream& _out) const 
    { 
     _out << myInt << myString; 
    }; // eo save 

    virtual void load(std::ifstream& _in) 
    { 
     _in >> myInt >> myString; 
    }; // eo load 
}; // eo class SomeObject 

class MyGame : public Serializable 
{ 
    MyObject a; 
    MyObject b; 

    virtual void save(std::ofstream& _out) const 
    { 
     a.save(_out); 
     b.save(_out); 
    }; // eo save 

    virtual void load(std::ifstream& _in) 
    { 
     a.load(_in); 
     b.load(_in); 
    }; // eo load 
}; // eo class MyGame 
+0

這不是真的二元嗎?;) – Nim 2010-11-30 13:44:10

1

你可以重載流了運營商(<<)和流出每個個體場(反之亦然)

編輯:這是一個完整的例子...

#include <iostream> 
#include <fstream> 
#include <map> 

using namespace std; 

template <typename T> 
void serialize(ostream& str, const T& field) 
{ 
    str.rdbuf()->sputn(reinterpret_cast<const char*>(&field), sizeof(T)); 
} 

template <typename T> 
void deserialize(istream& str, T& field) 
{ 
    str.rdbuf()->sgetn(reinterpret_cast<char*>(&field), sizeof(T)); 
} 

class MyGame 
{ 
public: 
MyGame() : a(), b() {} 
MyGame(int av, int bv) : a(av), b(bv) {} 

friend ostream& operator<<(ostream& str, MyGame const& game); 
friend istream& operator>>(istream& str, MyGame& game); 

    int getA() const { return a; } 
    int getB() const { return b; } 

private: 
int a; 
int b; 
}; 

ostream& operator<<(ostream& str, MyGame const& game) 
{ 
    serialize(str, game.a); 
    serialize(str, game.b); 
    return str; 
} 

istream& operator>>(istream& str, MyGame& game) 
{ 
    deserialize(str, game.a); 
    deserialize(str, game.b); 
    return str; 
} 

int main(void) 
{ 
    { 
    ofstream fout("test.bin", ios::binary); 
    MyGame game(10, 11); 
    fout << game; 
    } 

    { 
    ifstream fin("test.bin", ios::binary); 
    MyGame game; 
    fin >> game; 
    cout << "game.a: " << game.getA() << ", game.b: " << game.getB() << endl; 
    } 

    return 0; 
} 

你必須瞭解儘管這種方法存在問題,例如所產生的文件將是特定平臺(即非便攜式)等。

0

嘗試game.serialize(out);。在你的序列化成員函數中調用你的指針成員的序列化。

0

爲每個類型創建一個需要持久化的序列化函數。
給每位會員打電話。

它實際上類似於通過網絡進行序列化或用於調試目的的可視化。

boost.serialize可以幫助你。

2

假設你沒有重寫char *強制轉換,是的,這很可能只保存指針而不是數據。

你需要的是你的對象的序列化。你可以提供一種方法來封送比特流中的對象狀態並寫出來。而且你還需要有方法來恢復狀態。

你可以閱讀更多有關序列上wikipedia

+0

如下所述,您的序列化和恢復方法可以覆蓋運營商! – 2010-11-30 13:39:28

1

升壓有serialization library,與在建的深指針支持保存,恢復和共享數據指針的正確序列化。

這是一個相當廣泛的庫,但你不需要編寫那麼多代碼就可以開始在自己的項目中使用它。在我看來,除了最簡單的序列化要求之外,值得學習。

0

只是轉儲指針值的「天真」序列化永遠不會工作,因爲反序列化時,這些指針將無效。

的一般方法這種問題會是這樣的:

  1. 具有可以在你的遊戲序列化的每個對象實現serialize()虛函數(我假設所有這些對象將最終從派生相同的基類)。
  2. 有基類實現一個get_serialized_id()公共函數。此函數將使用靜態自動遞增變量爲每個對象實例生成唯一的ID,但僅在第一次調用該對象時(後續調用將返回現有值)。

現在,序列化時:

  1. 開始用std::map<int, YourBaseClass*>。將game對象添加到此地圖,使用get_serialized_id()返回的值作爲密鑰。
  2. 雖然地圖包含尚未序列化的對象:
    • 取第一個這樣的對象。
    • 序列化其get_serialized_id()
    • 通過調用serialize()來實現序列化。像往常一樣堅持原始數據。對於通過指針可用的數據,請在指向的每個對象上調用get_serialized_id(),並將其從中返回的數字序列化。另外,將該對象添加到地圖。

這將導致與每個人的「隨機」 ID一起一堆的對象被序列化(在「隨機」的順序)。

當反序列化:

  1. 開始用std::map<int, YourBaseClass*>。閱讀保存文件中的第一項。
  2. 對於第一個對象指向的每個對象,您知道一個唯一的id(這是您序列化的而不是指針)。從保存的文件中獲取具有此ID的項目並對其進行反序列化。
  3. 遞歸執行此操作,直到從保存的文件中提取並反序列化所有項目。
  4. 由於每個項目都具有上述步驟3中反序列化的所有依賴關係,因此將其實例化爲一個對象並將其添加到地圖中。
  5. 這將使您能夠從地圖中獲取指定項目ID的指針,您現在可以使用該項目來設置依賴於此項目的對象的指針成員。
  6. 當遞歸結束時,地圖中的最後一個對象將成爲您的主「遊戲」對象,並且所有指針都準備就緒。
0

你所做的是淺拷貝,如果你的MyGame類中有指針,那麼深拷貝是MUST !. 我建議在MyGame的內部實現一個函數或一組函數,這些函數會將自己的數據保存到一個文件中,而您只需要調用它。

0

感謝大家的快速和良好的答案,但我的一個朋友(誰在幫助我)告訴我,我們應該以另一種方式做。

我只是保存對象的基礎知識,我們在函數中重新創建其餘部分。

這是一款紙牌遊戲,爲了保存紙牌堆,我們只保存紙牌的ID(不是物體),並且在從文件中讀取ID時重新初始化每張紙牌。