我需要一种方法来序列化不同类型的对象(但是从同一个类派生的类型),然后将它们反序列化为包含派生类的基类的指针。例如:
#include<iostream>
#include<fstream>
class One
{
public:
int a;
virtual void Func()
{
}
};
class One1: public One
{
char s[128];
void Func1(int l)
{
std::cout<<l<<'\n';
}
void Func()
{
Func1(156);
}
};
int main()
{
One* x = new One1;
x->Func();
char* y=(char*)x;
delete x;
/*std::ofstream out("test11.txt",std::ofstream::out | std::ofstream::trunc);
out.write(y,sizeof(One1));
out.close();
std::ifstream in("test11.txt",std::ifstream::in);
char* y1=new char[sizeof(One1)];
in.read(y1,sizeof(One1));*/
One* z=(One*)y/*1*/;
z->Func();
return 0;
}
此代码输出
156
156
但是当我取消注释注释时(当我尝试将文件写入对象的 char 表示并从该文件读取时),程序输出156
并结束试图执行z->Func();
时出现分段错误。我检查了变量y
的内容与y1
的内容不同。为什么呢?
这个问题的原因是什么?我如何解决它(可能通过使用一些特殊的库)?
答案 0 :(得分:2)
您不能简单地通过将多态对象转换为字节数组来编写多态对象,然后通过二进制read
加载它们。具有虚函数的类存储指向vtable中的实现的指针。转储派生类的实例将导致转储存储在vtable中的指针,显然,在再次运行程序之后,它不必是有效的指针。之后访问它很可能会产生分段错误。
如果您真的想使用 easy 方式(直接读取和写入字节),请使用POD类。
虽然以上是答案中最重要的部分(因为它会完全改变你的程序),但还有其他一些事情需要加以强调。命令:
char* y=(char*)x;
创建一个char
指针,指向x
的地址。 不会复制对象。因此,当你以后做:
delete x;
指向y
的指针变为无效。当您稍后尝试将其写入文件时:
std::ofstream out("test11.txt",std::ofstream::out | std::ofstream::trunc);
out.write(y,sizeof(One1));
您可以访问不属于您的内存。至少不再这样了,因为你特别说你不需要它,通过早先打电话给delete
。