Boost serialization - abstrakte Klasse "templates may not be virtual"



  • Genau das habe ich auch mit meinem letzten Beitrag gemeint...



  • @hustbaer das Problem ist eher, dass ich alles ausprobiert habe und es immer noch nicht funktioniert. Der Fehler "input stream error" ist jetzt weg mit Hilfe deines Codes. Aber jetzt taucht den Fehler

    terminate called after throwing an instance of 'std::bad_alloc'
      what():  std::bad_alloc
    

    auf und ich habe vesucht, den Memoryleak Fehler zu finden.

    ich habe in int main() den Code so geändert und ich bekomme den obigen Fehler:

    int main() {
        std::string str;
       {
            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
    
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
    
            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            str = strs.str();
        }
    
        {
            std::unique_ptr<Audi> audi = std::make_unique<Audi>();
            std::unique_ptr<Porsche>porsche = std::make_unique<Porsche>();
    
    
            std::stringstream strs(str);
            boost::archive::binary_iarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            std::cout << "audi: hp=" << audi->hp << "\n";
            std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    
        }
        
    }
    


  • Ich habe den Fehler debuggert und es hat mit Linie 22 in int main() zu tun:

            boost::archive::binary_iarchive ar(strs);
    
    int main() {
        std::string str;
       {
            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
    
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
    
            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            str = strs.str();
        }
    
        {
            std::unique_ptr<Audi> audi = std::make_unique<Audi>();
            std::unique_ptr<Porsche>porsche = std::make_unique<Porsche>();
    
    
            std::stringstream strs(str);
            boost::archive::binary_iarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            std::cout << "audi: hp=" << audi->hp << "\n";
            std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    
        }
        
    }
    

    Also es gibt ein Problem mit dem Laden. Hat jemand eine Idee was das Problem sein könnte? Ich habe den Code ohne das Laden (also von Linie 16 bis 29 auskommentiert) kompeliert und der Code hat ohne Fehler kompeliert.

    Der gesamte Code:

    #include <armadillo>
    
    #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>
    
    //Serialization for Armadillo Matrices------------------
    BOOST_SERIALIZATION_SPLIT_FREE(arma::mat)
    namespace boost::serialization {
        template<class Archive>
        void save(Archive & ar, const arma::mat &t, unsigned int version) {
            ar << t.n_elem;
            auto data = t.colptr(0);
            for (size_t K = 0; K < t.n_elem; ++K)
                ar << data[K];
        }
    
        template<class Archive>
        void load(Archive & ar, arma::mat &t, unsigned int version) {
            size_t n_elem;
            ar >> n_elem;
            t.set_size(n_elem);
            t.zeros();
            auto data = t.colptr(0);
            for (size_t K = 0; K < n_elem; ++K)
                ar >> data[K];
        }
    } // boost::serialization
    
    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 Porsche : public Car {
    public:
        char const* type() const override { return "Porsche"; }
        //double getInfo() override { return 1.1; }
        Porsche(std::string owner1, int hp1, arma::mat A1)
            {
            owner = owner1;
            hp = hp1;
            A = A1; 
    
            }
        std::string owner;
        int hp{};
        arma::mat A;
        Porsche() = default;
    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 & A;
        }    
    
        
    };
    
    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,  arma::mat A1)
            {
            owner = owner1;
            hp = hp1;
            second_owner = second_owner1; 
            country = country1;
            A = A1; 
            }
        Audi() = default;
    
        std::string owner;
        int hp{};
        std::string second_owner;
        std::string country;
        arma::mat A;
    
    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;
            ar & A;
        }
    
    };
    
    BOOST_CLASS_EXPORT(Audi);
    BOOST_CLASS_EXPORT(Porsche);
    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" ,arma::randu<arma::mat>(4,5));
    
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
    
            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            str = strs.str();
        }
    
        {
            std::unique_ptr<Audi> audi = std::make_unique<Audi>();
            std::unique_ptr<Porsche>porsche = std::make_unique<Porsche>();
    
            std::stringstream strs(str);
            boost::archive::binary_iarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            std::cout << "audi: hp=" << audi->hp << "\n";
            std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    
        }
        
    }
    
    


  • Funktioniert bei dir das Beispiel von folgender Seite bezüglich binary archive:

    https://kezunlin.me/post/6887a6ee/

    #include <boost/archive/binary_iarchive.hpp> 
    #include <boost/archive/binary_oarchive.hpp> 
    #include <iostream> 
    #include <sstream>
    
    class Camera {
    
    public:
        int id;
        std::string name;
        double pos;
    };
    
    namespace boost {
        namespace serialization {
    
            template<class Archive>
            void serialize(Archive& archive, Camera& cam, const unsigned int version)
            {
                archive & BOOST_SERIALIZATION_NVP(cam.id);
                archive & BOOST_SERIALIZATION_NVP(cam.name);
                archive & BOOST_SERIALIZATION_NVP(cam.pos);
            }
    
        } // namespace serialization
    } // namespace boost
    
    std::ostream& operator<<(std::ostream& cout, const Camera& cam)
    {
        cout << cam.id << std::endl
            << cam.name << std::endl
            << cam.pos << std::endl;
        return cout;
    }
    
    void save_load_with_binary_archive()
    {
        // binary archive with stringstream
        std::ostringstream oss;
        boost::archive::binary_oarchive oa(oss);
    
        Camera cam;
        cam.id = 100;
        cam.name = "new camera";
        cam.pos = 99.88;
    
        oa & (cam);
    
        // get binary content
        std::string str_data = oss.str();
        std::istringstream iss(str_data);
        boost::archive::binary_iarchive ia(iss);
        Camera new_cam;
        ia & (new_cam);
        std::cout << new_cam << std::endl;
    }
    
    int main(int argc, char** argv)
    {
        save_load_with_binary_archive();
        return 0;
    }
    


  • @firefly ja das Beispiel funktioniert. Ich bekomme:

    100
    new camera
    99.88
    
    


  • Hab wohl das Problem gefunden. Wenn eine klasse via ihrem base ptr serialisiert wird, dann muss es beim de-serialize auch über den base ptr laufen.
    Funktioniert:

    std::unique_ptr<Camera> cam = std::make_unique<Camera>();
    std::unique_ptr<Camera> cam2 = std::make_unique<MyCam>(2000);
    boost::archive::binary_oarchive oa;
    
    oa & (cam);
    oa & (cam2);
    
    boost::archive::binary_iarchive ia(iss);
    std::unique_ptr<Camera> new_cam;
    ia & (new_cam);
    
    std::unique_ptr<Camera> new_cam2;
    ia & (new_cam2);
    
    

    Funktioniert nicht:

    std::unique_ptr<Camera> cam = std::make_unique<Camera>();
    std::unique_ptr<Camera> cam2 = std::make_unique<MyCam>(2000);
    boost::archive::binary_oarchive oa;
    
    oa & (cam);
    oa & (cam2);
    
    boost::archive::binary_iarchive ia(iss);
    std::unique_ptr<Camera> new_cam;
    ia & (new_cam);
    
    std::unique_ptr<MyCam> new_cam2;
    ia & (new_cam2);
    // new_cam2 holds still an nullptr
    

    Liegt wohl daran, dass im archive die information enthalten ist wie das objekt gespeichert wurde.
    Im obigen beispiel wurde wohl die information vermerkt dass die MyCam instanz als std::unique_ptr<Camera> gespeichert wurde.
    Aber beim de-serialize wurde ein std::unique_ptr<MyCam> übergeben was so nicht der information entspricht die im archive enthalten ist. Wodurch nichts serialisiert wird.

    Und hier das vollständige Beispiel mit den verschiedenen varianten:

    #include <boost/archive/binary_iarchive.hpp> 
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/serialization/export.hpp>
    #include <boost/serialization/unique_ptr.hpp>
    #include <iostream> 
    #include <sstream>
    
    class Camera {
    
    public:
        virtual ~Camera() = default;
        int id = -1;
        std::string name="<unknown>";
        double pos = -2.0;
    };
    
    class MyCam : public Camera
    {
    public:
        MyCam(int t): bla(t){}
        MyCam() = default;
        virtual ~MyCam() = default;
        int bla;
    };
    
    namespace boost {
        namespace serialization {
    
            template<class Archive>
            void serialize(Archive& archive, Camera& cam, const unsigned int version)
            {
                archive & BOOST_SERIALIZATION_NVP(cam.id);
                archive & BOOST_SERIALIZATION_NVP(cam.name);
                archive & BOOST_SERIALIZATION_NVP(cam.pos);
            }
    
            template<class Archive>
            void serialize(Archive& archive, MyCam& cam, const unsigned int version)
            {
                archive & boost::serialization::base_object<Camera>(cam);
                archive & BOOST_SERIALIZATION_NVP(cam.bla);
            }
    
        } // namespace serialization
    } // namespace boost
    
    BOOST_CLASS_EXPORT(Camera);
    BOOST_CLASS_EXPORT(MyCam);
    
    std::ostream& operator<<(std::ostream& cout, const Camera& cam)
    {
        cout << cam.id << std::endl
            << cam.name << std::endl
            << cam.pos;
        return cout;
    }
    
    std::ostream& operator<<(std::ostream& cout, const MyCam& cam)
    {
        cout << static_cast<const Camera&>(cam) << std::endl
            << cam.bla;
        return cout;
    }
    
    void save_load_with_binary_archive()
    {
        // binary archive with stringstream
        std::ostringstream oss;
        boost::archive::binary_oarchive oa(oss);
    
        Camera cam;
        cam.id = 100;
        cam.name = "new camera";
        cam.pos = 99.88;
    
        oa & (cam);
    
        // get binary content
        std::string str_data = oss.str();
        std::istringstream iss(str_data);
        boost::archive::binary_iarchive ia(iss);
        Camera new_cam;
        ia & (new_cam);
        std::cout << new_cam <<'\n'<< std::endl;
    }
    
    void save_load_with_binary_archive_unique_ptr()
    {
        // binary archive with stringstream
        std::ostringstream oss;
        boost::archive::binary_oarchive oa(oss);
    
        std::unique_ptr<Camera> cam = std::make_unique<Camera>();
        cam->id = 200;
        cam->name = "new camera";
        cam->pos = 99.88;
    
        oa & (cam);
        
        std::unique_ptr<MyCam> cam2 = std::make_unique<MyCam>(1000);
        cam2->id = 300;
        cam2->name = "my camera";
        cam2->pos = 42.2;
        
        oa & (cam2);
    
        // get binary content
        std::string str_data = oss.str();
        std::istringstream iss(str_data);
        boost::archive::binary_iarchive ia(iss);
        std::unique_ptr<Camera> new_cam;
        ia & (new_cam);
        std::cout << *(new_cam.get()) <<'\n' << std::endl;
        
        std::unique_ptr<MyCam> new_cam2;
        ia & (new_cam2);
        std::cout << *(new_cam2.get()) <<'\n' << std::endl;
    }
    
    void save_load_with_binary_archive_unique_ptr_base()
    {
        // Serialize child class via base class and deserialize via base class
        // binary archive with stringstream
        std::ostringstream oss;
        boost::archive::binary_oarchive oa(oss);
    
        std::unique_ptr<Camera> cam = std::make_unique<Camera>();
        cam->id = 2002;
        cam->name = "new camera2";
        cam->pos = 99.88;
    
        oa & (cam);
        
        std::unique_ptr<Camera> cam2 = std::make_unique<MyCam>(2000);
        cam2->id = 3002;
        cam2->name = "my camera2";
        cam2->pos = 42.2;
        
        oa & (cam2);
    
        // get binary content
        std::string str_data = oss.str();
        std::istringstream iss(str_data);
        boost::archive::binary_iarchive ia(iss);
        std::unique_ptr<Camera> new_cam;
        ia & (new_cam);
        std::cout << *(new_cam.get()) <<'\n' << std::endl;
        
        std::unique_ptr<Camera> new_cam2;
        ia & (new_cam2);
        std::cout << *static_cast<MyCam*>(new_cam2.get()) <<'\n' << std::endl;
    }
    
    void save_load_with_binary_archive_unique_ptr_notbase()
    {
        // Serialize child class via base class but deserialize via child class
        // binary archive with stringstream
        std::ostringstream oss;
        boost::archive::binary_oarchive oa(oss);
    
        std::unique_ptr<Camera> cam = std::make_unique<Camera>();
        cam->id = 2002;
        cam->name = "new camera2";
        cam->pos = 99.88;
    
        oa & (cam);
        
        std::unique_ptr<Camera> cam2 = std::make_unique<MyCam>(2000);
        cam2->id = 3002;
        cam2->name = "my camera2";
        cam2->pos = 42.2;
        
        oa & (cam2);
    
        // get binary content
        std::string str_data = oss.str();
        std::istringstream iss(str_data);
        boost::archive::binary_iarchive ia(iss);
        std::unique_ptr<Camera> new_cam = std::make_unique<Camera>();
        ia & (new_cam);
        std::cout << *(new_cam.get()) <<'\n' << std::endl;
        
        // Create instance here because here gets nothing deserialized and thus the output code would crash
        std::unique_ptr<MyCam> new_cam2 = std::make_unique<MyCam>(-1);
        ia & (new_cam2);
        std::cout << *(new_cam2.get()) <<'\n' << std::endl;
    }
    
    int main(int argc, char** argv)
    {
        save_load_with_binary_archive();
        std::cout<<"unique_ptr:\n";
        save_load_with_binary_archive_unique_ptr();
        
        std::cout<<"unique_ptr on base:\n";
        save_load_with_binary_archive_unique_ptr_base();
        
        std::cout<<"unique_ptr not base:\n";
        save_load_with_binary_archive_unique_ptr_notbase();
        return 0;
    }
    
    


  • Du hast es gelöst! Vielen vielen Dank! Das Problem lag genau an

    std::unique_ptr<Audi>
    std::unique_ptr<Porsche>
    

    Ich musste auch

    ar& *audi
    

    mit dem Zeiger machen, ansonsten wenn ich

    aud.get()
    

    aufrufe bekommen ich die Memory-Adresse.



  • @mika000 sagte in Boost serialization - abstrakte Klasse "templates may not be virtual":

    Du hast es gelöst! Vielen vielen Dank! Das Problem lag genau an

    std::unique_ptr<Audi>
    std::unique_ptr<Porsche>
    

    Ich musste auch

    ar& *audi
    

    mit dem Zeiger machen, ansonsten wenn ich

    aud.get()
    

    aufrufe bekommen ich die Memory-Adresse.

    Öhm Nein. Oder ich verstehe deine Aussage falsch.
    Dein Problem ist nicht audi.get() vs *audi sondern was anderes.

    Wenn es darum geht Objekte über einen pointer auf ihre basis klasse zu serialisieren/deserialisieren.

    Statt

    int main() {
        std::string str;
       {
            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
    
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
    
            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            str = strs.str();
        }
    
        {
            std::unique_ptr<Audi> audi = std::make_unique<Audi>();
            std::unique_ptr<Porsche>porsche = std::make_unique<Porsche>();
    
            std::stringstream strs(str);
            boost::archive::binary_iarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            std::cout << "audi: hp=" << audi->hp << "\n";
            std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    
        }
        
    }
    

    Sollte der Code so sein:

    int main() {
        std::string str;
       {
            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
    
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
    
            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            str = strs.str();
        }
    
        {
            std::unique_ptr<Car> audi = std::make_unique<Audi>();
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>();
    
            std::stringstream strs(str);
            boost::archive::binary_iarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            std::cout << "audi: hp=" << audi->hp << "\n";
            std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    
        }
        
    }
    

    -> Der Typ einer Variable im lese code muss identisch mit dem entsprechenden Typ im schreib code sein.



  • @firefly Das Problem ist damit, dass ich die Fehler bekomme:

             std::cout << "audi: hp=" << audi->hp << "\n";
                                               ^~
    virt_funk_seri.cpp:210:49: error: ‘class Car’ has no member named ‘hp’
             std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
                                                     ^~
    virt_funk_seri.cpp:210:76: error: ‘class Car’ has no member named ‘owner’
             std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
                                                                                ^~~~~
    virt_funk_seri.cpp:210:103: error: ‘class Car’ has no member named ‘A’
             std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    
    

    Ich habe dann so ausprobiert

            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& *audi;
            ar& *porsche;
    
            str = strs.str();
        }
    
        {
            std::unique_ptr<Car> audi; //= std::make_unique<Audi>();
            std::unique_ptr<Car> porsche; //= std::make_unique<Porsche>();
    
           std::stringstream strs(str);
           boost::archive::binary_iarchive ar(strs);
           ar& *audi;
           ar& *porsche;
    
           std::cout << audi.get() << "\n";
           std::cout <<  porsche.get(); 
    
    

    und ich hab das hier bekommen:

    audi: hp=0
    porsche: hp=0%  
    

    Ohne die Zeiger bekomme ich:

    audi: hp=0x55f67592d100
    porsche: hp=0x55f67592c780% 
    


  • @mika000 sagte in Boost serialization - abstrakte Klasse "templates may not be virtual":

    Das Problem ist damit, dass ich die Fehler bekomme:
    std::cout << "audi: hp=" << audi->hp << "\n";
    ^~
    virt_funk_seri.cpp:210:49: error: ‘class Car’ has no member named ‘hp’
    std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    ^~
    virt_funk_seri.cpp:210:76: error: ‘class Car’ has no member named ‘owner’
    std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    ^~~~~
    virt_funk_seri.cpp:210:103: error: ‘class Car’ has no member named ‘A’
    std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";

    Klar, weil ein Car diese properties nicht hat....
    Du musst vor den Ausgabe dann den Car Pointer auf das passende Objekt casten.
    Dafür musst du aber genau wissen dass die Car instanz auch wirklich ein Audi oder Porsche ist.
    Besser wäre es wenn Car die Properties hätte, denn in beiden abgeleiteten Klassen sind diese Properties jeweils vorhanden:

    • hp
    • owner
    • A

    Wenn es nur um die reine Ausgabe geht könnte man der Car klasse eine virtuelle "print" methode verpassen welche von den abgeleiteten Klassen implementiert wird um eine passende ausgabe zu machen.

    Aber das ganze hat jetzt null mit boost serialize zu tun. Da scheinst du ein grundlegendes Designproblem zu haben.

    Und wieso meinst du unbedingt über pointer gehen zu müssen, wenn boost serialization std::unique_ptr direkt unterstützt?
    Durch die Verwendung von unique_ptr<Car> musst du beim lesen kein Objekt erst erzeugen sondern der "de-serialize" Code erstellt dir ein passendes Objekt, falls beim lesen keine Probleme auftraten.
    Im Fehlerfall hält die unique_ptr<Car> instanz weiterhin einen nullptr was du dann zum prüfen nutzen kannst.



  • Besser wäre es wenn Car die Properties hätte, denn in beiden abgeleiteten Klassen sind diese Properties jeweils vorhanden:

    Der Code wird viele derived Klassen haben. Deswegen wird das leider nicht möglich.

    Du musst vor den Ausgabe dann den Car Pointer auf das passende Objekt casten.
    Dafür musst du aber genau wissen dass die Car instanz auch wirklich ein Audi oder Porsche ist.

    Ich habe cast bis jetzt nie benutzt. Ich habe aber das hier ausprobiert aber es klappt nicht.

    dynamic_cast<Audi>(audi);
    dynamic_cast<Porsche>(porsche);
    

    Kannst du mir einen Hinweis geben, wie ich das genau tun soll?

    Wenn es nur um die reine Ausgabe geht könnte man der Car klasse eine virtuelle "print" methode verpassen welche von den abgeleiteten Klassen implementiert wird um eine passende ausgabe zu machen.

    Ne es geht um die Serialisierung. Die Ausgabe ist nur wichtig, um nachzuprüfen, dass die Serialisierung funktioniert hat.

    Aber das ganze hat jetzt null mit boost serialize zu tun. Da scheinst du ein grundlegendes Designproblem zu haben.

    Der Code (ohne abstrakte Klassen+virtuell), den ich vorher hatte, hat perfekt mit boost:serialization funktioniert. Mit abstrakten Klassen + virtueller Funktion klappt es nicht und deswegen ist dieses Problem deutlich schwierig geworden. Von meinem ersten Beitrag was ich "wollte", war genau:

    class Car {
    public:
          virtual double getInfo() = 0;
    
    private:
       template <typename Archive> //wo das Problem liegt
       virtual void serialize(Archive& ar, unsigned int version) = 0;
    };
    

    Also template + virtual funktioniert nicht. Und wegen dieses Problemes haben wir in diesem Post versucht eine Alternative zu machen. Ich wollte das so machen, weil die Klassen sollten so instanziiert werden:

    std::unique_ptr<Car> audi(new Audi);
    

    Es müsste als Car definiert sein um die gleiche API zu verwenden.

    Und wieso meinst du unbedingt über pointer gehen zu müssen, wenn boost serialization std::unique_ptr direkt unterstützt?

    Ich meine das nicht, nur dass ohne Zeiger habe ich nur die Adresse bekommen.

    Im Fehlerfall hält die unique_ptr<Car> instanz weiterhin einen nullptr was du dann zum prüfen nutzen kannst.

    Meinst du so?:

    std::unique_ptr<Car> audi = NULL
    


  • Sorry, aber wie willst du so ein Programm mit "abstrakten Klassen + virtueller Funktion" entwickeln, wenn dir die logischen Grundlagen der OOP fehlen?

    @mika000 sagte in Boost serialization - abstrakte Klasse "templates may not be virtual":

    std::unique_ptr<Car> audi(new Audi);
    

    Es müsste als Car definiert sein um die gleiche API zu verwenden.

    Das ist auch so in Ordnung, aber dann sollte dir klar sein, daß du so eben nur auf die Member der Basisklasse Car zugreifen kannst.
    Und schau dir das Beispiel zu dynamic_cast an (du mußt also selbstverständlich den Rückgabewert speichern und benutzen).



  • @mika000 sagte in Boost serialization - abstrakte Klasse "templates may not be virtual":

    @hustbaer das Problem ist eher, dass ich alles ausprobiert habe und es immer noch nicht funktioniert.

    Nein, ernsthaft: das Problem ist dass du abstrakte Klassen und virtuelle Funktionen nicht verstanden hast, und daher seltsame andere Konstrukte versuchst die überhaupt keinen Sinn machen. Und daher dann auch nicht funktionieren. ar& *audi und ar& audi.get() sind halt einfach beide Quatsch in deinem Fall.



  • Jetzt funktioniert der Code richtig:

    #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);
            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;
            Audi& d =dynamic_cast<Audi &>(*audi);
            std::cout << "audi: hp=" << d.hp << " owner=" << d.owner <<"\n";
        }
    }
    

    Ich habe den Code minimalisiert.

    Ich danke euch für die Tipps und die Hilfe. Aber ich fand die anderen Nachrichten unnötig...natürlich bin ich kein Profi, wie ihr euch so darstellt aber ich gebe mir Mühe, um die Sachen zu lernen. Ich habe nicht gewusst, dass man hier im Forum keine Fehler machen kann. Wenn ich in der Zukunft hier was poste, musst ihr nicht kommentieren aber ich würde mich freuen wenn diese Gesellschaft auch "Anfängern" helfen kann.



  • Bei (schon gehobenen) Themen wie "Boost Serialisation" haben wir einfach erwartet, daß zumindestens die C++ Grundlagen sitzen, aber es hat sich ja dann herausgestellt, daß es bei dir noch nicht so ist (und dann wird so ein Thema unnötig in die Länge gezogen und das erzeugt Frust auf beiden Seiten).

    Ich hoffe, du hast jetzt wenigstens verstanden, warum man bei der Deserialisierung dann 'casten' muß, um auf die spezifischen Member (der konkreten Klasse) zugreifen zu können - und damit hat das Forum ja auch seinen Sinn erfüllt.

    PS: "Einfängern" helfe ich aber nicht 😉



  • @mika000 Wenn ich dir hier sage dass du offenbar virtuellen Funktionen und abstrakte Klassen (und vermutlich auch ein paar andere Grundlagen von C++) nicht verstanden hast, dann ist das eine Beobachtung. Wo genau ist jetzt das Problem? Du verstehst bzw. weisst es halt (noch) nicht, is ja eh OK.

    Blöd wird es nur dann, wenn du das nicht wahr haben willst, und daher versuchst alles mögliche komische Zeug in deinen Code zu schreiben von dem du offensichtlich gar nicht verstehst was es bewirkt, und dich dann wunderst warum es nicht geht und wiederholt fragen kommst warum es nicht geht. Das ist nämlich mühsam.

    Und doppelt blöd wird es, wenn du dann auch noch leicht angepisst ankommst und meinst man solle sich doch bitte die blöden Kommentare sparen.



  • @Th69 sagte in Boost serialization - abstrakte Klasse "templates may not be virtual":

    Ich hoffe, du hast jetzt wenigstens verstanden, warum man bei der Deserialisierung dann 'casten' muß, um auf die spezifischen Member (der konkreten Klasse) zugreifen zu können - und damit hat das Forum ja auch seinen Sinn erfüllt.

    Ich glaube nicht dass er das verstanden hat, da er ja meinte er müsse Car-Zeiger verwenden damit man das ganze mit einer gemeinsamen API verwenden kann. Und dann will er darüber auf Audi-Member zugreifen die es in Car nicht gibt und wundert sich warum es nicht geht. Ein Cast ist da mMn. nicht die Lösung. Wenn er weiss dass da ein Audi daherkommt, dann soll er einen Audio serialiserein. Und wenn er es nicht weiss, dann ist der Cast keine gute Lösung. Weil er ihm (in der Form wie er es geschrieben hat) um die Ohren fliegen wird (Exception) wenn es etwas anderes als ein Audi war.



  • @hustbaer

    Und dann will er darüber auf Audi-Member zugreifen die es in Car nicht gibt und wundert sich warum es nicht geht.

    Ich habe schon gewusst warum das nicht geklappt hat. Ich wollte nämlich 1. besser verstehen warum ist nicht klappt und 2. wie ich es lösen kann.

    Die einzige Person, die hier leicht angepisst ist, ist anscheinend du. Du musst nicht sauer sein, weil ich finde die anderen Nachrichten unnötig. Ich bin kein perfekter Mensch wie du...ich mache Fehler. Und weiß du was? Ich lerne von den Fehlern. Wenn du so ungeduldig bist, dann musst du mir nicht helfen. Aber wie auch schon geschrieben, ich bin dankbar für die Hilfe und ich habe mehrere Sachen von meinem Beitrag gelernt.



  • @mika000
    Vielleicht magst du mir sagen/schreiben was genau du "unnötig" findest? Ich les mir das dann gerne nochmal durch und dann sehe ich ja ob ich es auch unnötig finde bzw. kann dir schreiben warum ich es so geschrieben habe.


Anmelden zum Antworten