jeudi 19 septembre 2019

Serializing polymorphic classes using boost

I am trying to serialize using boost and my classes are polymorphic in nature.

when i compile the code , compiler throws exception .

exception thrown at 0x000007FEFD3DB87D in Serialization.exe: Microsoft C++ exception: boost::archive::archive_exception at memory location 0x000000000017AB30.

I have created a MVSC for the problem.

This is the main function.

#include "pch.h"
#include <iostream>
#include<fstream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include "Container.h"
#include "SumOpacityChannel.h"
#include "KeyframeFloat.h"
#include <boost/serialization/export.hpp>


BOOST_CLASS_EXPORT_GUID(SumOpacity_Channel, "SumOpacity_Channel")
BOOST_CLASS_EXPORT_GUID(Keyframebase, "Keyframebase")
int main()
{
    const char* fileName = "saved.txt"; 
    Container cont;
    SumOpacity_Channel opacityChannel;
    SumKeyframeFloat key1, key2;
    key1.setName("Key1");
    key2.setName("key2");
    opacityChannel.AddKeyframe(key1);
    opacityChannel.AddKeyframe(key2);
    cont.AddChannel(&opacityChannel);

    {
        // Create an output archive
        std::ofstream ofs(fileName);        
        boost::archive::text_oarchive ar(ofs);  
        ar & cont;
    }
    Container c_Restored ;

    //load data
    {
        // create an input stream
        std::ifstream ifs(fileName);        
        boost::archive::text_iarchive ar(ifs);
        ar & c_Restored ;
    }

    do
    {
        std::cout << '\n' << "Press a key to continue...";
    } while (std::cin.get() != '\n');
}

I first create SumOpacity_Channel and than add two KeyframeFloat to the channel.

1) SumOpacity_Channel is subclass of SumChannel.

2) KeyframeFloat is subclass of KeyframeBase.

these are the header files for SumChannel and SumOPacity_Channel

#pragma once


#include <boost/serialization/split_member.hpp>
#include <boost/serialization/vector.hpp>

enum class ChannelType
{
    NONE,
    POSITION,
    ROTATION,
    SCALING,
    OPACITY,
};



class SumChannel
{
private:

    ChannelType type;

public:
    SumChannel();
    SumChannel(ChannelType type);
    SumChannel(const SumChannel& channel);
    SumChannel& operator=(const SumChannel& channel);
    virtual ~SumChannel() { }
    virtual SumChannel* Clone() const = 0;


private:

    friend class boost::serialization::access;

    template<typename Archive >
    void save(Archive& ar, const unsigned int version) const {


        ar & type ;
    }

    template<typename Archive>
    void load(Archive& ar, const unsigned int version) {

        ar & type ;
    }

    BOOST_SERIALIZATION_SPLIT_MEMBER()

};

//////////////////////////////////////////////////////////////////////////////

#pragma once
#include "KeyframeFloat.h"
#include "SumChannel.h"
#include <string>
#include <iostream>
#include <vector>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/base_object.hpp>


class SumOpacity_Channel : public SumChannel
{
private:
    std::vector<SumKeyframeFloat>  keyframes;

public:
    SumOpacity_Channel();
    SumOpacity_Channel(const SumOpacity_Channel &opacityChannel);
    ~SumOpacity_Channel();
    SumOpacity_Channel& operator=(const SumOpacity_Channel &posChannel);
    void AddKeyframe(SumKeyframeFloat key);
    void DeleteKeyframe(SumKeyframeFloat key, int number);
    virtual SumChannel* Clone() const;


public:
    typedef SumChannel _Super;
    friend class boost::serialization::access;

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

    template<typename Archive>
    void load(Archive& ar, const unsigned int version) {

        ar & boost::serialization::base_object<_Super>(*this);
        ar & keyframes;
    }    
};

The cpp file for SumChannel and SumOpacity channel

#include "pch.h"
#include "SumChannel.h"


