Jeux Libres
       
           

» Les Tutoriels » La sérialization et la compression de données avec ODFAEG.

La sérialization et la compression de données avec ODFAEG.


Introduction d'une 10<!-- o sup -->ène<!-- f sup --> de lignes pour présenter le chapitre.




La serialisation et la compression de données.


Utilité.



Sérialiser, pour ceux qui ne le savent pas, c'est décomposer des objets afin de les enregistrer dans un flux, alors pourquoi faire ceci, tout simplement parce que imaginer que vous ayez une entité complexe comportant pleins d'attributs, de vecteurs, d'entités enfants, etc..., ça va vite devenir lourd de récupérer tout les attributs des entités et de les sauvegarder dans un fichier ou bien de les transférer en réseau d'une machine à l'autre.

C'est pour cela que dans mon framework j'ai mis au point un système de sérialisation similaire à celui de boost, mais en plus puissant, en incorporant le nouveau standart du c++11, cela devient beaucoup plus simple surtout pour les objets polymorphes, et vous allez voir que seulement 1 seule macro va suffire!

Sérialiser des données simples avec ODFAEG



Pour sérialiser des données il faut deux choses. (une archive qui contiendra le flux dans lequel on mettra les données, ainsi que le flux bien sur)
Pour le moment odfaeg gère 2 types d'archives : une pour l'écriture (OTextArchive) et une pour la lecture. (ITextArchive)
Mais plus tard il est fort possible que j'incorpore d'autres types d'archive comme par exemple les archives binaires ou bien les archives au format xml.

Il faut donc créer un objet de ce type en lui passant un flux, par exemple, un fichier :
1
2
ofstream ofs("thefile");
OTextArchive oa (ofs);

Ensuite pour sérialiser il suffit d'appeler l'opérateur () sur l'archive en lui passant l'objet, ici par exemple nous allons sérialiser un objet de type std::string :
1
2
3
4
5
6
7
8
9
 
   std::string text="blablabla";
   std::string text2;
   std::ofstream ofs("FichierDeSerialisation");
   {
       odfaeg::OTextArchive oa(text);
       oa(text);
   }
   ofs.close();

Pour la lecture le code est similaire à part que l'on utilise les classe ifstream et ITextArchive :
1
2
3
4
5
6
7
std::ifstream ifs("FichierDeSerialisation");
{
   odfaeg::ITextArchive ia(ifs);
   ia(text2);        
}
std::cout<<text2<<std::endl;
ifs.close();

Pour sérialiser vos objets personnels, il suffit de redéfinir la méthode serialize dans la classe et de passer à l'archive toutes les variables de la classe.
1
2
3
4
5
6
7
8
9
10
11
12
struct A {
   A() {
       var = 10;
   }
void foo(int i)
{ std::cout << i; }
template <typename A>
void serialize (A & ar) {
       ar(var);
}
int var;
};

Car c'est cette méthode que odfaeg va rechercher pour sérialiser l'objet dans l'archive, le code pour sérialiser l'objet dans le main est le même que pour les objets de types std::string.

Sérialiser des objets complexes.



Cette manière de faire est simple mais ne fonctionnera pas dans le cadre des objets polymorphique, en effet, quel donnée de l'objet faut t'il sérialiser, les données de la classe de base seulement, ou celles de la classe dérivée seulement, ou bien les deux ?

Par défaut odfaeg ne sérialize que les données de la classe de base.

Pour lui dire de sérialiser les données de la classe dérivée, il faut redéfinir une autre méthode : la méthode vtserialize.

Pour serializer un objet odfaeg utilise une classe dont il faut hériter dans la classe de base comme ceci :

La classe de base doit au moins avoir une méthode virtuelle pour pouvoir être considérée comme une classe polymorphique, car, odfaeg fait le test à l'exécution avec typeid, et l'héritage doit être pulibque! (Sinon ça ne fonctionnera pas)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct B : public Registered<B> {
   B() {
       c = "serialize base";
   }
virtual void foo()
{ std::cout << 1; }
virtual void print() {
       std::cout<<c<<std::endl;
}
template <typename A>
void vtserialize (A & ar) {
       ar(c);
}
virtual ~B();
std::string c;
};
 
