我对boost序列化有点问题。有许多示例显示如何通过简单地使用BOOST_CLASS_EXPORT和BOOST_CLASS_EXPORT_IMPLEMENT来序列化通过基类指针的派生类指针。这工作正常,完全没有问题。
但是,我不想序列化一个指针,因为另一侧的反序列化应该再次在指针上,然后,boost会创建一个序列化对象的新实例。
我可以序列化一个解除引用的指针,然后在没有问题的情况下在现有对象实例上再次反序列化,并且不会创建新的实例。但是,当解除引用的指针位于基类之上时,在对指针进行序列化时,派生类不会按预期序列化。
工作示例:
Class A;
Class B : public A;
A* baseClass = new B();
ar << baseClass // works perfectly
不工作的例子:
Class A;
Class B : public A;
A* baseClass = new B();
ar << *baseClass; // only A is serialized
我可以通过对派生类进行简单的序列化来实现它,如:
B* derivedClass = new B();
ar << *derivedClass; // works fine
但是我在结构中的所有引用都是基类类型。此外,我无法序列化指针,因为我不需要在反序列化时实例化新的objetcs,只在现有实例上“覆盖”内容。
我试图序列化指针并尝试对现有实例进行反序列化,但这不能正常工作。当我说对现有实例进行反序列化时,我的意思是:
A* baseClass = new B();
// baseClass is used in the program and in a given moment, its contents must be overwrite, so:
ar >> *baseClass;
正如我所说,反序列化时我不需要新的baseClass实例。那么,有没有办法让这个工作?
答案 0 :(得分:1)
我遇到了同样的问题!所以我查看了boost的文档,它提供了解决问题的方法,我可以定义一个D类来管理派生对象,并使用ar.register_type
来差异abc类,就像这样:
class base {
...
};
class derived_one : public base {
...
};
class derived_two : public base {
...
};
main(){
...
base *b;
...
ar & b;
}
保存b时应保存哪种对象?加载b时应该创建哪种对象?它应该是类derived_one,derived_two还是base?
的对象事实证明,序列化的对象类型取决于基类(在这种情况下是基础)是否是多态的。如果base不是多态的,即如果它没有虚函数,那么将序列化类型base的对象。任何派生类中的信息都将丢失。如果这是期望的(通常不是),则不需要其他任何努力。
如果基类是多态的,则序列化最派生类型的对象(在本例中为derived_one或derived_two)。将序列化哪种类型的对象的问题(几乎)由库自动处理。
系统在第一次对该类的对象进行序列化时“注册”归档中的每个类,并为其分配序号。下次该类的对象在同一存档中序列化时,此编号将写入存档中。因此,每个类都在归档中唯一标识。当读回存档时,每个新的序列号与正在读取的类重新关联。请注意,这意味着必须在保存和加载期间发生“注册”,以便在加载时构建的类 - 整数表与在save上构建的类 - 整数表相同。事实上,整个序列化系统的关键是始终以相同的顺序保存和加载事物。这包括“注册”。
main(){
derived_one d1;
derived_two d2:
...
ar & d1;
ar & d2;
// A side effect of serialization of objects d1 and d2 is that
// the classes derived_one and derived_two become known to the archive.
// So subsequent serialization of those classes by base pointer works
// without any special considerations.
base *b;
...
ar & b;
}
当读取b时,它前面是一个唯一的(到存档)类标识符,该标识符先前与类derived_one或derived_two相关。
如果派生类未按上述方式自动“注册”,则在调用序列化时将抛出unregistered_class异常。
这可以通过显式注册派生类来解决。所有归档都是从实现以下模板的基类派生的:
template<class T>
register_type();
所以我们的问题也可以通过写作来解决:
main(){
...
ar.template register_type<derived_one>();
ar.template register_type<derived_two>();
base *b;
...
ar & b;
}
请注意,如果序列化功能在保存和加载之间分配,则两个功能都必须包含注册。这是保持同步和保存相应负载所必需的。
你也可以使用:
#include <boost/serialization/export.hpp>
...
BOOST_CLASS_EXPORT_GUID(derived_one, "derived_one")
BOOST_CLASS_EXPORT_GUID(derived_two, "derived_two")
main(){
...
base *b;
...
ar & b;
} 宏BOOST_CLASS_EXPORT_GUID将字符串文字与类相关联。在上面的例子中,我们使用了类名的字符串呈现。如果此类“导出”类的对象通过指针序列化并以其他方式取消注册,则“导出”字符串将包含在归档中。稍后读取存档时,字符串文字用于查找应由序列化库创建的类。这允许每个类与其字符串标识符一起位于单独的头文件中。无需维护可能序列化的派生类的单独“预注册”。这种注册方法称为“密钥导出”。
也许对你有帮助!!有关详细信息,您可以看到:http://www.boost.org/doc/libs/1_54_0/libs/serialization/doc/index.html
答案 1 :(得分:1)
我想我明白了这个问题。当你这样做
ar >> *DerivedClass;
您正在将参考传递给operator<<
。现在,通过对基类的引用访问的对象没有正确序列化,正如我从Robert Ramey在Boost-users邮件列表中对this question的回答中收集的那样。虽然答案已经有好几年了,但我认为它仍然适用,因为如果你想到它,一个写的serialize
方法不是虚拟的(它们是模板,所以它们是cannot be virtual)。 / p>
因此,库必须使用特殊的东西来处理指针,但它并没有使用引用。我发现一个丑陋的解决方案是添加一对(虚拟)序列化函数,如下所示:
virtual myser(iarchive &ia) {ia >> *this;}
virtual myser(oarchive &oa) {oa << *this;}
其中iarchive
和oarchive
应替换为您想要的存档。这真的很糟糕,因为除了必须编写两个额外的函数之外,你必须明确地为所需的所有存档类型重载它们。不幸的是,我不知道更好的解决方案。