2017-05-29 78 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; 
}