Увеличить сериализацию производного класса с закрытыми членами
Я пытаюсь сериализовать класс, скажем, B (в файле bh), который получен из другого, скажем, A (в файле ах). У обоих классов есть закрытые члены, и я хочу сериализовать оба с помощью библиотеки ускоренной сериализации. Сериализация / десериализация A работает до сих пор. Для того же самого для производного класса можно использовать
ar & boost::serialization::base_object<base_class>(*this);
когда используется навязчивый метод, но где его поместить в неинтрузивном случае (сохранить / загрузить / сериализовать или все три?)? И какой объект должен был использоваться вместо этого указателя?
В производительном коде я вывел класс немного сложнее, чем B. Там я получил ошибку компилятора, которую я не смог воспроизвести в этом небольшом примере. Сообщение компилятора (MSVC 2015, C2665, переведено на английский):
'boost:: serialization:: save': ни одна из перегрузок number1 не может преобразовать параметр number2 из типа 'type'
Ошибка на немецком языке:
Fehler C2665 "boost:: serialization:: save": Durch keine der 3 Überladungen konnten alle Argumenttypen konvertiert werden. CalorCLI c: \ boost_1_61_0 \ boost \ serialization \ split_free.hpp 45
Кто-нибудь может помочь?
Кодекс ах:
#pragma once
class A {
private:
int elemA;
public:
A() = default;
A(int elem) : elemA(elem) {};
virtual ~A() = default;
int getElemA() const { return elemA; }
void setElemA(int elem) {
elemA = elem;
}
};
Код BH:
#pragma once
#include "a.h"
class B : public A {
private:
int elemB;
public:
B() = default;
B(int elem) : elemB(elem) {};
virtual ~B() = default;
int getElemB() const { return elemB; }
void setElemB(int elem) { elemB = elem; }
};
Код основной программы:
// TestSerialization.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
//
#include <string>
#include <fstream>
#include <iostream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include "b.h"
#include "stdafx.h"
namespace boost {
namespace serialization {
template<class Archive>
void save(Archive & ar, const A & pA, const unsigned int version)
{
ar & pA.getElemA();
}
template<class Archive>
void load(Archive & ar, A & pA, const unsigned int version)
{
int n;
ar & n;
pA.setElemA(n);
}
template<class Archive>
void serialize(Archive & ar, A & pA, const unsigned int version)
{
boost::serialization::split_free(ar, pA, version);
}
template<class Archive>
void save(Archive & ar, const B & pB, const unsigned int version)
{
ar & pB.getElemB();
}
template<class Archive>
void load(Archive & ar, B & pB, const unsigned int version)
{
int n;
ar & n;
pB.setElemB(n);
}
template<class Archive>
void serialize(Archive & ar, B & pB, const unsigned int version)
{
boost::serialization::split_free(ar, pB, version);
}
}
}
int main()
{
A *objA= new A(747);
{
std::ofstream ofs("SavedA");
boost::archive::text_oarchive oa(ofs);
oa << objA;
}
{
A *objA1 = new A();
std::ifstream ifs("SavedA");
boost::archive::text_iarchive ia(ifs);
ia >> objA1;
}
B *objB = new B(747);
{
std::ofstream ofs("SavedB");
boost::archive::text_oarchive oa(ofs);
oa << objB;
}
{
B *objB1 = new B();
std::ifstream ifs("SavedB");
boost::archive::text_iarchive ia(ifs);
ia >> objB1;
}
return 0;
}
2 ответа
Во-первых, справедливое предупреждение о квази-классах (PDF). Они враги инкапсуляции и путают ООП.
Затем позвольте мне ответить на два ваших вопроса очень быстро и продолжить, чтобы показать мой взгляд на это:
Q. где поместить это в ненавязчивом случае (сохранить / загрузить / сериализовать или все три?)?
Либо в
serialize
ИЛИ в обоихsave
а такжеload
(если у вас есть разделенные реализации)В. Какой объект должен использоваться вместо указателя this?
Тот же объект. Если вы делаете функцию-член
serialize
this
указывает на тот же объект, что и переданная свободная функция в качестве второго аргумента. Просто используйте этот объект.
Мой дубль
Теперь позвольте мне сослаться на мой ответ, чтобы получить личные данные членов для неинтрузивного ускорения сериализации C++
Вот демонстрация идеи, предложенной Таннером в его комментарии
ах
#pragma once class A { private: int elemA; public: A(int elem = 0) : elemA(elem) {}; virtual ~A() = default; int getElemA() const { return elemA; } void setElemA(int elem) { elemA = elem; } };
ЬН
#pragma once #include "a.h" class B : public A { private: int elemB; public: B(int elem = 0) : A(42), elemB(elem) {}; int getElemB() const { return elemB; } void setElemB(int elem) { elemB = elem; } };
main.cpp
#include <string> #include <sstream> #include <iostream> #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> #include <boost/serialization/base_object.hpp> #include <boost/serialization/export.hpp> #include "b.h" BOOST_CLASS_EXPORT(A) BOOST_CLASS_EXPORT(B) namespace privates { template <typename Key, typename Key::type PointerToMember> struct store { friend typename Key::type get(Key) { return PointerToMember; } }; struct elemA { typedef int A::*type; friend type get(elemA); // ADL-enable }; struct elemB { typedef int B::*type; friend type get(elemB); // ADL-enable }; template struct store<elemA, &A::elemA>; template struct store<elemB, &B::elemB>; } // namespace privates auto& getElemA(A& instance) { return instance.*(get(privates::elemA())); } auto& getElemB(B& instance) { return instance.*(get(privates::elemB())); } namespace boost { namespace serialization { template<class Archive> void serialize(Archive & ar, A& v, unsigned) { ar & getElemA(v); } template<class Archive> void serialize(Archive & ar, B& v, unsigned) { ar & base_object<A>(v) & getElemB(v); } } } template <typename T> void run_tests() { std::stringstream ss; { A *obj= new T(747); boost::archive::text_oarchive oa(ss); oa << obj; delete obj; } std::cout << ss.str() << "\n"; { A *obj = nullptr; boost::archive::text_iarchive ia(ss); ia >> obj; delete obj; } } int main() { run_tests<A>(); run_tests<B>(); }
Обратите внимание, что это упрощает некоторые вещи и, по крайней мере, устраняет утечки памяти, когда не было исключений.
Выход в прямом эфире на WandBox
22 serialization::archive 15 0 1 0
0 747
22 serialization::archive 15 1 1 B 1 0
0 1 0
1 42 747
Теперь я понял: неинтрузивная сериализация (текстовый формат) со структурой стиля pimpl, как описано в параграфе 3, позволяет большинству членов закрываться и сокращает накладные расходы на методы get/set. XML все еще открыт - получил ошибки компилятора C2664 и C2789 в Visual Studio 2015. Также может быть интересным json...