====== Biblioteka boost:serialization ====== Autor : Marcin Kocoń, G1ISI --- //[[mkocon(_at_)gmail.com|Marcin Kocoń]] 2008/04/14 11:36// ===== Opis biblioteki ===== Poprzez serializację rozumiemy zapis instancji dowolnej klasy do pliku w sposób umożliwiający jej późniejszą rekonstrukcję. Biblioteka boost:serialization umożliwia automatyczną (tzn. bez jakieś większej naszej ingerencji) serializację wybranych atrybutów. Dzięki wbudowanych funkcjom tej biblioteki jesteśmy w stanie w prosty (jednakże czasem mniej lub bardziej zróżnicowany) sposób dokonać serializacji następujących elementów : * składowych prywantych w sposób ingerenujący w składowe wewnętrzne klasy * składowych publicznych w sposób nieingerenujący w składowe wewnętrzne klasy * składowych prywatnych poprzez zestaw Set'ów/Get'ów i rozdzielenie funkcji serializacji na save/load * STL-owskich kolekcji w sposób zupełnie automatyczny * wskaźników (a raczej elementów na które te wskaźniki wskazują) * tablic elementów * i wiele, wiele innych... Więcej informacji o dokładnym działaniu biblioteki na stronie [[http://www.boost.org/doc/libs/1_35_0/libs/serialization/doc/index.html|Boost:serialization]] ===== Opis programu testowego ===== Program testuje najważniejsze funkcje wchodzące w skład pakietu boost:serialization. Mamy tutaj zawarte : * klasę bazową budynek i dziedziczącą po niej klasę akademik * klasę student, której instancje wchodzą w skład STL-owskiej kolekcji, będącej elementem klasy akademik * test działania metody serialize, będącej elementem klas akademik i budynek * rozdzielenie metody serialize na load/save (+split_free) dla zapisu elementów klasy student * zapis do prostego archiwum tekstowego całej instancji klasy akademik, a następnie odtworzenie z tego pliku zserializowanych atrybutów ===== Kod źródłowy programu testowego ===== // Praca domowa ZPR 2008L // Marcin Kocoń // temat : biblioteka boost:serialization #include #include // bedziemy zapisywac proste archwium w postaci tekstowej #include #include // potrzebne do obslugi serializacji klas pochodnych #include #include // nagłówek zawierający metodę(makro) do rozdzielenia funkcji serializacji #include #include // Klasa opisująca studenta class student { private: std::string imie; std::string nazwisko; public: student() {} student(const std::string& _imie, const std::string& _nazwisko){ imie = _imie; nazwisko = _nazwisko; } // Zestaw Set'ów i Get'ów między innymi do obsługi serializacji dla atrybutów prywatnych std::string& getImie() { return imie; } std::string& getNazwisko() { return nazwisko; } void setImie(const std::string& _imie) { imie = _imie; } void setNazwisko(const std::string& _nazwisko) {nazwisko = _nazwisko; } }; // Metoda serializacji nie będąca elementem klasy. Umożliwia zapisz/odczyt atrybutów // prywatnych. Jednakże, aby tego dokonać potrzeba jest rozczepienie domyślnej // metody serialize na dwie : save i load, a następnie połączenie ich w całość namespace boost { namespace serialization { template void save(Archive & ar, const student& g, const unsigned int version) { student g2 = const_cast(g); // usunięcie const, aby można było wywołać metodę getXXX ar << g2.getImie(); ar << g2.getNazwisko(); } template void load(Archive & ar, student& g, const unsigned int version) { std::string s1, s2; ar >> s1; ar >> s2; g.setImie(s1); g.setNazwisko(s2); } template inline void serialize(Archive & ar, student& g, const unsigned int version){ // złączenie load/save -> serialize split_free(ar, g, version); } } // namespace serialization } // namespace boost // Klasa opisująca budynek - klasa bazowa class budynek { private: // dzięki temu metoda serializacji ma dostęp do atrybutów prywatnych friend class boost::serialization::access; template // te dwie linijki są wzorcem, z którego void serialize(Archive& ar, const unsigned int version) // korzystamy zawsze przy serializacji { ar & identyfikator; // poszczególne atrybuty są dodawane do archiwum ar & nazwa; // poprzez użycie operatora '&' na archiwum ar & miasto; } std::string miasto; std::string nazwa; int identyfikator; protected: budynek(const int _id, const std::string& _nazwa, const std::string& _miasto) : identyfikator(_id), nazwa(_nazwa), miasto(_miasto) {} public: std::string& getMiasto() { return miasto; } std::string& getNazwa() { return nazwa; } int getId() { return identyfikator; } budynek() {} virtual ~budynek() {} }; // Klasa pochodna akademik, dziedzicząca po budynku class akademik : public budynek { private: // Standardowo dostęp do metod prywatnych dla serializacji friend class boost::serialization::access; template // metoda serializacji void serialize(Archive & ar, const unsigned int version) { // Zserializuj atrybuty z klasy bazowej ar & boost::serialization::base_object(*this); // Kolekcje STL-owskie są automatycznie serializowane. // W podobny sposób działa także serializacja wskaźników // (= obiektów, na które wskazują) ar & studenci; } std::deque studenci; // Standardowa kolejka STL-owska public: akademik() {} akademik(const int _id, const std::string& _nazwa, const std::string& _miasto) : budynek(_id, _nazwa, _miasto) {} // Umożliwia dodanie studenta do kolekcji studentów void dodajStudenta(student* const _stud) { studenci.push_back(_stud); } // Zwraca ilość studentów w akademiku const int getIlStud() { return studenci.size(); } // Podaje dane studenta student* const podajDaneStudentaNr(const int _nr) { return studenci[_nr]; } virtual ~akademik() {} }; void zapisz_akademik(const akademik &s, const char* filename) { try{ // stworz archiwum std::ofstream ofs(filename); // zapisz w postaci archiwum tekstowego boost::archive::text_oarchive oa(ofs); oa << s; } catch(std::exception e) { std::cout << e.what() << std::endl; exit(1); } } void wczytaj_akademik(akademik &s, const char* filename) { try{ // otwórz archiwum std::ifstream ifs(filename); boost::archive::text_iarchive ia(ifs); // przywroc dane z uprzednio zapisanego archiwum ia >> s; } catch(std::exception e) { std::cout << e.what() << std::endl; exit(1); } } int main() { const char* filename = "ala_i_kot.dat"; // Nowy akademik + dwoch studentow akademik* ak1 = new akademik(1, "Riviera", "Warszawa"); ak1->dodajStudenta(new student("Jacek", "Jankowski")); ak1->dodajStudenta(new student("Adam", "Jakubowski")); //----- Zapis do archiwum ----- { zapisz_akademik(*ak1, filename); } // archiwum i output stream zamykane podczas wywolywania destruktora delete ak1; // Jakis czas pozniej.... akademik nowy; // ----- Odczyt z archiwum ----- { wczytaj_akademik(nowy, filename); } std::cout << "Nowy akademik : " << nowy.getId() << ", " << nowy.getNazwa() << ", " << nowy.getMiasto() << ", " << nowy.getIlStud() << "\n"; std::cout << "Mieszkancy : \n"; for (int i=0; i< nowy.getIlStud(); ++i) { std::cout << "[" << i << "] Imie : " << nowy.podajDaneStudentaNr(i)->getImie(); std::cout << " Nazwisko : " << nowy.podajDaneStudentaNr(i)->getNazwisko() << "\n"; } std::cout << "\n\n"; return 0; }