|
Publicité ' | |||||||||||||||||||||||
|
|
#1 |
|
Invité régulier
![]() Inscription : janvier 2006 Messages : 155 ![]() |
Bonjour,
J'ai cinq classes A, B, C, D et Z. Dans ma classe Z qui est une classe contenant des symboles, les instances sont soient de type A, B, C ou D. Je souhaiterais savoir pour chaque instance de Z vers quelle instance de A, B, C ou D elle pointe. J'imagine donc un pointeur générique qui pourrait mémoriser un pointeur vers A ou B ou C ou D. La taille des pointeurs vers A, B, C, D n'est pas la même car les classes sont totalement différentes. On pourrait imaginer écrire dans le constructeur de Z : type_symbole = "type_A"; pointeur_vers_classe = new A(...); // constructeur de A Mais je ne vois pas comment déclarer pointeur_vers_classe. Merci pour votre aide |
|
|
00
|
|
|
#2 | ||||||||||
![]() ![]() |
Salut,
Le plus facile pour y arriver, c'est que A,B,C et D fassent partie d'une même hiérarchie de classe (par exemple, que B, C et D héritent toutes les trois de A). Il "suffit" alors d'utiliser un pointeur sur la classe de base, et tu pourra, la substitution aidant, y placer un pointeur sur n'importe quel objet dérivé de la classe de base. Cela pourrait ressembler à quelque chose comme Code :
J'ai, en effet, du mal à imaginer que l'on puisse trouver un point commun "utile et justifié" entre un oiseau, une tronçonneuse, une voiture et une fleur Dans ce cas, il faut utiliser le principe du "type ereasure", et il est sans doute bon de te tourner vers boost::variant (si tes classes on sémantique d'entité) ou vers boost::any, si elles ont sémantique de valeur Comme tu envisages l'utilisation d'un pointeur, tu devrais plutôt te tourner vers boost::variant, mais, ceci dit, il est peut etre utile de réfléchir à la relation réelle qui existe entre Z et les autres classes. En effet, si la relation est "simplement" de se dire que Z "fait référence" à un objet qui peut exister de manière indépendante, le pointeur semble en effet être la meilleure solution, et le choix se tournera "naturellement" sur boost::variant Par contre, si Z utilise "une variable" d'un des autres type, en fonction d'un contexte quelconque et que la dite variable ne peut exister sans qu'il y ait un Z pour s'en occuper, on peut parfaitement envisager le fait de ne pas travailler avec un pointeur, mais carrément avec un objet. Et, si cet objet a sémantique de valeur (qu'il est copiable, et affectable, et qu'il ne fait partie d'aucune hiérarchie de classe), on peut parfaitement envisager l'utilisation de boost::any Mais avant d'en arriver là, il y a malgré tout deux questions qu'il semble intéressant de se poser... La première est celle du but que tu poursuis en plaçant une référence parfois sur un objet de type A, parfois sur un objet de type B, ou C ou D. Est-ce que c'est pour que ta classe Z puisse les manipuler "en interne" (comprend : que l'utilisateur puisse tout ignorer de A, B, C et D quand il manipule Z, une fois qu'elle a été correctement "initialisée"), ou est-ce pour que Z puisse fournir un accès à l'objet référencé La deuxième question est de savoir s'il est vraiment "utile et opportun" de pouvoir disposer, en même temps de deux objets de type Z dont l'un référence un A et l'autre un B (ou un C ou un D) Si tu envisages de ne travailler, à un moment donné, uniquement avec des objets de type Z qui manipulent des A OU uniquement avec des objets de type Z qui ne manipulent que des B (ou C ou D, encore une fois Code :
Code :
On garderait les "helpers" tels que je les ai décrit plus haut, et l'on utiliserait le pattern NVI sous une forme proche de Code :
Code :
Je vais donc m'en arrêter là avant d'écrire un roman, mais n'hésites pas à demander plus d'information si tu ne comprends pas une chose ou l'autre
__________________
en bas de page
|
||||||||||
|
|
20
|
|
|
#3 |
|
Invité régulier
![]() Inscription : janvier 2006 Messages : 155 ![]() |
Merci pour ta réponse.
Je comprends dans la globalité. Ne serait il pas plus simple dans la classe Z d'avoir comme attributs : A* A_pointer; B* B_pointer; C* C_pointer; D* D_pointer; et de documenter le pointeur correspondent suivant le type d'objet A, B, C ou D. Les autres seraient dcumentés avec NULL ? |
|
|
00
|
|
|
#4 |
![]() ![]() |
En terme de facilité, c'est discutable, car tu devrais alors prévoir quatre constructeur, ou les quatre mutateurs directement, avec la difficulté de t'assurer, si tu fournis les mutateurs, que les pointeurs sont tous remis à NULL au moment où tu change de type.
De plus, si ta classe utilise elle-même les pointeurs en interne, tu seras obligé de tester les quatre pointeurs pour savoir lequel référence un objet. Par contre, en terme d'évolutivité, ce serait une catastrophe ![]() Si tu viens, dans quelques mois, à vouloir rajouter une classe E ou une classe F parce que tes besoins ont évolué, tu devras revoir l'intégralité du code de Z, avec le risque d'oublier quelque chose ![]() Avec la solution basée sur un helper, tu n'auras qu'à le spécialiser pour ta nouvelle classe et le tour sera joué (sans avoir à toucher au code existant). De plus, si tu viens à avoir plusieurs helpers exécutant des choses différentes (car, en gros, il y en aura un par comportement
__________________
en bas de page
|
|
|
00
|
|
|
#5 |
|
Invité régulier
![]() Inscription : janvier 2006 Messages : 155 ![]() |
Merci.
Pourrions nous expliciter la première approche du helper qui me paraît plus simple. Pourquoi dans la classe template MyHelper fais tu une surcharge d'opérateur ? Qu'entends tu par "traitement spécifique à ..." ? |
|
|
00
|
|
|
#6 | ||||||||
![]() ![]() |
Citation:
Une classe qui ne contient qu'une seule fonction que l'on peut appeler à l'aide des (), sous une forme proche de Code :
Par exemple, si tu envisage d'avoir un tableau de A, et que tu veux parfois le trier sur A.truc() et parfois sur A.machin(), tu peux très bien envisager d'avoir un foncteur qui comparera first.truc() à second.truc() et un autre qui comparera first.machin() à second.machin() afin de savoir, dans les deux cas, lequel est le plus petit. Le tri pourra alors se faire en une seule ligne grace à la fonction sort, disponible (comme tout ce qui est fourni par le standard) dans l'espace de nom std par simple inclusion du fichier d'en-tête <algorithm> sous la forme de Code :
Code :
Citation:
Si les classes A, B, C et D n'ont aucune relation d'héritage, il y a fort à parier (même si ce n'est pas forcément certain Le "traitement spécifique à..." correspond à tout ce qui sera propre à ton objet de type A, B, C ou D et qui n'est pas forcément utilisable avec les autres types
__________________
en bas de page
|
||||||||
|
|
00
|
|
|
#7 |
|
Invité régulier
![]() Inscription : janvier 2006 Messages : 155 ![]() |
Si tu permets nous allons expliciter un peu.
Il s'agit d'une partition de musique. Ma classe Z est la classe MESURE qui contient pour attributs : - son numéro - un vecteur de pointeurs sur la classe SYMBOLE Un symbole peut être de type NOTE, TEXTE ou ICONE. Il s'agit donc de 3 classes (pas 4 Lorsque je vais balayer ma partition, je vais par exemple rencontrer une clef de Fa qui esr de type ICONE. Je vais donc instancier ICONE et récolter un pointeur. Comment dois je définir la classe SYMBOLE et la classe MyHelper pour dire à la classe SYMBOLE que mon premier symbole est de type ICONE et qu'il pointe vers la clef de Fa ? |
|
|
00
|
|
|
#8 |
|
Expert Confirmé
![]() Pierre Ingénieur développement logiciels Inscription : juin 2007 Messages : 1 185 ![]() |
et tu ne peux pas avoir une classe de base (affichable ou autre)?
__________________
Mes principes de bases du codeur qui veut pouvoir dormir:
|
|
00
|
|
|
#9 | ||
|
Invité régulier
![]() Inscription : janvier 2006 Messages : 155 ![]() |
Au départ, j'ai créé une classe instrument qui a des classes filles :
Code :
|
||
|
|
00
|
|
|
#10 |
![]() ![]() |
En fait, cela me fait furieusement penser à une discussion (ouverte par toi, d'ailleurs) à laquelle j'ai répondu il n'y a pas si longtemps et dans laquelle je présentais une conception possible pour la notion de partition (et pour laquelle tu n'as jamais répondu, soit dit en passant
)...Peut etre pourrais tu te baser sur ma prose en considérant qu'un instrument est, quoi qu'il arrive, un instrument, même si certains (comme le piano ou la guitare) permettent de jouer plusieurs notes en même temps et que d'autres (comme les instruments à vent de manière générale) ne permettent que d'en jouer une seule... Tu pourrais alors considérer que chaque instrument dispose de sa propre partition, mais que la partition n'a aucun besoin de pouvoir dire à quel instrument elle est reliée Comme je l'ai fait remarquer dans l'intervention que je cite ici, tu dois clairement faire la différence entre ta partie "métier" (les instruments, les notes, les partitions et tout le saint frusquin) et la partie qui s'occupe de les afficher d'une manière ou d'une autre. Les classes que je présentais à l'occasion de cette intervention fournissent normalement tout ce qui te sera nécessaire pour l'affichage (ou peu s'en faut), sous n'importe quelle forme, étant entendu que ce n'est ni à l'instrument, ni à la partition, ni au note ni à quoi que ce soit d'autre issu de la partie "métier" de prendre en charge une quelconque responsabilité d'affichage. En effet, si tu décides de donner la responsabilité de l'affichage aux éléments de ta partie "métier", tu contreviens à plusieurs principes considérés comme les "piliers de base" de la programmation orienté objects que l'on connait sous l'aconyme de SOLID(dont, au minimum, le S, en l’occurrence En séparant clairement ta vue (ton affichage) de ton modèle (la partie métier), tu prendras la voie d'un respect de l'ensemble de ces principes, et tu te mettras en position de faire évoluer beaucoup plus facilement ton application
__________________
en bas de page
|
|
|
10
|
|
|
#11 |
|
Invité régulier
![]() Inscription : janvier 2006 Messages : 155 ![]() |
Merci beaucoup pour tous ces conseils
|
|
|
00
|
Copyright © 2000-2013 - www.developpez.com