如何解决模板问题以将不同的数据类型保存到文件?

时间:2010-07-17 17:50:13

标签: c++ templates stl

我在使用模板时遇到了一个新问题。这是我最近阅读的一本书中的一点创意,扩展了他的想法,并且它有这个代码示例。

假设你有一个模板化的Array2D类。你有这个方法(Array2D :: WriteFile):

    bool WriteFile( const char* p_filename )
{
    FILE* outfile = 0;
    int written = 0;

    // open the file
    outfile = fopen( p_filename, "wb" );

    // return if it couldn't be opened
    if( outfile == 0 )
        return false;

    // write the array and close thef ile
    written = fwrite( m_array, sizeof( Datatype ), m_size, outfile );
    fclose( outfile );

    // if we didn't write the number of items we expected,
    // return failure
    if( written != m_size )
        return false;

    // return success.
    return true;
}

这适用于基本数据类型,如int,char,float等。但是,如果你有一点创意,使数据类型成为复合变量,如SLinkedList(单链表)。它将是Array2D。然后你调用旧的WriteFile()函数。它会保存它,但你只保存了一个节点。剩下的节点都被遗忘了,永远不会回来。

我脑子里浮现出一些想法: 在你的截止日期前,看着时钟旋转你的拇指。 2.使Array2D :: WriteFile()成为一个纯虚函数,使更具体的类以它应该的方式保存它。但是我不能在其他独立的情况下单独使用Array2D。 3.编写一个函数指针来保存,但我认为它可能会变得混乱,因为你不知道你传入的数据是什么时候到来。它可能会根据数据类型而有所不同。 4.也许,实现模板不是解决方案。

模板类没有根据数据类型为我解决每种情况。那么您认为什么是好的解决方案?谢谢!

3 个答案:

答案 0 :(得分:4)

您的对象需要可序列化。当你试图以这种方式写出链表的头部时,想想实际发生的事情 - 当然它只是写第一个节点; write函数不知道它正在写什么,所以它不知道如何遵循指向下一个节点的指针并写出来。它只是看到位并将它们写出来直到当前对象的结尾,在这种情况下只是第一个节点。

序列化基本上意味着,对于每个非平凡类型,编写一个方法,将该类型打包成适合写出的平面字节流(理想情况下也是读取该格式的第二种方法)。

现在,您的问题被标记为C ++,但您编写的代码非常类似于C语言。在C ++中实现可序列化对象的常规方法是使用<<参数覆盖std::ostream&运算符并返回值,例如

 std::ostream& MyType::operator<< (std::ostream& out)
 {
    // Here, write out the logical contents of this object in whatever format you
    // feel is appropriate (keep in mind endianness and floating point representation
    // if you want portability!)
    return out << this->field1 << this->field2 << this->field3;
 }

对称

 std::istream& MyType::operator>> (std::istream& in)
 {
    // Here, read in the logical contents of this object in the same format
    return in >> this->field1 >> this->field2 >> this->field3;
 }

现在,您可以这样做:

 MyType t;
 std::ofstream outputFile("myoutputfile.dat");

 outputFile << t;

请注意,这种覆盖流运算符的方法意味着,例如,如果MyType::field2本身就是一个复杂的对象,只要它,它仍然可以在上面的代码中正确地序列化和反序列化。 流操作符被覆盖。

但是如果你想继续使用原始帖子中的C风格文件I / O,事情就不会那么干净了。如果您的代码确实应该是C ++,那么您应该使用iostream库来执行文件I / O.

答案 1 :(得分:2)

你可以简单地使用iostreams等价物。而不是使用作为C函数的fwrite并且仅适用于C数据类型,而是使用可以重载并专门用于自定义类型的C ++等价物。

std::ofstream file(p_filename);
file << m_array;

operator <<适用于所有内置类型,对于自定义类型,您可以自行定义。

答案 2 :(得分:1)

我的直接反应是,您正在查看之前已经查看过(并且至少在某种程度上已经解决过)的问题。是的,它仍然可以使用相当多的模板。我会看一下std::copystd::ostream_iterator以及一些序列化库,例如Boost serialization