我有可序列化的基类User:
class User
{
public:
User();
std::string GetLogin() const;
void SetLogin(std::string login);
protected:
std::string mLogin;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & mLogin;
}
};
这个类可以被其他类继承,比如
class UserA : public User
{
UserA();
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & boost::serialization::base_object<User>(*this);
ar & mIsSomething;
}
bool mIsSomething = true;
}
为了处理这些用户,我有一个"管理器"类,其中包含一个用户向量:
class Manager
{
public:
bool Add(User user);
bool Remove(unsigned int index);
private:
std::vector<User> mUsers;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & mUsers;
}
};
因此,我的经理可以用UserA或UserB来填充(决不能同时使用两者)。当我从Manager
中检索一个元素时,我只需将它强制转换回正确的子类。这部分工作正常。
但是,当我想序列化Manager
类时,Boost显然不知道我要序列化哪种类型的User
,并且子类中的额外字段没有序列化。
我的解决方案是什么
我的设计完全错了吗
我应该把我的经理课专门用于这样的课程吗?
class Manager
{
bool Add(UserA user);
bool Add(UserB user);
private:
std::vector<UserA> mUsersA;
std::vector<UserB> mUsersB;
}
因此,我的经理可以填写UserA或UserB(绝不能同时填写两者)
不,不能:
std::vector<User> mUsers;
按值存储CCD_ 4对象。请参见什么是对象切片?。
思想
我还建议将Manager模板化到具体的用户类型上,但看看您如何使用实际的类型层次结构,您可能希望实际使用运行时多态性。
由于序列化多态类型在某种程度上更为复杂,所以让我向您展示一个示例。
它还展示了如何在动态存储对象的同时使用例如boost::ptr_vector<>
来管理对象。
在Coliru上直播1
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/ptr_container/serialize_ptr_vector.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
class User
{
public:
User() {};
virtual ~User() {}
std::string GetLogin() const;
void SetLogin(std::string login);
protected:
std::string mLogin;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & mLogin;
}
};
class UserA : public User
{
public:
UserA() {};
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & boost::serialization::base_object<User>(*this);
ar & mIsSomething;
}
bool mIsSomething = true;
};
class UserB : public User
{
public:
UserB() {};
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & boost::serialization::base_object<User>(*this);
ar & mIsSomethingElse;
}
bool mIsSomethingElse = true;
};
template <typename Tag>
class UserGen : public User
{
public:
UserGen() {};
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & boost::serialization::base_object<User>(*this);
ar & mIsGen;
}
bool mIsGen = true;
};
struct GenA;
struct GenB;
struct GenC;
BOOST_CLASS_EXPORT(User)
BOOST_CLASS_EXPORT(UserA)
BOOST_CLASS_EXPORT(UserB)
BOOST_CLASS_EXPORT(UserGen<GenA>)
BOOST_CLASS_EXPORT(UserGen<GenB>)
BOOST_CLASS_EXPORT(UserGen<GenC>)
#include <boost/type_index.hpp>
class Manager
{
public:
template <typename User>
bool Add(User const& user) {
mUsers.push_back(new User(user));
return true; // FIXME?
}
bool Remove(unsigned int index) {
if (mUsers.size() > index) {
mUsers.erase(mUsers.begin()+index);
return true;
}
return false;
}
void dump() const {
for (auto& u : mUsers) {
std::cout << "user of type " << boost::typeindex::type_id_runtime(u) << "n";
}
}
private:
boost::ptr_vector<User> mUsers;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & mUsers;
}
};
#include <sstream>
#include <iostream>
int main() {
std::stringstream ss;
{
Manager man;
man.Add(UserA{});
man.Add(UserB{});
man.Add(UserGen<GenA>{});
man.Add(UserGen<GenB>{});
man.Add(UserGen<GenC>{});
boost::archive::text_oarchive oa(ss);
oa << man;
}
{
boost::archive::text_iarchive ia(ss);
Manager man;
ia >> man;
man.dump();
}
}
打印
user of type UserA
user of type UserB
user of type UserGen<GenA>
user of type UserGen<GenB>
user of type UserGen<GenC>
<小时>1链接boost 1.59在某种程度上失败了:(感谢@m.s计算出1.58仍然有效
小时>