2010-11-30 65 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时重新初始化每张纸牌。