2017-05-29 77 views
0

我有一个名为如何将对象的模板化阵列保存到文件?

Array<T> 

您可以创建任何类型的数组类。

template <typename T> 
    class Array 
    { 
    private: 
     T *m_array; 
     int m_size; 
     ... 

例如,

Array <int> myArray(32) 

是int类型的数组的大小为32。这可以存储基本类型或复杂的对象。例如,

Array<Monster> monsters(32) 

可以容纳一个怪物对象的数组。无论使用什么类型,我想从磁盘保存和加载数组。

其中一个对象,比如Actor,有一个类型为std :: string的成员变量(名称)。因此,它被存储为

Array<Actor> actors(32) 

我今天意识到,C'S I/O功能一无所知的std :: string,所以装载的std ::从文件的字符串是在关机导致飞机坠毁。我想将我的Save/Load函数升级到C++的等价函数。我的假设是这将解决我的问题,保存和加载具有std :: string类型的成员变量的对象。我的原始保存/加载函数: (因为它们由于模板的工作原因而在头文件中,我应该提到它们是Array的更正式成员,或者Array :: save()和Array :: load() 。))

  bool save(const string filename) 
     { 
      FILE *fOut = NULL; 
      int written = 0; 

      // Validate the array 
      if (!isValidArray()) 
       return false; 

      // Open the file 
      fOut = fopen(filename.c_str(), "wb"); 
      if (fOut == NULL) 
       return false; 

      // Write the array's size to file. 
      fwrite(&m_size, sizeof(int), 1, fOut); 

      // Write the array to file. 
      written = fwrite(m_array, sizeof(T), m_size, fOut); 
      fclose(fOut); 

      // Validate if the array was written correctly 
      if (written != m_size) 
       return false; 

      return true; 
     } 

负载:

bool load(const string filename) 
     { 
      FILE *fIn = NULL; 
      int read = 0; 
      int size = 0; 

      // Open the file 
      fopen_s(&fIn, filename.c_str(), "rb"); 
      if (fIn == NULL) 
       return false; 

      // Read the array's size from file. 
      fread(&size, sizeof(int), 1, fIn); 

      // Rleease the old array 
      release(); 

      // Initialize the new array 
      if (!init(size)) 
       return false; 

      // Read the array from file. 
      read = fread(m_array, sizeof(T), size, fIn); 
      fclose(fIn); 

      // Validate if the array was written correctly. 
      // If not, clean up the array object. 
      if (read != size) 
      { 
       if (m_array != NULL) 
       { 
        delete[] m_array; 
        m_array = NULL; 
        m_size = 0; 
       } 

       return false; 
      } 

      return true; 
     } 

总体来说,我想这些转换成C++的文件处理。

这是我的C++的尝试与保存():

 bool save(const string filename) 
     { 
      ofstream fOut; 

      // Validate the array 
      if (!isValidArray()) 
       return false; 

      // Open the file 
      fOut.open(filename.c_str(), std::ios::binary | std::ios::out); 
      if (!fOut.is_open()) 
       return false; 

      // Write the array's size to file. 
      fOut << m_size; 

      // Write the array to file. ???? 
      fOut.write(m_array, m_size); 

      fOut.close(); 

      return true; 
     } 

所以,我的问题是我如何保存到文件时,它的模板类型可以是基本数据类型,结构或类阵列。我的第一个假设是:

// Write the array to file. ???? 
fOut.write(m_array, m_size); 

任何想法都会有帮助。谢谢。

发现我需要序列化,我为我的Actor类重载了运算符< <,但希望进一步指导如何将其用于此目的。 Actor有一个需要保存到文件的std :: string。

std::ofstream & X2D::operator<<(std::ofstream & output, const Actor & p) 
{ 
    // insert magical code here 
    return output; 
} 
+3

你在找什么叫做序列化。 –

+0

_“由于模板的工作原因,它们位于标题中”_作为旁白,您应该考虑将这些定义从类定义中移出以获得更清晰和更好的代码。他们仍然可以在头上。 –

+0

_“我有一个名为[..]的类你可以创建任何类型的数组。”_std :: array有什么问题? –

回答

0

考虑让save功能阵中的一员,并根据需要重载它。您可能会发现C++ 11的std::enable_if功能非常有用,只允许您的代码准备好的类型进行序列化。你的

fOut.write(m_array, m_size); 

不会从头开始工作,你需要自己实现它。截至本文撰写时,C++在这方面还不是Java。

+0

save()和load()是Array的成员函数。我在上面添加了一个注释。 – Phil

+0

就像我写的一样,和C一样,它主要是管理数据序列化的关注点(或者仅仅是你的类)。如果对有限数量的类型使用模板化,请手动为这些类型专门设置保存/加载功能。如果你想编写一个序列化其成员的通用容器,那么你遇到了麻烦。 'traits'的概念可能是有用的 - 你可能以这样的方式制作你的容器,使得'Array '的实例化将需要'T'来暴露适当的序列化接口。在后一种情况下,您只需在保存/加载Array时调用这些方法。 – iehrlich

+0

@Phil easy out是您在问题底部的for循环,并为您希望存储的所有自定义对象编写相应的“>>”和“<<”运算符。文字很粗糙,效率低下,但这很容易处理。 – user4581301

0

这最终成为我的解决方案。超载运营商< <和>>帮助我的班级在保存时保持灵活性。

我会发布下面的代码以防万一它对任何人有用。字符串保存看起来有些乱七八糟,可能会有所改进,但它会成功保存/加载长度,然后保存/加载std :: string。

std::ostream& operator<<(std::ostream& os, const Monster& obj) 
{ 
int length = obj.m_name.length() + 1; 
char buffer[1080]; 

strcpy_s(buffer, 1080, obj.m_name.c_str()); 

os << length; 
os.write(buffer, strlen(buffer) + 1); 
os << endl; 

os << obj.m_x << endl; 
os << obj.m_y << endl; 
os << obj.m_hp << endl; 

return os; 
} 

std::istream& operator>>(std::istream& is, Monster& obj) 
{ 
int length; 
char buffer[1080]; 

is >> length; 
is.readsome(buffer, length); 

std::string sBuffer(buffer, length); 
obj.m_name = sBuffer; 

is >> obj.m_x; 
is >> obj.m_y; 
is >> obj.m_hp; 

return is; 
}