Сериализация производных классов из абстрактного класса с использованием boost :: serialization - PullRequest
1 голос
/ 26 апреля 2020

Я пытаюсь сериализовать производные классы из абстрактного класса, и я получаю некоторые (очевидные) ошибки.

Вот код (запускается с использованием g ++ -std = c ++ 17 XXXX. cpp -Wall -larmadillo -lboost_serialization):

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/unique_ptr.hpp>

#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <vector>


class Car {
public:
    //Car() = default;
    //virtual double getInfo() = 0;
    virtual char const* type() const = 0;
    virtual ~Car() = default;

private:
    friend class boost::serialization::access;
    template <class Archive>
    void serialize(Archive& ar, const unsigned int version) {};
};

class Audi : public Car {
public:
    char const* type() const override { return "Audi"; }
    //double getInfo() override { return 2.2; }
    Audi(std::string owner1, int hp1, std::string second_owner1, std::string country1)
        {
        owner = owner1;
        hp = hp1;
        second_owner = second_owner1; 
        country = country1;
        }
    Audi() = default;

    std::string owner;
    int hp{};
    std::string second_owner;
    std::string country;    
private:
    friend class boost::serialization::access;
    template <class Archive>
    void serialize(Archive& ar, const unsigned int version) {
        ar & boost::serialization::base_object<Car>(*this); //https://theboostcpplibraries.com/boost.serialization-class-hierarchies
        ar & owner;
        ar & hp;
        ar & second_owner;
        ar & country;
    }

};

BOOST_CLASS_EXPORT(Audi);
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Car); //Tell Boost that Car is abstract



int main() {
    std::string str;
   {
        std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina");
        audi->type();


        std::stringstream strs;
        boost::archive::binary_oarchive ar(strs);
        ar& audi;

        str = strs.str();
    }

    {
        std::unique_ptr<Car> audi; //= std::make_unique<Audi>();

        std::stringstream strs(str);
        boost::archive::binary_iarchive ar(strs);
        ar& audi;
        //dynamic_cast<Audi>(audi); Tried using casting but am unfamiliar with it -- perhaps this is the issue?

        std::cout << "audi: hp=" << audi->hp << " owner=" << audi->owner <<"\n";

    }

}

, и я получаю ошибки:

audi_seri.cpp: In function ‘int main()’:
audi_seri.cpp:84:36: error: cannot dynamic_cast ‘audi’ (of type ‘class std::unique_ptr<Car>’) to type ‘class Audi’ (target is not pointer or reference)
             dynamic_cast<Audi>(audi);
                                    ^
audi_seri.cpp:86:47: error: ‘class Car’ has no member named ‘hp’
             std::cout << "audi: hp=" << audi->hp << " owner=" << audi->owner <<"\n";
                                               ^~
audi_seri.cpp:86:72: error: ‘class Car’ has no member named ‘owner’
             std::cout << "audi: hp=" << audi->hp << " owner=" << audi->owner <<"\n";

Теперь я знаю, почему это происходит - у машины нет этих переменных. Но как я могу решить эту проблему, когда решение может работать для многих производных классов, которые могут иметь разных членов? Возможно, чтобы решить эту проблему, я должен использовать кастинг?

Чтобы лучше понять, почему я пытаюсь это сделать. Сначала я хотел использовать void serialize () в Car как виртуальную функцию, но это не работает с шаблонами. И поэтому я пришел к приведенному выше коду с помощью https://theboostcpplibraries.com/boost.serialization-class-hierarchies

Вот старый код с void serialize как виртуальная функция:

class Car {
public:
      virtual double getInfo() = 0;

private:
   template <typename Archive> //This is the problem I am trying to solve: templates cannot be virtual
   virtual void serialize(Archive& ar, unsigned int version) = 0;
};

class Audi : public Car {
    public:
        char const* type() const override { return "Audi"; }
        //double getInfo() override { return 2.2; }
        Audi(std::string owner1, int hp1, std::string second_owner1, std::string country1)
            {
            owner = owner1;
            hp = hp1;
            second_owner = second_owner1; 
            country = country1;
            }
        Audi() = default;

        std::string owner;
        int hp{};
        std::string second_owner;
        std::string country;    
    private:
        template <class Archive>
        void serialize(Archive& ar, const unsigned int version) {
            ar & owner;
            ar & hp;
            ar & second_owner;
            ar & country;
        }

    };

    BOOST_SERIALIZATION_ASSUME_ABSTRACT(Car); //Tell Boost that Car is abstract



    int main() {
        std::string str;
       {
            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina");


            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& audi;

            str = strs.str();
        }

        {
            std::unique_ptr<Car> audi; //= std::make_unique<Audi>();

            std::stringstream strs(str);
            boost::archive::binary_iarchive ar(strs);
            ar& audi;
            //dynamic_cast<Audi>(audi);

            std::cout << "audi: hp=" << audi->hp << audi->hp<< " owner=" << "\n";

        }

    }
...