Salut,
étant donné les problèmes que j'ai eu avec certaines librairies de sérialisation en c++ lors de l'enregistrement des types pour les pointeurs sur des objets de classe dérivées.
de plus ces librairies sont parfois de grosses dépendances supplémentaire à fournir qui augment considérablement la taille de mon framework!

J'ai décidé de créer mon propre système de sérialisation d'objets.

L'idée est de passer en template le type réel du pointeur à une classe de base dont hériteront tout les objets sérializable, afin que après je n'ai plus qu'à faire un downcast et appeler la bonne fonction sérialize lors de l'archivation.

Donc j'ai fait une classe sérializable, son rôle est de contenir le type réel de l'objet. (c'est à dire celui fourni à l'instanciation et non celui fourni lors de la déclaration de l'objet à sérialiser)

Et de récupérer le bon pointeur vers la fonction membre sérialize c'est à dire celle de la classe dérivée si la classe est héritée), j'ai donc fait ceci :

Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
#ifndef SERIALIZATION
#define SERIALIZATION
namespace odfaeg {
template <typename C>
class Serializable {
public :
    template <typename A>
    void getSerializeFunc(void(C::**func)(A&)) {
         *func = &C::serialize;
    }
};
}
#endif // SERIALIZATION

Ensuite j'ai fait deux classes (ITextArchive et OTextArchive) exactement comme certaines librairies le font :
Et je fais un downcast de la classe de base vers la classe dérivée, au cas ou le type de l'objet à sérialisé et le type de la classe contenant la fonction membre serialize sont différent.

Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
 
#ifndef ODFAEG_ARCHIVE
#define ODFAEG_ARCHIVE
#include <vector>
#include <fstream>
#include "serialization.h"
namespace odfaeg {
class OTextArchive {
public :
    OTextArchive(std::ofstream& buffer) : buffer(buffer) {
 
    }
    template <typename T>
    operator& (T& data) {
        buffer<<data;
    }
    template <typename T>
    operator& (T* data) {
        buffer<<*data;
    }
    template <typename T>
    operator& (std::vector<T>& data) {
        buffer<<data.size();
        for (unsigned int i = 0; i < data.size(); i++)
            buffer<<data[i];
    }
    template <typename T>
    operator& (std::vector<T*> data) {
        buffer<<data.size();
        for (unsigned int i = 0; i < data.size(); i++)
            buffer<<(*data[i]);
    }
    template <typename T>
    void save (T object, void(T::*func)(OTextArchive&)) {
        (object.*func)(*this);
    }
    template <typename B, typename D>
    void save (B* base, void(D::*func)(OTextArchive&)) {
        (static_cast<D*>(base)->*func)(*this);
    }
    template <typename C>
    void operator<<(Serializable<C>* object) {
        void(C::*func)(OTextArchive&);
        object->getSerializeFunc(&func);
        save(object, func);
    }
private :
    std::ofstream& buffer;
};
class ITextArchive {
public :
    ITextArchive (std::ifstream& buffer) : buffer(buffer) {
    }
    template <typename T>
    operator& (T& data) {
        buffer>>data;
    }
    template <typename T>
    operator& (T* data) {
        data = new T();
        buffer>>*data;
    }
    template <typename T>
    operator& (std::vector<T>& data) {
        int size;
        buffer>>size;
        for (unsigned int i = 0; i < size; i++)
            buffer>>data[i];
    }
    template <typename T>
    operator& (std::vector<T*> data) {
        unsigned int size;
        buffer>>size;
        for (unsigned int i = 0; i < size; i++) {
            T* vi = new T();
            buffer>>(*vi);
            data.push_back(vi);
        }
    }
    template <typename T>
    void load (T object, void(T::*func)(ITextArchive&)) {
        (object.*func)(*this);
    }
    template <typename B, typename D>
    void load (B* base, void(D::*func)(ITextArchive&)) {
        (static_cast<D*>(base)->*func)(*this);
    }
    template <typename C>
    void operator>>(Serializable<C>* object) {
        void(C::*func)(ITextArchive&);
        object->getSerializeFunc(&func);
        load(object, func);
    }
private :
    std::ifstream& buffer;
};
}
#endif // ODFAEG_ARCHIVE

Lors de la déclaration de ma classe de base, je dois passer en paramètre template le type réel de l'objet.

Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
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
 
class BaseObjet : public odfaeg::Serializable<D> {
public :
    BaseObjet(std::string name) {
        this->name = name;
    }
    template <typename Archive>
    void serialize (Archive & ar) {
        ar & name;
    }
    virtual std::string getName() {
        return name;
    }
private:
    std::string name;
 
};
class ObjetToutBete : public BaseObjet<ObjetToutBete> {
    public:
    ObjetToutBete(std::string name) : BaseObjet("Base objet de objet tout bete") {
        this->name = name;
    }
    template <typename Archive>
    void serialize (Archive & ar) {
        BaseObjet::serialize(ar);
        ar & name;
    }
    std::string getName() {
        return BaseObjet::getName() + "\n" + name;
    }
private :
    std::string name;
};

Ensuite je dois lors de la déclaration, indiquer que le type réel du pointeur est ObjetToutBete.

Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
 
int main(int argc, char* args[])
{
    std::ofstream ofs("FichierDeSerialisation");
    BaseObjet<ObjetToutBete>* ob = new ObjetToutBete("un objet tout bete");
    odfaeg::OTextArchive oa(ofs);
    oa<<ob;
    std::ifstream ifs("FichierDeSerialisation");
    odfaeg::ITextArchive ia(ifs);
    ia>>ob;
    std::cout<<ob->getName()<<std::endl;
}

Ok ça marche et j'ai bien tout dans le fichier

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
 
Base objet de objet tout beteun objet tout bete
Alors je me demandais si il n'y aurais pas moyen de faire mieux... (sans utiliser une "registration" de type car ça, ça ne marche pas très bien surtout quand j'ai une classe C qui dérive d'une classe B et ensuite une classe A qui dérive de B)
Car quand je passe BaseObjet en template ça me renvoie une erreur de compilation :
Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
 
BaseObjet<BaseObjet>* ob = new BaseObjet("un objet de base");

Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
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
 
||=== Build: Debug in ODFAEG-DEMO (compiler: GNU GCC Compiler) ===|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp||In function ‘int main(int, char**)’:|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|81|error: type/value mismatch at argument 1 in template parameter list fortemplate<class D> class BaseObjet’|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|81|error:   expected a type, got ‘BaseObjet’|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|81|error: invalid type in declaration before ‘=’ token|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|81|error: expected type-specifier before ‘BaseObjet’|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|83|error: no match foroperator<<’ (operand types are ‘odfaeg::OTextArchive’ andint*’)|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|83|note: candidates are:|
/usr/local/include/odfaeg/Core/archive.h|41|note: template<class C> void odfaeg::OTextArchive::operator<<(odfaeg::Serializable<C>*)|
/usr/local/include/odfaeg/Core/archive.h|41|note:   template argument deduction/substitution failed:|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|83|note:   mismatched types ‘odfaeg::Serializable<C>’ andint’|
/usr/local/include/odfaeg/Math/matrix3.h|147|note: std::ostream& odfaeg::operator<<(std::ostream&, const odfaeg::Matrix3f&)|
/usr/local/include/odfaeg/Math/matrix3.h|147|note:   no known conversion for argument 1 from ‘odfaeg::OTextArchive’ to ‘std::ostream& {aka std::basic_ostream<char>&}’|
/usr/local/include/odfaeg/Math/matrix4.h|165|note: std::ostream& odfaeg::operator<<(std::ostream&, const odfaeg::Matrix4f&)|
/usr/local/include/odfaeg/Math/matrix4.h|165|note:   no known conversion for argument 1 from ‘odfaeg::OTextArchive’ to ‘std::ostream& {aka std::basic_ostream<char>&}’|
/usr/local/include/odfaeg/Math/matrix2.h|119|note: std::ostream& odfaeg::operator<<(std::ostream&, const odfaeg::Matrix2f&)|
/usr/local/include/odfaeg/Math/matrix2.h|119|note:   no known conversion for argument 1 from ‘odfaeg::OTextArchive’ to ‘std::ostream& {aka std::basic_ostream<char>&}’|
/usr/local/include/odfaeg/Math/vec2f.h|205|note: std::ostream& odfaeg::operator<<(std::ostream&, const odfaeg::Vec2f&)|
/usr/local/include/odfaeg/Math/vec2f.h|205|note:   no known conversion for argument 1 from ‘odfaeg::OTextArchive’ to ‘std::ostream& {aka std::basic_ostream<char>&}’|
/usr/local/include/odfaeg/Math/vec4.h|241|note: std::ostream& odfaeg::operator<<(std::ostream&, const odfaeg::Vec3f&)|
/usr/local/include/odfaeg/Math/vec4.h|241|note:   no known conversion for argument 1 from ‘odfaeg::OTextArchive’ to ‘std::ostream& {aka std::basic_ostream<char>&}’|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|86|error: no match foroperator>>’ (operand types are ‘odfaeg::ITextArchive’ andint*’)|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|86|note: candidates are:|
/usr/local/include/odfaeg/Core/archive.h|88|note: template<class C> void odfaeg::ITextArchive::operator>>(odfaeg::Serializable<C>*)|
/usr/local/include/odfaeg/Core/archive.h|88|note:   template argument deduction/substitution failed:|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|86|note:   mismatched types ‘odfaeg::Serializable<C>’ andint’|
/usr/local/include/odfaeg/Math/matrix4.h|166|note: std::istream& odfaeg::operator>>(std::istream&, odfaeg::Matrix4f&)|
/usr/local/include/odfaeg/Math/matrix4.h|166|note:   no known conversion for argument 1 from ‘odfaeg::ITextArchive’ to ‘std::istream& {aka std::basic_istream<char>&}’|
/home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|87|error: request for member ‘getName’ in ‘* ob’, which is of non-class type ‘int’|
||=== Build failed: 7 error(s), 0 warning(s) (0 minute(s), 4 second(s)) ===|

Et la seconde chose est que je n'arrive pas à mettre un int dans un std::streambuf et je n'ai pas trouvé beaucoup de documentation là dessus.

Alors voilà je voudrais savoir comment faire ça.

Merci d'avance.