B::~B(){}

Registered n'est rien d'autre qu'un objet qui va savoir comment sérialiser l'objet polymorphique, on doit lui passer en paramètre template la classe de Base.

Ensuite il ne faut pas oublié de redéfinir la méthode virtuelle temlplate vtserialize dans la classe dérivée.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct C : B {
   C () {
       c = "serialize derived";
   }
   void foo();
   void print () {
       B::print();
       std::cout<<c<<std::endl;
   }
   template <typename A>
void vtserialize (A & ar) {
       B::vtserialize(ar);
       ar(c);
}
std::string c;
};
 
void C::foo(){ std::cout << 2; }

Mais ce n'est pas tout, odfaeg sait comment sérialiser les objets polymorphiques, c'est grâce à la classe Registred héritée par la classe de base qu'il sait qu'il doit aussi sérialiser les attributs de la classe dérivée.

Mais il ne sait pas quelle fonction de la classe dérivé il doit appeler pour sérialiser les données ni quel allocator utiliser pour allouer les pointeurs sur les types de base pour les objets des classes dérivées, pour lui dire, il faut appeler  la macro EXPORT_CLASS_GUID dans la fonction main et lui passer 3 paramètres!

Le 1er paramètre est un id qui doit être unique pour chaque exportation, car on peut très bien avoir plusieurs classes dérivées pour une classe de base, ou bien même avoir des classes dérivées qui héritent de plusieurs classe de base! (héritage multiple)

Le second paramètre est le type de la classe de base dont hérite la classe Dérivée.

Et le dernier paramètre est le type de la classe dérivée à exporter, ce qui donne le code final suivant :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
struct B : public odfaeg::Registered<Base> {
   B() {
       c = "serialize base";
   }
   virtual void foo()
   { std::cout << 1; }
   virtual void print() {
   std::cout<<c<<std::endl;
   }
   template <typename A>
   void vtserialize (A & ar) {
   ar(c);
   }
   virtual ~B();
   std::string c;
};
 
B::~B(){}
 
struct C : B {
   C () {
       c = "serialize derived";
   }
   void foo();
   void print () {
       B::print();
       std::cout<<c<<std::endl;
   }
   template <typename A>
void vtserialize (A * ar) {
       B::vtserialize(ar);
       ar(c);
}
std::string c;
};
void C::foo(){ std::cout << 2; }
int main() {    
   EXPORT_CLASS_GUID(BC, B, C)
   C c;
   B* b = &c;
   B* b2;
   std::ofstream ofs("FichierDeSerialisation");
   odfaeg::OTextArchive oa(ofs);
   oa(b);
   std::ifstream ifs("FichierDeSerialisation");
   odfaeg::ITextArchive ia(ifs);
   ia(b2);
   b2->print();
}
Si vous voulez serialiser les données de la classe de base et de la classe dérivée, n'oublier pas d'appeler la méthode vtserialize de la classe de base dans la méthode vtserialize de la classe dérivée!

Voila vous savez maintenant comment sérialiser des objets avec ODFAEG, c'est pas dur!




Conclusion récapitulative de 5 à 10 lignes.



Rédigé par Lo
Consulté 984 fois



Hébergeur du site : David
Version PHP : 5.4.45-0+deb7u2
Uptime : 301 jours 19 heures 10 minutes
Espace libre : 1509 Mo
Dernière sauvegarde : 21/09/2019
Taille de la sauvegarde : 1115 Mo


5511453 pages ont été consultées sur le site !
Dont 2115 pages pendant les 24 dernières heures.

Page générée en 0.601 secondes


Nos sites préférés
- Création d'un jeu de plateforme de A à Z avec SDL
- Zelda ROTH : Jeux amateurs sur le thème de Zelda
- Zeste de Savoir : la connaissance pour tous et sans pépins
- YunoHost : s'héberger soi-même en toute simplicité
- Site de Fvirtman : recueil de projets et de codes en C et C++
- Par ici la sortie : le site des idées de sorties


  © 2005-2019 linor.fr - Toute reproduction totale ou partielle du contenu de ce site est strictement interdite.