J'ai une question de fond sur les classes et leur typage en c++, que j'illustrerai avec l'histoire suivante:
Imaginons une usine de traitement de colis.
Elle dispose d'un traitement automatisé des colis sur un tapis roulant qui classe et dirige les paquets au bon endroit suivant un code barre qui est associé dans une base de données à d'autre informations ("poids", "taille", "type", +paramètres fonction du type), ET d'un traitement spécial pour les colis pour lesquels le code barre est illisible automatiquement.
Ces colis illisibles sortent d'un tapis roulant vers un opérateur.
Ils sont d'abord automatiquement pesés et mesurés avant leur arrivée et le poids est annoncé sur un écran.
L'opérateur doit ensuite manuellement déterminer le type de colis parmis "Fragile", "Normal" et "Solide"
Et compléter selon ce type les paramètres demandés:
-pour "Fragile" il doit donner la "pression max" autorisée pour le colis
-pour "Normal" il ne donne rien
-pour "Solide" il doit donner le "type de matériaux" contenu dans le colis
Si on regarde maintenant au sens C++ les objets:
J'ai un objet "Colis" générique qui va être traité par l'opérateur et qui contient le poids et la taille. Et en sortie du traitement de l'opérateur, J'ai 3 types d'objets qui ont des propriétés différentes selon leur type.
J'avais pensé faire (c'est du pseudo_code c++, je ne l'ai pas compilé donc erreurs possible, mais l'idée reste la même):
En refaisant l'histoire:
Code : 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 class Colis{ public: virtual int get_destination(){} int poids; int taille; }; class Colis_Fragile: public Colis{ public: int get_destination(){ return 1; } int pression_max; }; class Colis_Normal: public Colis{ public: int get_destination(){ return 2; } }; class Colis_Solide: public Colis{ public: int get_destination(){ return 3; } char *type_de_materiau; };
Ma question est la suivante, que pourrait t'on mettre dans le switch à la place des --->???<--- ?
Code : 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 ... //le colis existe Colis *un_colis = new Colis(); //il est pesé et mesuré par la machine un_colis->poids = pese(); un_colis->taille = mesure(); //puis il est présenté à l'opérateur affichage_infos(un_colis); // et on lui demande de typer ce colis switch(demande_du_type_de_colis()){ case TYPE_FRAGILE: //-->???<--- break; case TYPE_NORMAL: //--->???<--- break; case TYPE_SOLIDE: //--->???<--- break; } //maintenant que le colis est typé, la machine peut le gérer //en demandant à l'objet sa destination int destination=un_colis->get_destination(); ...
A ma connaissance on ne peut pas changer le type d'une classe mère en une classe fille. En effet l'objet construit est bien celui de la classe mère et ne contient pas les données supplémentaires de la fille.
D'un autre côté si on veut respecter l'ordre de l'histoire on ne peut pas typer notre Colis tant qu'on ne l'a pas identifié, mais on peut déjà lui avoir renseigné des informations (le poids et la taille ici).
Y a t'il quelquechose en c++ de prévu pour "compléter" un objet créé sur une classe de base en le typant fortement et qu'à l'occasion de ce complément, un constructeur pour les données de la classe fille soit appelé afin d'initialiser les données spécifiques au type?
Si les données avaient été recueillies dans un autre ordre, j'aurai par exemple eu le type en 1er, et ainsi pu créer mon objet fille, puis remplir l'ensemble des données de facon sécurisée et propre... MAIS ma question est uniquement dans le cas où les données apparaissent dans cet ordre et où bien évidemment on se refuse de les stocker temporairement dans le but de créer l'objet complet à la fin en une fois.
J'ai plusieurs pistes:
- créer une méthode de la classe mère "Colis *change_type(int type)" qui retourne un pointeur sur un objet dupliqué dans la classe fille spécifiée, mais qui nécessite de bien gérer les destructions et qui oblige à recopier les données lors de la construction de la classe fille.
- créer une méthode de la classe mère "change_type(int type)" qui changerait "this" directement en faisant la même chose... mais je ne sais pas si c'est jouable, et surtout utilisable car avant l'appel à cette fonction, le pointeur de l'objet serait générique et après il serait spécifique, faut voir c'est peut être bien géré.
- changer l'ordre d'héritage des classes, et dire que le colis finalement hérite de tous les types en même temps, du coup le simple opérateur de cast fait la bonne interprétation, mais cela duplique les données, et les objets sont donc plus volumineux.
- ??? autre solution?
Je souhaite conserver une classe différente par type, c'est plus élégant que d'avoir un pointeur "options_du_type" qui pointerait vers des pseudos classes contenant les options spécifiques et venant s'ajouter à l'objet "générique"
C'est bien sur un cas d'école, et je cherche simplement à trouver une solution élégante, optimisée et transparente au possible.
Si j'avais pris l'analogie avec les cellules souches du corps humain par exemple, cela m'aurai mené vers l'héritage multiple, car une cellule souche est au début capable de tout faire et au fur et à mesure de sa spécialisation elle "oublie" pour faire moins de chose, jusqu'à devenir une simple cellule totalement différenciée capable de ne faire qu'une chose.
L'héritage multiple ne me permet cependant pas semble t'il d'oublier qu'on est capable de tout faire, et un objet fortement différencié se trimballerait avec la totalité de ses héritiers.
Du coup, avant de me lancer, je cherche à savoir quelle serait la plus belle solution pour ce type de problème de "typage de classe tardif"
Merci d'avance de vos avis sur le sujet.
Partager