Увеличить сериализацию производного класса с закрытыми членами

Я пытаюсь сериализовать класс, скажем, 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). Они враги инкапсуляции и путают ООП.

Затем позвольте мне ответить на два ваших вопроса очень быстро и продолжить, чтобы показать мой взгляд на это:

  1. Q. где поместить это в ненавязчивом случае (сохранить / загрузить / сериализовать или все три?)?

    Либо в serialize ИЛИ в обоих save а также load (если у вас есть разделенные реализации)

  2. В. Какой объект должен использоваться вместо указателя this?

    Тот же объект. Если вы делаете функцию-член serializethis указывает на тот же объект, что и переданная свободная функция в качестве второго аргумента. Просто используйте этот объект.

Мой дубль

Теперь позвольте мне сослаться на мой ответ, чтобы получить личные данные членов для неинтрузивного ускорения сериализации C++

Вот демонстрация идеи, предложенной Таннером в его комментарии

Жить на WandBox

  • ах

    #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...

Другие вопросы по тегам