使用私有成员增强派生类的序列化

时间:2017-08-26 09:26:41

标签: c++ serialization boost derived-class

我尝试序列化一个类,比如B(在文件b.h中),它是从另一个派生的,比如A(在文件a.h中)。这两个类都有私有成员,我想用非侵入式的boost序列化序列化这两个类。到目前为止,A的序列化/反序列化确实有效。对于派生类的相同,可以使用

ar & boost::serialization::base_object<base_class>(*this);

当使用侵入式方法时,但是将它放在非侵入式的情况下(保存/加载/序列化还是全部三种?)? 必须使用哪个对象代替这个指针?

在生产代码中,我派生的类比B更复杂。我得到了一个编译器错误,我无法在这个小例子中重现。编译器消息(MSVC 2015,C2665,翻译成英文):

  

'boost :: serialization :: save':没有number1重载可以从类型'type'转换参数number2

德语错误:

  

Fehler C2665“boost :: serialization :: save”:Durch keine der3Überladungenkontentenalle Argumenttypen konvertiert werden。 CalorCLI c:\ boost_1_61_0 \ boost \ serialization \ split_free.hpp 45

有人可以帮忙吗?

a.h的代码:

#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; 
    }

};

b.h的代码:

#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 个答案:

答案 0 :(得分:1)

首先,关于Quasi-Classes (PDF)的公正警告。他们是封装的敌人并混淆OOP。

接下来,让我快速回答您的两个问题并继续展示我对此的看法:

  1.   

    问。将其置于非侵入式案例中(保存/加载/序列化或全部三种?)?

    serializesaveload中的serialize(如果您有拆分实施)

  2.   

    问。必须使用哪个对象来代替this指针?

    同一个对象。如果你做成员函数this #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; } }; 指向同一个对象,则传递自由函数作为第二个参数。只需使用该对象。

  3. 我的选择

    现在,让我参考我对Get private data members for non intrusive boost serialization C++

    的回答

    以下是Tanner在his comment

    中提出的想法的演示

    <强> Live On WandBox

    • A.H

      #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; }
      };
      
    • b.h

      #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>();
      }
      
    • 的main.cpp

      22 serialization::archive 15 0 1 0
      0 747
      
      22 serialization::archive 15 1 1 B 1 0
      0 1 0
      1 42 747
      

    注意它简化了一些事情,并且在没有例外时至少消除了内存泄漏。

    输出 Live On WandBox

    # Max Channels is the maximum number of channels to allow on the ordering
    # network. When set to 0, this implies no maximum number of channels. MaxChannels: 0
    

答案 1 :(得分:0)

现在我明白了:带有pimpl样式结构的非侵入式序列化(文本格式),如第3段here所述,让大多数成员都是私有的,并减少了get / set方法的开销。 xml仍处于打开状态 - 在Visual Studio 2015上遇到编译器错误C2664和C2789。此外,json可能很有趣......