SumChannel::SumChannel()
{
    this->type = ChannelType::NONE;

}
/////////////////////////////////////////////////////////////////////////////////////////////////////
SumChannel::SumChannel(ChannelType type)
{
    this->type = type;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
SumChannel::SumChannel(const SumChannel& channel)
{
    this->type = channel.type;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
SumChannel& SumChannel::operator=(const SumChannel& channel)
{
    this->type = channel.type;
    return *this;
}

/////////////////////////////////////////////////////////////////////////////////

#include "pch.h"
#include "SumOpacityChannel.h"
#include <boost/serialization/vector.hpp>

SumOpacity_Channel::SumOpacity_Channel() : SumChannel(ChannelType::OPACITY)
{

}

SumOpacity_Channel::~SumOpacity_Channel()
{

}

SumOpacity_Channel::SumOpacity_Channel(const SumOpacity_Channel &opacityChannel) : SumChannel(opacityChannel)
{
    this->keyframes.clear();
    for (auto KeyFrame : keyframes)
    {
        this->keyframes.push_back(KeyFrame);
    }
}

SumOpacity_Channel& SumOpacity_Channel::operator=(const SumOpacity_Channel &opacityChannel)
{
    SumChannel::operator=(opacityChannel);
    this->keyframes.clear();
    for (auto KeyFrame : keyframes)
    {
        this->keyframes.push_back(KeyFrame);
    }
    return *this;
}

void SumOpacity_Channel::AddKeyframe(SumKeyframeFloat key)
{
    keyframes.push_back(key);
}

void SumOpacity_Channel::DeleteKeyframe(SumKeyframeFloat key, int number)
{
    keyframes.erase(keyframes.begin() + number);
}

SumChannel* SumOpacity_Channel::Clone() const
{
    return (SumChannel*) new SumOpacity_Channel(*this);
}

The Header file for Keyframe Base and Keyframe Float.

#pragma once

#include <string>
#include <iostream>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/base_object.hpp>



enum class KeyframeType
{
    NONE,
    POSITION,
    ROTATION,
    MATERIAL,
    SCALING,
    TEXTURE1,
    OPACITY,
};


class Keyframebase
{

protected:
    std::string stdstrName;
    KeyframeType keyframeType;

public:
    Keyframebase();
    Keyframebase(KeyframeType keyType);
    Keyframebase(const Keyframebase &key);
    Keyframebase& operator = (const Keyframebase &key);
    std::string getName();
    void setName(std::string stdstrName);

private:

    friend class boost::serialization::access;

    template<typename Archive >
    void save(Archive& ar, const unsigned int version) const {

        ar & stdstrName & keyframeType;
    }

    template<typename Archive>
    void load(Archive& ar, const unsigned int version) {

        ar & stdstrName  & keyframeType;
    }

    BOOST_SERIALIZATION_SPLIT_MEMBER()
};

////////////////////////////////////////////////////////////////////////////////////

#pragma once

#include "KeyframeBase.h"
#include <boost/serialization/serialization.hpp>

class SumKeyframeFloat : public Keyframebase
{
private:
    float x;

public:

    SumKeyframeFloat();
    SumKeyframeFloat(float x);
    SumKeyframeFloat(const SumKeyframeFloat& key);
    //  const Sum_Position& operator=(const Container& container);
    SumKeyframeFloat& operator=(const SumKeyframeFloat& key);
    void setValue(float x);
    void getValue(float *x);


private:

    typedef Keyframebase _Super;
    friend class boost::serialization::access;

    template<typename Archive>
    void save(Archive& ar, const unsigned int version) const {

        ar & boost::serialization::base_object<_Super>(*this);
        ar & x;
    }

    template<typename Archive>
    void load(Archive& ar, const unsigned int version) {

        ar & boost::serialization::base_object<_Super>(*this);
        ar & x;
    }

    BOOST_SERIALIZATION_SPLIT_MEMBER()

};

The CPP files for KeyframeBase and Keyframe Float

#include "pch.h"
#include "KeyframeBase.h"


Keyframebase::Keyframebase()
{
    stdstrName = "Keyframe";
    this->keyframeType = KeyframeType::NONE;
}
Keyframebase::Keyframebase(KeyframeType keyType)
{
    this->keyframeType = keyType;
    stdstrName = "Keyframe";
}   

Keyframebase::Keyframebase(const Keyframebase &key)
{
    this->stdstrName = key.stdstrName;
    this->keyframeType = key.keyframeType;
}

Keyframebase& Keyframebase::operator = (const Keyframebase &key)
{
    this->stdstrName = key.stdstrName;
    this->keyframeType = key.keyframeType;
    return *this;
}

std::string Keyframebase::getName()
{
    return this->stdstrName;
}

void Keyframebase::setName(std::string stdstrName)
{
    this->stdstrName = stdstrName;
}

///////////////////////////////////////////////////////////////////////////////////////

#include "pch.h"
#include "KeyframeFloat.h"



SumKeyframeFloat::SumKeyframeFloat() : Keyframebase(KeyframeType::OPACITY)
{
    this->x = 0.0;
}

SumKeyframeFloat::SumKeyframeFloat(float x)
{
    this->x = x;
}

SumKeyframeFloat::SumKeyframeFloat(const SumKeyframeFloat& key) : Keyframebase(key)
{
    this->x = key.x;
}

SumKeyframeFloat& SumKeyframeFloat::operator = (const SumKeyframeFloat& key)
{
    Keyframebase::operator=(key);
    this->x = key.x;
    return *this;
}

void SumKeyframeFloat::setValue(float x)
{
    this->x = x;
}

void SumKeyframeFloat::getValue(float *x)
{
    *x = this->x;
}

/////////////////////////////////////////////////////////////

The header file for Container

#pragma once

#include <boost/serialization/base_object.hpp>
#include <boost/serialization/split_member.hpp>

#include "SumChannel.h"
#include <boost/serialization/vector.hpp>
#include <memory>


class Container
{
private:
    std::vector< SumChannel* > Channels;

public:

    Container() {   };

    ~Container()
    {
        if(Channels.size() > 0 )
            for (int i = 0; i < Channels.size(); i++)
            {
                delete Channels[i];
            }
    }

    Container& operator = (const Container& c)
    {
        if (Channels.size() > 0)
            Channels.clear(); // clear any previous channels

            for (int i = 0; i < c.Channels.size(); i++)
            {
                Channels.push_back(c.Channels[i]->Clone());
            }
    }


    Container(const Container& c)
    {
        if (Channels.size() > 0)
            Channels.clear(); // clear any previous channels

        for (int i = 0; i < c.Channels.size(); i++)
        {
            Channels.push_back(c.Channels[i]->Clone());
        }
    }

    void AddChannel(SumChannel* channel)
    {
        Channels.push_back(channel->Clone());
    }

private:

    friend class boost::serialization::access;

    template <typename Archive>
    void save(Archive& ar, const unsigned version) const {
        ar &  Channels;
    }

    template <typename Archive>
    void load(Archive& ar, const unsigned version) {

        ar &  Channels;
    }

    BOOST_SERIALIZATION_SPLIT_MEMBER()

};

Aucun commentaire:

Enregistrer un commentaire