我正在尝试实现反序列化,其中映射到字段/成员仅在运行时已知(其复杂)。无论如何,我正在尝试做的事情如下:
Class A
{
public:
int a; // index 0
float b; // index 1
char c; // index 2
}
然后我有两个数组,一个是字段索引,另一个是表示类型的。然后我想迭代数组并从字节流写入字段。
很抱歉这个糟糕的描述,但我不知道如何在代码中实现它。任何想法将不胜感激!
答案 0 :(得分:1)
需要做很多问题和决定。最简单的方法是,每个字段可以保留一个偏移量A
,你可以打开类型并设置指向字段的指针。例如 - 假设输入流中有一个int16_t
个编码字段编号,不费力地使用static_cast<>
等,这样做更好一些,并假设一个0字段编号输入终止符。
A a;
char* pa = (char*)&a;
char* p_v = (char*)&input_buffer;
...
while ((field_num = *(int16_t)p_v) && (p_v += sizeof(int16_t)))
switch (type[field_num])
{
case Int32:
*(int32_t*)(p_a + offset[field_num]) = *(int32_t*)(p_v);
p_v += sizeof(int32_t);
break;
...
}
您可能需要考虑使用,例如ntohl()
等来处理字节序转换。
答案 1 :(得分:1)
我想不出一种能够在运行时给定索引的字段地址的语言结构。如果您可以使用“type”数组来实际包含字段大小,那么您可以执行以下操作:
istream &in = <get it somehow>;
size_t *field_size = <get it somehow>;
size_t num_of_fields = <get it somehow>;
A a;
char *ptr = reinterpret_cast<char *>(&a);
for (int i = 0; i < num_of_fields; i++)
{
in.read(ptr, field_size[i]);
ptr += field_size[i];
}
请注意,如果您的类很简单并且没有任何虚函数成员,那么这将是真的 (或继承自这样的一类)。如果是这种情况,您最好包括一个虚拟成员 获取字段在类中开始的字节偏移量:
class A
{
int __dummy; /* must be the first data member in the class */
...
<rest of your class definition here>
};
现在更改 ptr 的初始化,如下所示:
ptr = reinterpret_cast<char *>(&a) + offsetof(A, __dummy);
此代码的另一个隐含假设是,运行此代码的计算机和接收序列化数据的计算机的机器字节顺序相同。如果没有,那么您将需要转换从流中读取的数据的字节顺序。此转换当然取决于类型,但每个字段可以有另一个转换函数数组。
答案 2 :(得分:1)
是的,你可以,但是在做这件事时你需要注意两件事。
首先确保你从(const char*)&A.a
开始写作,因为所有编译器在对象的开头附加了与你没有真正关系的东西(例如,visualc将vtable放在那里)你就不会如果你从对象的地址开始写你认为你是什么。
其次,在声明需要写入磁盘的任何类之前,您可能想要执行#pragma pack(1)
,因为编译器通常会对类成员进行对齐以使DMA传输更有效,并且您可能最终也遇到问题
在它的动态部分,如果为每个字段组合创建一个类定义是可以接受的,那么可以这样做,否则你最好在你的类中包含一个哈希表,通过将键值对写入文件来序列化/反序列化其内容
答案 3 :(得分:-1)
让编译器执行此操作:
编写operator>>
函数。