我有一段代码,其中定义了以下类:Base
,Derived
,Contaienr
。
Derived
显然继承了Base
,而Container
包含Base
个共享指针的向量,该指针可以是Base
和{{1}的指针}。
我想序列化Derived
,以便将向量的元素分别序列化为Container
和Base
,但似乎不起作用。
这是我的测试代码:
Derived
运行程序时,我打印#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/export.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <sstream>
/// Base class ///
class Base {
public:
using Ptr = std::shared_ptr<Base>;
public:
void setDouble(double d) {
m_d = d;
}
void setInteger(int c) {
m_c = c;
}
double getDouble() const {
return m_d;
}
int getInteger() const {
return m_c;
}
private:
double m_d;
int m_c;
};
/// Derived class from Base ///
class Derived : public Base {
public:
using Ptr = std::shared_ptr<Derived>;
public:
void setString(const std::string& s) {
m_s = s;
}
const std::string& getString() const {
return m_s;
}
private:
std::string m_s;
};
/// Container of base class pointers ///
class Container {
public:
void addData(Base::Ptr data) {
m_data.push_back(data);
}
const std::vector<Base::Ptr>& getDataVector() const {
return m_data;
}
private:
std::vector<Base::Ptr> m_data;
};
BOOST_SERIALIZATION_SPLIT_FREE(Base)
BOOST_SERIALIZATION_SPLIT_FREE(Derived)
BOOST_SERIALIZATION_SPLIT_FREE(Container)
BOOST_CLASS_EXPORT_GUID(Derived, "Derived")
namespace boost {
namespace serialization {
/// Serialization of base class ///
template<class Archive>
void save(Archive& ar, const Base& m, unsigned int) {
auto d = m.getDouble();
auto i = m.getInteger();
ar& make_nvp("doublevalue", d);
ar& make_nvp("intvalue", i);
}
template<class Archive>
void load(Archive& ar, Base& m, unsigned int) {
double d;
int i;
ar& make_nvp("doublevalue", d);
ar& make_nvp("intvalue", i);
m.setDouble(d);
m.setInteger(i);
}
/// serialization of derived class ///
template<class Archive>
void save(Archive& ar, const Derived& m, unsigned int) {
ar& make_nvp("base", base_object<const Base>(m));
ar& make_nvp("stringvalue", m.getString());
}
template<class Archive>
void load(Archive& ar, Derived& m, unsigned int) {
std::string s;
ar& make_nvp("base", base_object<Base>(m));
ar& make_nvp("stringvalue", s);
m.setString(s);
}
/// serialization of container class ///
template<class Archive>
void save(Archive& ar, const Container& m, unsigned int) {
ar& make_nvp("data", m.getDataVector());
}
template<class Archive>
void load(Archive& ar, Container& m, unsigned int) {
std::vector<Base::Ptr> data;
ar& make_nvp("data", data);
for (const auto& it : data) {
m.addData(it);
}
}
}
} // namespace boost::serialization
int main(int argc, char *argv[]) {
// Initialize container
Container container;
auto baseObj = std::make_shared<Base>();
baseObj->setDouble(4.3);
baseObj->setInteger(6);
auto derivedObj = std::make_shared<Derived>();
derivedObj->setDouble(1.1);
derivedObj->setInteger(2);
derivedObj->setString("string in derived");
container.addData(baseObj);
container.addData(derivedObj);
// Print serialization of Base
std::stringstream basess;
boost::archive::xml_oarchive baseoa{basess};
baseoa << boost::serialization::make_nvp("baseclass", baseObj);
std::cout << basess.str() << std::endl;
// Print serialization of Derived
std::stringstream derivedss;
boost::archive::xml_oarchive derivedoa{derivedss};
derivedoa << boost::serialization::make_nvp("derivedclass", derivedObj);
std::cout << derivedss.str() << std::endl;
// Print serialization of Container
std::stringstream containerss;
boost::archive::xml_oarchive containeroa{containerss};
containeroa << boost::serialization::make_nvp("containerclass", container);
std::cout << containerss.str() << std::endl;
return 0;
}
的序列化,它是baseObj
的共享指针:
Base
这似乎是正确的,因为我在基类中同时定义了<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="17">
<baseclass class_id="0" tracking_level="0" version="1">
<px class_id="1" tracking_level="1" version="0" object_id="_0">
<doublevalue>4.29999999999999982e+00</doublevalue>
<intvalue>6</intvalue>
</px>
</baseclass>
和doublevalue
。
然后我打印intvalue
的序列化,它是derivedObj
的共享指针:
Derived
由于我拥有基类数据以及派生类的<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="17">
<derivedclass class_id="0" tracking_level="0" version="1">
<px class_id="1" tracking_level="1" version="0" object_id="_0">
<base class_id="2" tracking_level="1" version="0" object_id="_1">
<doublevalue>1.10000000000000009e+00</doublevalue>
<intvalue>2</intvalue>
</base>
<stringvalue>string in derived</stringvalue>
</px>
</derivedclass>
,因此似乎可以按预期工作。
现在,如果我将两个指针都放在stringvalue
的{{1}}中,则期望正确地序列化std::vector<std::shared_ptr<Base>>
和Container
。相反,这是输出:
baseObj
向量的两个元素都被序列化为derivedObj
指针。
我已尝试按照文档中的建议使用<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="17">
<containerclass class_id="0" tracking_level="0" version="0">
<data class_id="1" tracking_level="0" version="0">
<count>2</count>
<item_version>1</item_version>
<item class_id="2" tracking_level="0" version="1">
<px class_id="3" tracking_level="1" version="0" object_id="_0">
<doublevalue>4.29999999999999982e+00</doublevalue>
<intvalue>6</intvalue>
</px>
</item>
<item>
<px class_id_reference="3" object_id="_1">
<doublevalue>1.10000000000000009e+00</doublevalue>
<intvalue>2</intvalue>
</px>
</item>
</data>
</containerclass>
宏,但似乎不起作用。
我还尝试了this post中提出的解决方案,方法是注释Base
并在BOOST_CLASS_EXPORT_GUID(Derived, "Derived")
的序列化中使用BOOST_CLASS_EXPORT_GUID(Derived, "Derived")
,但问题仍然存在:
register_type
如何正确序列化存储在Container
共享指针向量中的/// serialization of container class ///
template<class Archive>
void save(Archive& ar, const Container& m, unsigned int) {
ar.template register_type<Derived>();
ar& make_nvp("data", m.getDataVector());
}
template<class Archive>
void load(Archive& ar, Container& m, unsigned int) {
ar.template register_type<Derived>() ;
std::vector<Base::Ptr> data;
ar& make_nvp("data", data);
for (const auto& it : data) {
m.addData(it);
}
}
类?
答案 0 :(得分:1)
在派生类的情况下,问题的一部分可能是std::shared_ptr
的行为。因此,有必要仅用普通指针替换std::shared_ptr
。
struct A
{
};
struct B : public A
{
};
void fun(const std::shared_ptr<A>& base)
{
std::cout << typeid(base).name() << std::endl;
}
int main(int argc, char *argv[]) {
auto a=std::make_shared<A>();
auto b=std::make_shared<B>();
std::cout << typeid(a).name() << std::endl;
std::cout << typeid(b).name() << std::endl;
fun(a);
fun(b);
}
这会给您带来希望第二行和第四行相等的地方:
class std::shared_ptr<struct A>
class std::shared_ptr<struct B>
class std::shared_ptr<struct A>
class std::shared_ptr<struct A>
第二点但不是很明显的一点是,您的基类应至少包含一个virtual function。您只需包含以下内容即可使析构函数成为虚拟函数:
virtual ~Base() {};
文档说:
事实证明,序列化的对象的类型取决于基类(在这种情况下为基类)是否是多语言的。如果base不是多态的,也就是说它没有虚函数,那么base类型的对象将被序列化。任何派生类中的信息都将丢失。如果这是期望的(通常是不需要的),则无需其他努力。
在我用简单的指针替换了所有shared_ptr
并添加了虚拟析构函数之后,结果就如所期望的,最后一部分得到以下输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="17">
<containerclass class_id="0" tracking_level="0" version="0">
<data class_id="1" tracking_level="0" version="0">
<count>2</count>
<item_version>0</item_version>
<item class_id="2" tracking_level="1" version="0" object_id="_0">
<doublevalue>4.29999999999999982e+00</doublevalue>
<intvalue>6</intvalue>
</item>
<item class_id="3" class_name="Derived" tracking_level="1" version="0" object_id="_1">
<base object_id="_2">
<doublevalue>1.10000000000000009e+00</doublevalue>
<intvalue>2</intvalue>
</base>
<stringvalue>string in derived</stringvalue>
</item>
</data>
</containerclass>