Boost 序列化在C++多态上应用遇到的问题及解决方法

        最近在使用Boost 序列化自定义的数据类型时,遇到了一些问题,在这里记录一下解决这些问题的过程。

        背景:我有一些类,是多级继承的。例如:class C:pulic class B,class B:pulic class A。这些类中都有虚函数,而且存在使用基类指针指向子类指针对象的情况。这些类是定义在一个DLL中,导出使用。在这些类中添加了Boost序列化代码。一般情况下,在主程序中序列化这些类的非指针对象时没有问题,指针类型和实际指向的指针的类型一致时序列化这个指针也没有问题。当使用基类指针指向子类指针对象时,序列化代码在程序执行时就会抛异常“unregistered class - derived class not registered or exported ”。

       开始我怀疑是我多级继承导致的问题。于是就写了一些验证代码。代码如下:

基类头文件:

#include "boost/serialization/split_member.hpp"
#include <boost/serialization/access.hpp>
#include <boost/serialization/export.hpp>
#include "boost/archive/binary_iarchive.hpp"
#include "boost/archive/binary_oarchive.hpp"

namespace CY
{
    class CBaseA
    {
    public:
        CBaseA();
        virtual ~CBaseA();
        virtual void DoNothing() {}
    private:
        friend class ::boost::serialization::access;

        template<class Archive>
        void save(Archive & ar, const unsigned int version) const {
            ar & a;
        }

        template<class Archive>
        void load(Archive & ar, const unsigned int version) {
            ar & a;
        }
        BOOST_SERIALIZATION_SPLIT_MEMBER()

    private:
        double a;
    };
}

子类头文件: 

#include <boost/serialization/base_object.hpp>
#include "CBaseA.h"

namespace CY
{
    class CDivB : public CBaseA
    {
    public:
        CDivB();
        virtual ~CDivB();

    private:
        friend class ::boost::serialization::access;

        template<class Archive>
        void save(Archive & ar, const unsigned int version) const {
            ar & ::boost::serialization::base_object<CBaseA>(*this);
            ar & b;
        }

        template<class Archive>
        void load(Archive & ar, const unsigned int version) {
            ar & ::boost::serialization::base_object<CBaseA>(*this);
            ar & b;
        }
        BOOST_SERIALIZATION_SPLIT_MEMBER()

    private:
        double b;
    };
}

孙类头文件 

#include "CDivB.h"

namespace CY
{
    class CDivC : public CDivB
    {
    public:
        CDivC();
        virtual ~CDivC();
    private:
        friend class ::boost::serialization::access;

        template<class Archive>
        void save(Archive & ar, const unsigned int version) const {
            ar & ::boost::serialization::base_object<CDivB>(*this);
            ar & c;
        }

        template<class Archive>
        void load(Archive & ar, const unsigned int version) {
            ar & ::boost::serialization::base_object<CDivB>(*this);
            ar & c;
        }
        BOOST_SERIALIZATION_SPLIT_MEMBER()

    private:
        double c;
    };
}

 这些类的CPP文件内容如下:

#include "CBaseA.h"
namespace CY
{
    CBaseA::CBaseA()
    {
        a = 0.1;
    }


    CBaseA::~CBaseA()
    {
    }
}
///
#include "boost/archive/binary_iarchive.hpp"
#include "boost/archive/binary_oarchive.hpp"
#include "CDivB.h"

BOOST_CLASS_EXPORT_GUID(CY::CDivB, "CDivB")
namespace CY
{
    CDivB::CDivB()
    {
        b = 0.2;
    }


    CDivB::~CDivB()
    {
    }
}

///
#include "CDivC.h"

BOOST_CLASS_EXPORT_GUID(CY::CDivC, "CDivC")

namespace CY
{
    CDivC::CDivC()
    {
        c = 3;
    }


    CDivC::~CDivC()
    {
    }
}

在main函数中使用如下代码进行测试:

    bool bSave = true;
    if (bSave)
    {
        CBaseA *p = new CDivC();
        Save("D:/boost2.bin", p);
    } 
    else
    {
        CBaseA *p = nullptr;
        Load("D:/boost2.bin", p);
        printf("aa\n");
    }

经过测试,读写都没有问题。

但是一旦把这三个类的定义和实现放到DLL中,序列化时就会抛出异常“unregistered class - derived class not registered or exported 

DLL版代码如下:

CBaseA.h

#include "boost/serialization/split_member.hpp"
#include <boost/serialization/access.hpp>
#include <boost/serialization/export.hpp>
#include "boost/archive/binary_iarchive.hpp"
#include "boost/archive/binary_oarchive.hpp"
namespace CY
{

    class _EXPORTS_API CBaseA
    {
    public:
        CBaseA();
        virtual ~CBaseA();
        virtual void DoNothing() {}
    private:
        friend class ::boost::serialization::access;

        template<class Archive>
        void save(Archive & ar, const unsigned int version) const {
            ar & a;
        }

        template<class Archive>
        void load(Archive & ar, const unsigned int version) {
            ar & a;
        }
        BOOST_SERIALIZATION_SPLIT_MEMBER()

    private:
        double a;
    };
}

CDivb.h

#include <boost/serialization/base_object.hpp>
#include "CBaseA.h"
namespace CY
{
    class _EXPORTS_API CDivB : public CBaseA
    {
    public:
        CDivB();
        virtual ~CDivB();

    private:
        friend class ::boost::serialization::access;

        template<class Archive>
        void save(Archive & ar, const unsigned int version) const {
            ar & ::boost::serialization::base_object<CBaseA>(*this);
            ar & b;
        }

        template<class Archive>
        void load(Archive & ar, const unsigned int version) {
            ar & ::boost::serialization::base_object<CBaseA>(*this);
            ar & b;
        }
        BOOST_SERIALIZATION_SPLIT_MEMBER()

    private:
        double b;
    };
}

CDivC.h

#include "CDivB.h"

namespace CY
{
    class _EXPORTS_API CDivC : public CDivB
    {
    public:
        CDivC();
        virtual ~CDivC();
    private:
        friend class ::boost::serialization::access;

        template<class Archive>
        void save(Archive & ar, const unsigned int version) const {
            ar & ::boost::serialization::base_object<CDivB>(*this);
            ar & c;
        }

        template<class Archive>
        void load(Archive & ar, const unsigned int version) {
            ar & ::boost::serialization::base_object<CDivB>(*this);
            ar & c;
        }
        BOOST_SERIALIZATION_SPLIT_MEMBER()

    private:
        double c;
    };

}

后来,通过在DLL中添加导出的读写函数解决了这个问题:

#include "boost/serialization/split_member.hpp"
#include <boost/serialization/access.hpp>
#include <boost/serialization/export.hpp>
#include "boost/archive/binary_iarchive.hpp"
#include "boost/archive/binary_oarchive.hpp"

namespace CY
{

    class KHC_OBJECT_EXPORTS_API CBaseA
    {
    public:
        CBaseA();
        virtual ~CBaseA();
        virtual void DoNothing() {}
    private:
        friend class ::boost::serialization::access;

        template<class Archive>
        void save(Archive & ar, const unsigned int version) const {
            ar & a;
        }

        template<class Archive>
        void load(Archive & ar, const unsigned int version) {
            ar & a;
        }
        BOOST_SERIALIZATION_SPLIT_MEMBER()

    private:
        double a;
    };

    void KHC_OBJECT_EXPORTS_API Save(const char *path, CBaseA *p);
    void KHC_OBJECT_EXPORTS_API Load(const char *path, CBaseA *&p);

}

在main函数中调用Save和Load函数,都能正常读写序列化文件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值