使用私有成员促进派生类的序列化

使用私有成员促进派生类的序列化

本文介绍了使用私有成员促进派生类的序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试序列化一个类,例如B(在文件b.h中),该类派生自另一个类,例如A(在文件a.h中).这两个类都有私有成员,我想以非侵入方式使用boost序列化库对两者进行序列化.到目前为止,A的序列化/反序列化确实有效.对于相同的派生类,将使用

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

使用侵入式方法时,但是在非侵入式情况下将其放置在何处(保存/加载/序列化还是全部三个?)? 并且必须使用什么对象代替此指针?

在生产性代码中,我派生的类比B要复杂一些.我遇到了一个编译器错误,在这个小例子中无法重现.编译器消息(MSVC 2015,C2665,英语翻译):

德语错误:

有人可以帮忙吗?

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;
}
解决方案

首先,对准类(PDF).它们是封装的敌人,并混淆了OOP.

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

  1. serialize中还是在saveload中(如果您有分开的实现)

  2. 同一对象.如果执行成员函数,则serialize this指向与传递自由函数相同的对象作为第二个参数.只需使用该对象即可.

我的收获

现在,让我参考我对

这是Tanner在

>

  • a.h

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

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

  • 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>();
    }
    

请注意,它简化了几件事,并且在没有异常的情况下至少消除了内存泄漏.

输出

22 serialization::archive 15 0 1 0
0 747

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

I try to serialize a class, say B (in file b.h), which is derived from another one, say A (in file a.h). Both classes have private members and I want to serialize both with the boost serialization library non-intrusively. The serialization/deserialization of A does work so far. For the same for the derived class one would use

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

when the intrusive method is used, but where to put it in the non-intrusive case (save/load/serialize or all three?)? And what object has to been used in place of the this pointer?

In the productive code I have derived class a bit more complicated than B. There I got a compiler error which I wasn't able to reproduce in this small example. The compiler message (MSVC 2015, C2665, translated in English):

The Error in German:

Could anyone help?

The Code of 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;
    }

};

The code of 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; }

};

The Code of the main program:

// 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;
}
解决方案

First, a fair warning about Quasi-Classes (PDF). They are the enemy of encapsulation and confuse OOP.

Next, let me answer two of your questions real quick and proceed to show my take on this:

  1. Either in serialize OR in both save and load (if you have split implementations)

  2. The same object. If you do member-function serialize this points to the same object as gets passed the free function as the second argument. Just use that object.

My Take

Now, let me refer to my answer to Get private data members for non intrusive boost serialization C++

Here's a demonstration of the idea Tanner suggested in his comment

  • a.h

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

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

  • 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>();
    }
    

Note it simplifies a few things and at least removed memory-leaks when there were no exceptions.

Output

22 serialization::archive 15 0 1 0
0 747

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

这篇关于使用私有成员促进派生类的序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 08:17