c++ - 使用虚拟方法将对象写入和读取到二进制文件

标签 c++

您好,我目前正在开发一个模拟程序,该程序会在请求时尝试将程序的状态(变量和对象)保存到二进制文件中,以便它可以在需要时恢复模拟。

请注意:我知道这在不同的 CPU 架构之间不兼容,但这绝对没问题!

在将具有虚方法的对象写入文件然后尝试将其读回之前,一切似乎都运行良好。

下面的代码说明了这个问题:

header.hpp

using namespace std;

class parent
{
        public:
                int mValue;
                virtual string getName() =0;
                virtual size_t getSize() =0;

                parent(int value) : mValue(value)
                {

                }
};

class bob : public parent
{
        public:
                bob(int value) : parent(value)
                {

                }

        string getName();
        size_t getSize() { return sizeof(bob); }
};

string bob::getName()
{
        string name("bob");
        return name;
}

class sarah : public parent
{
        public:
                sarah(int value) : parent(value)
                {

                }

        string getName();
        size_t getSize() { return sizeof(sarah); }
};

string sarah::getName()
{
        string name("sarah");
        return name;
}

写.cpp

#include <iostream>
#include <fstream>
#include <string>
#include "header.hpp"

int main()
{
    sarah girl(1);
    bob boy(2);

    parent* child1 = &girl;
    parent* child2 = &boy;

    cout << "Created child called " << child1->getName() << endl;
    cout << "Created child called " << child2->getName() << endl;

    //save sarah and bob to a binary file
    ofstream file("temp.bin", ios::binary | ios::trunc);

    if(!file.is_open())
            return 1;

    //format <size><data><size><data>....
    size_t tempSize=0;

    //write child1
    tempSize = child1->getSize();
    file.write( (char*) &tempSize,sizeof(size_t));

    file.write( (char*) child1,tempSize);

    tempSize = child2->getSize();
    file.write( (char*) &tempSize,sizeof(size_t));

    file.write( (char*) child2,tempSize);

    file.close();

    return 0;
}

读取.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include "header.hpp"

int main()
{

    //read sarah and bob from a binary file
    ifstream file("temp.bin", ios::binary);

    //format <size><data><size><data>....
    size_t tempSize=0;

    //get size of child1
    file.read( (char*) &tempSize, sizeof(size_t));

    //allocate memory for child1
    parent* child1= (parent*) malloc(tempSize);
    //read child 1 back
    file.read( (char*) child1,tempSize);

    //get size of child2
    file.read( (char*) &tempSize, sizeof(size_t));

    //allocate memory for child2
    parent* child2= (parent*) malloc(tempSize);
    //read child 2 back
    file.read( (char*) child2,tempSize);

    file.close();

    //Using virtual methods causes SEGFAULT
    cout << "Recreated child" << child1->getName() << endl;
    cout << "Recreated child" << child2->getName() << endl;



    return 0;
}

构建和运行如下:

g++ -g write.cpp -o write ; ./write
g++ -g read.cpp -o read  ; ./read

当我单步执行 gdb 中的读取程序时,我注意到问题似乎出在 v 表指针上。当我在读取程序中重新创建“sarah”(child1) 时,v 表指针是写入程序存在的指针,而不是读取程序。因此可以推测,写入程序中“sarah”的这个 v-table 指针指向了导致 SEGFAULT 的无效内存区域。

我有两个问题:

  • 是否可以在“写入”程序中将 v 表指针信息保存到二进制文件,以便在“正确”程序中完美地重新创建我的对象,而无需求助于诸如 Boost::之类的库:序列化或 POST++ 来为我处理这个问题?

  • 如果不可能……或者如果它相当复杂,那么我将不得不添加一个构造函数和一个“saveState()”方法(可以分别作用于 ifstream 和 ofstream 对象)以便每个类(在本例中为 sarah 和 bob)处理从二进制文件中保存和读取其状态。这个问题是我有多个派生自类“parent”的类,所以我需要一种方法让“read”程序计算出从读取二进制文件调用哪个构造函数。

    我想出了一种方法来确定调用哪个构造函数。这将是

  • 为每个派生自“parent”的类分配一个唯一的 ID

  • 在“write”程序中为二进制文件添加唯一ID
  • 在“读取”程序中读取每个唯一的 ID,然后使用 switch 语句调用相关的构造函数。

    这不是很优雅,因为每次我添加一个派生自“parent”的新类时,我都必须给它一个 ID 并将它添加到“read”中的 switch 语句。有更好的方法吗?

感谢阅读,我知道我的帖子很长!

最佳答案

每次编译程序时,它都会将函数放在内存中的不同位置。此外,在某些操作系统配置上,功能甚至可能会在您每次重新启动程序时移动。这是一种称为地址空间布局随机化的安全功能。如果您确定您将从完全相同的二进制文件读取和写入对象,您可能可以通过将读取和写入函数在同一个程序中,而不是两个不同的程序中。然而,即使这样也充满了问题,如果您进行更改并重新编译,您将无法再读取旧数据文件。

Boost::Serialization 是专门为避免所有这些问题而创建的,包括我敢肯定的一些我什至不知道的问题,它经过了大量的同行评审和测试,并且拥有极其自由的许可作为奖励。使用这样的库不是“诉诸”的东西,而是一种特权。

关于c++ - 使用虚拟方法将对象写入和读取到二进制文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5126247/

相关文章:

c++ - 未解析的外部符号,但我包含了带有函数定义的文件?

c++ - Qt5:派生QQuickWidget以获取小部件

C++冒泡排序动态分配数组

c++ - 将 TableView 中的 CheckBox 选中状态绑定(bind)到自定义模型属性

c++ - 需要从枚举(类)到 std::binary_function 的映射

c++ - 为其他范围内的指针创建一个实例

c++ - DirectShow - 如何确定流是否有效(C++)

C++相减函数相互形成

c++ - SDL 错误 Visual Studio 2013

c++ - 使用开源Clamav引擎