У меня есть некоторые проблемы с форсированием сериализации при сериализации производного класса с помощью указателя базового класса. Мне нужна система, которая сериализует некоторые объекты по мере их поступления в систему, поэтому мне нужно сериализоваться с течением времени. Это не проблема, так как я могу открыть boost::archive::binary_oarchive
и сериализовать объекты, когда это необходимо. Быстро я заметил, что boost выполнял отслеживание объектов по адресу памяти, поэтому первая проблема заключалась в том, что разные объекты во времени, которые используют один и тот же адрес памяти, были сохранены как один и тот же объект. Это можно устранить, используя следующий макрос в требуемом производном классе:
BOOST_CLASS_TRACKING(className, boost::serialization::track_never)
Это отлично работает, но опять же, когда базовый класс не абстрактный, базовый класс не сериализуется должным образом. В следующем примере метод сериализации базового класса вызывается только один раз с первым объектом. В следующем случае boost предполагает, что этот объект был сериализован раньше, хотя объект имеет другой тип.
#include <iostream>
#include <fstream>
#include <boost/serialization/export.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/archive/archive_exception.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
using namespace std;
class AClass{
public:
AClass(){}
virtual ~AClass(){}
private:
double a;
double b;
//virtual void virtualMethod() = 0;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & a;
ar & b;
cout << "A" << endl;
}
};
//BOOST_SERIALIZATION_ASSUME_ABSTRACT(Aclass)
//BOOST_CLASS_TRACKING(AClass, boost::serialization::track_never)
class BClass : public AClass{
public:
BClass(){}
virtual ~BClass(){}
private:
double c;
double d;
virtual void virtualMethod(){};
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & boost::serialization::base_object<AClass>(*this);
ar & c;
ar & d;
cout << "B" << endl;
}
};
// define export to be able to serialize through base class pointer
BOOST_CLASS_EXPORT(BClass)
BOOST_CLASS_TRACKING(BClass, boost::serialization::track_never)
class CClass : public AClass{
public:
CClass(){}
virtual ~CClass(){}
private:
double c;
double d;
virtual void virtualMethod(){};
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & boost::serialization::base_object<AClass>(*this);
ar & c;
ar & d;
cout << "C" << endl;
}
};
// define export to be able to serialize through base class pointer
BOOST_CLASS_EXPORT(CClass)
BOOST_CLASS_TRACKING(CClass, boost::serialization::track_never)
int main() {
cout << "Serializing...." << endl;
{
ofstream ofs("serialization.dat");
boost::archive::binary_oarchive oa(ofs);
for(int i=0;i<5;i++)
{
AClass* baseClassPointer = new BClass();
// serialize object through base pointer
oa << baseClassPointer;
// free the pointer so next allocation can reuse memory address
delete baseClassPointer;
}
for(int i=0;i<5;i++)
{
AClass* baseClassPointer = new CClass();
// serialize object through base pointer
oa << baseClassPointer;
// free the pointer so next allocation can reuse memory address
delete baseClassPointer;
}
}
getchar();
cout << "Deserializing..." << endl;
{
ifstream ifs("serialization.dat");
boost::archive::binary_iarchive ia(ifs);
try{
while(true){
AClass* a;
ia >> a;
delete a;
}
}catch(boost::archive::archive_exception const& e)
{
}
}
return 0;
}
При выполнении этой части кода результат следующий:
Serializing....
A
B
B
B
B
B
C
C
C
C
C
Deserializing...
A
B
B
B
B
B
C
C
C
C
C
Таким образом, базовый класс только сериализуется один раз, хотя в производном классе явно указан флаг track_never. Существует два разных способа решения этой проблемы. Первый заключается в том, чтобы абстрагироваться базовым классом с помощью чистого виртуального метода и вызвать макрос BOOST_SERIALIZATION_ASSUME_ABSTRACT(Aclass)
, а второй - поставить флаг track_never также в базовый класс (прокомментированный в коде).
Ни одно из этих решений не отвечает моим требованиям, так как я хочу делать в будущем пунктуальную сериализацию состояния системы, для чего потребуются функции отслеживания для данного DClass, расширяющего A (не B или C), а также AClass не должен быть абстрактным.
Любые подсказки? Есть ли способ явно вызвать метод сериализации базового класса, избегая функции отслеживания в базовом классе (который уже отключен в производном классе)?