D'accord...:DCitation:
Envoyé par Miles
Donc, par déduction. Si je travaille depuis la classe Choc. Comme j'ai un CFP*, je ne peux pas faire de :
C'est bien ça?Code:cfp->getNomComposant();
Une méthode pour palier à ce problème?
Version imprimable
D'accord...:DCitation:
Envoyé par Miles
Donc, par déduction. Si je travaille depuis la classe Choc. Comme j'ai un CFP*, je ne peux pas faire de :
C'est bien ça?Code:cfp->getNomComposant();
Une méthode pour palier à ce problème?
Ben si, tu as un CFP*, donc tu y accèdes avec ->...
Dans ton exemple, tu avais une Camera, donc c'est directement '.', c'est du C++ classique...
Ok ok, c'est que la POO a tendance à embrouiller mes connaissances en C++!;)
Je vais essayer de pondre une version, et demain je montre mes soucis (j'espère ne pas en recontrer mais bon...)
Je devrais rapidement passer du côté forum C++ je pense...:D
Merci Miles
De rien ;)
Effectivement, maintenant, ça peut être plus du C++ que de la conception ;)
Le mieux est sans doute un nouveau sujet dans le forum C++, pour laisser une trace ici pour les autres :D
OK ! Juste une dernière question Miles:
Quand je crée un Choc (c'est inévitablement le point de départ!), j'utilise le constructeur qui prend entre autre comme paramètres le numero_choc... Cette donnée étant très importante pour les autres classes, j'ai deux solutions:
1) Soit j'écris tous les constructeurs des autres classes de façon à ce qu'ils prennent comme paramètre numero_choc, de même pour les méthodes en ayant besoin. Je me débrouille alors pour boucler tout ce qui a besoin de numero_choc d'un coup dans le constructeur.
Inconvénient : Une fois que la classe est instancié:impossible de retrouver le numero_choc (à moins que tu aies une méthode !!)
2) Chaque classe a un attribut privé numero_choc que je rempli lors de l'appel du constructeur.
Inconvénient : Ca fait le même attribut dans toute les classes, qui est identique partout... Je sais pas si c'est génial!!!
J'aimerai vraiment avoir ton retour là dessus ! :D
Si tu en as besoin partout, de ce numéro, autant le donner partout, c'est pas un problème.
Même si ça fait pas vraiment parti de la Classe (i.e : rien à voir avec l'objet )?
C'est clair, c'est limite, mais bon, ça serait se casser la tête pour pas grand chose, AMHA.
Oui, je pense aussi...
J'ai encore une p'tite interrogation: j'ai des fonctions (typiquement affichage par transparence de deux images) que je ne sais pas vraiment encore où ranger... Soit je crée une autre classe, soit je la laisse en fonction libre!
Je ne perçois pas bien les limites de la POO, j'ai l'impression que si je fais pas tout rentrer dans des classes, comme ils le font si bien à l'école, c'est pas de la POO propre ?:mrgreen:
classe ou libre ?:aie:
Une fonction libre peut appartenir à une classe, ça dépend si elle est fournie avec ou pas :)
L'avantage des fonctions libres, c'est que si elles sont bien faites, elles peuvent épargner la réécriture d'elles-mêmes : une classe polymorphique avec une fonction libre appelant des fonctions virtuelles.
Tout faire rentrer dans une classe, ça donne des trucs horribles comme la classe std::string qui est un grois bloc infâme.
Dans mon cas, je parle surtout de fonction de mon cru (donc pas très bien faite :mrgreen: )!Citation:
Envoyé par Miles
CE qui me chagrine, c'est qu'une fonction AffichageMix() a peu de point commun avec une classe CFP (un peu quand même, mais bon)!
Comme tu le dis, j'ai peur qu'à la fin, tout soit mis n'importe comment dans la classe, ça va devenir le b...
D'un autre côté, une fonction libre, pour moi, c'est une fonction mis dans un fichier outils.cpp à côté. Bof bof:roll:
J'ai choisi la solution de recopier le numero_choc là où j'en ai besoin. Ca me parait pas mal!;)
Une autre (dernière?) question:
Y a t-il un moyen pour que toutes les variables numero_choc soient identiques?
Ou bien faudra -til prévoir une mise à jour vers les autres classes lorsque je ferai:Le problème peut-être: si j'ai envie de rajouter d'autres classes!:mrgreen:Code:choc.setNumeroChoc(36547)
Merci!
A priori, la seule manière qu'elle soient identiques, c'est que ce soit la même variable, et donc que ce soir une référence dans les classes filles, mais bof.
Ok !
Je pense que le mieux est que dans la méthode qui modifie numero_choc, je fasse "descendre" l'info aux autres classes, qui elles n'auront pas le pouvoir de modifier directement cet attribut ?
Oui, sauf que tu ne pourras jamais leur interdire d'écrire dans cette variable :|
C'est juste...
Pb connu ou de conception ? ;)
Je pense pas que ce soit si grave... Au pire, je peux le déclarer const dans les autres classes que choc ?
C'est un problème qui est dû aux spécificités du langage : une variable d'une instance de classe peut être modifiée par cette instance, c'est normal.
Avec un const, tu ne pourras pas changer la valeur de la variable, depuis ton instance comme depuis l'extérieur.Je n'ai pas de solution simple à ce "problème".
OK c'est bien ce que je craignais. :mrgreen:
J'ai une idée:
Si CFP est une classe abstraite, et ne contient pas de méthode pouvant modifier numero_choc (private). Les deux classes filles (les seules pouvant être instanciées) n'auront donc pas accès à cet attribut, non?:mrgreen:
Ainsi, seul choc pourra modifier numero_choc (car possède un pointeur CFP *)?
Dis moi si je me plante lamentablement dans mon raisonnement!:aie:
Ca pourrait marcher, sauf que la variable dans CFP est private et donc non accessible de l'extérieur...
:aie:
+1
Donc il me faut une méthode pour la modifier.
Donc mon raisonnement est à l'eau complet:haha:
Disons, c'est bien essayé!
ARGG, j'ai encore un problème!
Le constructeur de Choc instancie d'abord un objet Camera, puis CFP.
LE problème, c'est qu'il y a une instance de PDC à créer dans CFP, mais le constructeur de PDC a besoin de coeff_mul, qui n'a pas encore été calculé...
Ce qui veut dire que je ne peux pas mettre
Mais seulement:Code:
1
2
3
4
5 CFP::CFP(int num_choc, std::string nom_cfp) : numero_choc(num_choc), nom_composant(nom_cfp), CFP(coeff_mul) { //code }
Est ce que je peux instancier comme je viens de le faire juste au dessus??????Code:
1
2
3
4
5
6
7
8 CFP::CFP(int num_choc, std::string nom_cfp) : numero_choc(num_choc), nom_composant(nom_cfp) { zone = 0; //suite PDC(coeff_mul); }
Merci!
de toute manière, CFP est un pointeur, donc c'est un new que tu vas faire, donc tu peux toujours intialiser ton pointeur à NULL et ensuite lui donner un autre pointeur.
euh... oui mais PDC fait parti des attributs de CFP, non?
Le problème est pour PDC! Comment l'initialiser, sachant que je ne connais pas coeff_mul?
Je ne peux pas le créer autrement!
A ce moment-là, ne le construis que plus tard.
Est-ce que ça marche pour le "plus tard"? ;)Code:
1
2
3
4
5
6
7
8 CFP::CFP(int num_choc, std::string nom_cfp) : numero_choc(num_choc), nom_composant(nom_cfp) { zone = 0; // code pour initialiser coeff_mul PDC(coeff_mul); }
J'en sais rien, ça dépend du reste de ton code.
Ah bon... 8O
Voilà mon code presque complet de cfp.h:
Et voilà le code de cfp.cpp:Code:
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 class CFP { friend ajusterTailleVisibleEtIR(); public: CFP(int num_choc, std::string nom_cfp); ~CFP(); CImg <unsigned short> getImageIR(); virtual setImageIR(CImg <unsigned short>); CImg <unsigned short> getImageVisible(); setImageVisible(); CImg <unsigned short> warping(); std::string getNomComposant(); setNomComposant(std::string); virtual setZone(int); int getZone(); affichageMix(float, bool, float, bool); private: PDC pdc; CImg <unsigned short> image_IR; CImg <unsigned short> image_visible; CImg <>champ_deformation; std::string nom_composant; int zone; int numero_choc; float coeff_mul; }
Code:
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 CFP::CFP(int num_choc, std::string nom_cfp) : numero_choc(num_choc), nom_composant(nom_cfp) { zone = 0; setImageVisible(); setImageIR(); ajusterTailleVisibleEtIR(); // Création des Points de Controle PDC(coeff_mul); } CFP::ajusterTailleVisibleEtIR() { coeff_mul = 0.5f*( static_cast<float>(LARGEUR_ECRAN) /static_cast<float>(IR.dimx()) ); IR.resize(static_cast<int>(-100*coeff_mul), static_cast<int>(-100*coeff_mul), 1, 3, 1); visible.resize(IR.dimx(), IR.dimy(), 1, 3, 1); } CFP::setNomComposant(std::string nom_cfp){nom_composant = nom_cfp;} CFP::getNomComposant {return nom_composant;} CFP::setImageVisible() { CImg <unsigned short> visible (nom_composant); image_visible = visible; } CFP::setImageIR(int num_choc) { int num_cam = camera.getNumeroCamera(); int *nbimages = new int[1]; int cr = IRnb_images(numchoc, numcam, &nbimages); importImage(num_choc, num_cam, static_cast<long> floor(nbimages*0.5 ), static_cast<long> floor(nbimages*0.5 ), ; delete[] nbimages; }
Euh... C'est supposé faire quoi pour toi, PDC(coeff_mul); à cet endroit du code ?
1) Il y en a plusieurs. Le plus répandu, qu'il est important d'assimiler avec les langages statiquement typés comme le C++ (Java, ...), c'est l'héritage en vu de la substituabilité. Là où on attend un objet d'un type Parent, on peut accepter (sans rupture de contrats et d'invariants) un objet d'un type fils. C'est le LSP (principe de substitution de Liskov), c'est fortement lié au polymorphisme d'inclusion (obtenu en C++ avec les fonctions membres virtuelles), c'est très étroitement lié à l'héritage public en C++.Citation:
Envoyé par poukill
C'est à dire, hériter publiquement implique que la syntaxe du langage permet de tenter de substituer un objet d'un type fils là où l'on attend un type parent. Si ces types n'ont pas été écrits pour être substituables, alors le risque de mauvaises surprises est assez élevé en cas d'héritage public. Exemples types de non substituabilité: en informatique, un carré n'est-pas-un rectangle, une liste triée n'est-pas-une liste.
On entend aussi parfois parler d'héritage "est-un", celui qui permet d'"être utilisé en place de"
L'héritage peut aussi être utilisé pour "réutiliser du code". Une classe peut être "implémentée en termes" d'une autre classe. C'est une alternative à la délégation (un traitement est délégué à une autre classe) ; alternative plus fortement couplée. Le C++ permet facilement de mettre en oeuvre ce type d'héritage sans permettre, syntaxiquement parlant, la substitution. Cela se fait avec l'héritage privé. Je crois qu'Eiffel a aussi sa propre façon de faire pour mettre en oeuvre un héritage de réutilisation. Java et quelques autres en sont incapables, i.e. seule la composition peut être utilisée pour définir proprement une liste triée à partir d'une liste dans ces langages.
C'est un héritage qui a beaucoup été vendu (à tord AMHA) dans les années 80/90.
Il y a d'autres approches de l'héritage que j'utilise assez peu: pour rajouter du code à une classe existante, ... J'avais croisé un résumé plutôt pas mal sur wikipédia (en français ou en anglais, je ne sais plus).
2) J'écris régulièrement des classes sans données. Parce que le pattern stratégie ne requiert pas nécessairement la présence d'une donnée -- je spécialise des comportements en fonction de la stratégie courante (qui se substitue à une classe qui décrit de manière assez "abstraite" le traitement à réaliser). Parce que parfois en méta-prog j'ai besoin de classes particulières polices, traits ou autres qui ne définissent que des types ou des fonctions.
...
La donnée encapsulée n'est pas ce qui caractérise une classe chez moi. Je réfléchis beaucoup plus en termes d'abstraction. La donnée encapsulée n'étant alors généralement qu'un détail d'implémentation.
3) On essaie d'avoir un couplage intelligent entre les classes. Même si on peut pafois avoir des classes de données, il est tout à fait courant d'avoir des classes qui définissent en fait des rôles. Personnellement, j'ai tendance à priviliéger cette dernière approche -- je manipule en fait assez eu des classes de données. Du coup, les données contenues ne sont qu'un détail d'implémentation (bis). Je m'interresse avant tout aux rôles et services que fournit la classe.
Il n'y a pas de "classes virtuelles" en C++. On a des ABC (Abstract Base Classes) qui sont des classes abstraites. Toutes leurs fonctions peuvent être virtuelles pures (sans implémentation), ce qui ressemble beaucoup aux interfaces de Java, mais aussi à celles que l'on trouve chez COM. Seules certaines fonctions peuvent être virtuelles pures. Cela est un moyen de programmer nativement (avec de l'huile de coude) par contrats -- Java ne le permet pas sans passer par des outils externes de préprocessing.Citation:
Une autre question que je me pose: dois-je déclarer CFP comme classe virtuelle??? Quelles sont les conséquences (je viens du C et du java!!!!)?
Faudra t-il recoder toutes les méthodes dans les classes filles comme en java?
Il est impossible d'instancier un objet d'une classe à laquelle il reste des fonctions membres virtuelles pures.
NB: il existe aussi la notion de "classe de base virtuelle" qui est :
- relative aux classes qui héritent (A peut être une classe de base virtuelle pour B, mais juste une classe de base pour C)
- lié à l'héritage multiple et au partage de membres.
i.e. "virtuel" est utilisé dans deux contextes différents.
Beurk. Je n'aime pas cette approche car il est très facile d'oublier d'appeller ce qui doit l'être. Quand cela est possible (pas toujours pratique de la mettre en oeuvre simplement), je préfère le design pattern template method->Citation:
Oui, je me souviens de mes cours de POO en java. L'idée était toujours d'appeler une méthode de la classe mère...
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 struct Base { void f() { trucs_f_toujours_faits_pre(); do_spe_f(); trucs_f_toujours_faits_post(); } private: virtual do_spe_f() { /*rien par defaut; ou virtuel pur*/} }; struct Specialization : public Base { private: virtual do_spe_f() { /*trucs propres à la spécialisation*/} };
J'espère bien que c'est le cas. Les classes filles qui définissent des données, voient ces données se rajouter à celles de la classe mère. Si les données portent le même nom, alors on perd l'accès (simple) aux données (au plus protégées) de la classe mère. Il y a un processus de masquage, valable sur tous les membres (données comme fonctions), à quelques nuances près.Citation:
2) Les classes filles peuvent-elle avoir des variables qui ne sont pas dans la classe mère? Si oui, est-ce souhaitable? (en fait je ne pense pas que ce soit pas possible, mais n'étant pas sur...)
Quand on ne peut pas fournir de comportement par défaut qui ait un sens pour une fonction membre, alors "virtuelle pure" est le meilleur choix.Citation:
...virtuel pur
C'est aussi la seule façon de définir une ABC: une ABC est une classe qui dispose d'au moins une fonction membre virtuelle pure.
<pinaillage>"méthode" ne fait pas partie de la terminologie C++. Certains comprennent ça comme "fonction membre". D'autres considèrent que ce sont des "fonctions membre virtuelles", ce qui me parait assez consistant avec la définition UML : une méthode étant une spécialisation (ou implémentation ?) d'une opération.
</>
C'est le genre de cas où la fonction membre serait statique (car elle ne porte sur aucun objet en particulier) (-> fonction membre de classe). Ici, il me semble que c'est avant tout un artifice pour déclarer la fonction dans une portée, pas pour dire que les fonctions membres des objets (!= classe) peuvent être implémentées à l'aide de fonctions, dans la même thématique, mais qui ne portent sur aucun objet en particulier.Citation:
Pour implémenter une fonction du genre "is_readable (std::string &file)", comme celà est fait dans la FAQ, faut-il créer une classe fichier (pour rester dans l'esprit de la POO), ou bien alors le laisser comme une fonction, et donc créer un fichier outils.cpp où tous ces petits test seront implémentés (moins propre ???)
Bref, j'utiliserai un espace de noms. En plus, c'est extensible.
Cela sent le code orienté données. As-tu réellement besoin des données contenues dans l'objet référencé, ou alors veux-tu réaliser un traitement sur ces données contenues dans l'objet référencé.Citation:
Oui, mais les variables ne sont pas dans la classe ? Je ne peux donc pas faire un simple get ? (cf pièce jointe)
Ma question est donc : comment accéder aux classes par composition? L'amitié est - elle dans mon cas un bon moyen (cf schéma ?)
Même la sérialisation des données est un traitement qui peut être délégué à l'objet qui connait le mieux les données qui définissent son état.
Hum... C'était sensé être un constructeur pour la classe PDC! C'est pas vraiment la bonne syntaxe :aie:Citation:
Envoyé par Médinoc
Et c'est aussi interdit puisque le constructeur ne peut être appelé qu'à l'initialisation, celle-ci se passe dans la liste des initialisations. Mais si tu as un pointeur vers la bête, tu dois faire un new - encore une fois, c'est du C++ ;) -
Grrrr, je vais pas y arriver...
Suite à la magnifique remarque de Luc, je viens de passer la matinée à me documenter (design pattern). J'ai bien analysé la notion de couplage faible (l'idéal). Tout ceci remet un peu en cause mon travail de conception :( .
En effet :
1) La recopie de variable privée dans plusieurs classes à partir de la classe principale Choc(pas toujours mère...)
2) Le problème soulevé plus haut par Médinoc et Miles sur l'instanciation de PDC (non Miles je n'ai pas de pointeurs);)
3) Certains attributs sont placés dans des classes alors qu'ils n'en font parti que pour l'implémentation (mais pas pour le rôle, cf Luc) Donc en gros, s'il est là, c'est pour m'arranger dans le code, alors qu'il faudrait penser objet pur, c'est à dire oublier le côté implémentation. Dur, dur... Ca me rappelle mes cours de java!
4) En outre, certaines fonctions sont mises dans une classe par défaut (comme l'affichage d'une image dans une classe de composant, car en fait, un composant est toujours vu dans mon cas par une image via une caméra CCD)
Tout ceci montre un couplage assez fort entre mes classes, ce qui entraine évidemment un problème d'ordre de création, car Caméra a besoin de CFP pour être construite intégralement (i.e remplir tous ses champs privés) et vice versa...
Voici quand même le code pour la création de PDC. J'aurai espérer l'existence d'une astuce pour créer PDC "plus tard", et pas directement dans le "prototype"... Ca a l'air possible mais uniquement avec un pointeur, pas par composition directe d'après ce que j'ai compris Miles.
Hé oui, il me faut ce fameux coeff_mul pour créer PDC, ce qu'on ne connait pas encore lorsqu'on crée CFP...
Je ne sais pas si un jour je vais voir le bout de ce projet ! :D
MErci à vous tous.
cfp.h :
pdc.h:Code:
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 #ifndef CFP_H #define CFP_H #include "CImg.h" #include <iostream> #include <string> class CFP { friend ajusterTailleVisibleEtIR(); public: CFP(int num_choc, std::string nom_cfp); ~CFP(); CImg <unsigned short> getImageIR(); virtual setImageIR(CImg <unsigned short>); CImg <unsigned short> getImageVisible(); setImageVisible(); CImg <unsigned short> warping(); std::string getNomComposant(); setNomComposant(std::string); virtual setZone(int); int getZone(); affichageMix(float, bool, float, bool); private: PDC pdc; CImg <unsigned short> image_IR; CImg <unsigned short> image_visible; CImg <>champ_deformation; std::string nom_composant; int zone; int numero_choc; float coeff_mul; } #endif
Code:
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 #ifndef PDC_H #define PDC_H #include <vector> #include <fstream> #include <string> #include "CImg.h" typedef std::vector< std::pair <int, int> > tableau; class PDC { public: PDC(float); ~PDC(); void sauveTableau(); void chargeTableau(); void setNomFichier(); std::string getNomFichier(); void setCoeffMul(float coeff_muliplicateur); void ajouterPDCDepart(int a, int b); void enleverPDCDepart(int a, int b); void ajouterPDCArrivee(int a, int b); void enleverPDCArrivee(int a, int b); private: tableau tableau_depart; tableau tableau_arrivee; std::string nom_fichier; float coeff_mul; } #endif
Tu ne peux pas laisser pdc (la variable membre, oui) se construire avec le constructeur par défaut de sa classe puis appeler la fonction membre setCoeffMul()?
Si si! C'est une solution...
Certes! Mais comme je programme comme un pied(;) ), mes classes sont couplées. Or dans le constructeur 'global', c'est à dire celui dont plusieurs autres classes dépendent, va justement remplir ces autres champs privés de ces classes en question...
C'est sans doute encore trop bidouille...
Pour voir mon diagramme -> Page 5 de ce topic. C'est un diagramme maison, mais qui vaut ce qu'il vaut... ;)
Donc... place à la réflexion!:D
Je vais réfléchir encore aux conseils de Luc, et puis je vous montrerai mes propositions demain...
Hum. Attention.Citation:
Envoyé par poukill
C'est très bien d'avoir des attributs qui aident à l'implémentation. C'est un peu l'une de leurs raisons d'être premières.
Ce que je voulais dire est différent.
Ce qui me fait décider du design de mes classes, et en particulier de leur interface publique, ce sont les services qu'elles vont remplir (/rôles qu'elles vont tenir).
Si pour réaliser (là, c'est l'implémentation) ces services j'ai besoin de données, je vais ensuite voir comment disposer de ces données. Là, il y a plein de façons.
Ces données peuvent être obtenues va un autre objet qui va avoir la responsabilité de la fournir (donnée stockée, ou calculée) -- réduire le couplage, c'est aussi ne pas calculer soi-même ce qu'un autre est mieux à même de faire, cela évite de nécessiter des données de plus bas niveau dont on n'a que faire en fait.
Ces données peuvent aussi être des attributs de l'objet courant que l'on stocke en local pour éviter d'aller les chercher au travers de 42 autres objets imbriqués.
C'est assez difficile de parler avec des généralités comme je le fais, car il n'y a que des cas particuliers, et que je n'ai pas eu le temps d'approndir le cas particulier que tu as exposé. Chaque problème appelle à un design unique. (Des recettes peuvent toutes fois revenir, ce sont les Design Pattern.)
OK d'accord, je pense avoir enfin compris! L'interface publique de la classe se décide à la conception. On lui attribue tel rôle, et à une autre classe tel autre. Si besoin est, on peut rajouter des attributs, par commodité (cf ta dernière remarque), ou par besoin.Citation:
Envoyé par Luc Hermitte
Lorsqu'on décide d'ajouter un attribut privé, il va falloir nécessairement rajouter une méthode (pardon, je sais que c'est un terme du java, mais c'est très clair comme ça dans ma tête, alors que fonction membre moins ;) ).
On pourrait déclarer cette méthode publique, dans ce cas, ça va modifier un poil l'interface publique de la classe (grave? pas grave?).
La déclarer en privée va restreindre l'utilisation de celle-ci dans la classe même, donc en local.
Si l'attribut en question n'est recopié que par commodité, alors pour moi il vaudrait mieux laisser private.
Si c'est un attribut calculé ici, et donc devant être accessible par les autres classes, alors évidemment la méthode sera publique!
Dites moi si je dis vrai, ou bien alors si je me suis planté au cours de ce raisonnement!:D
MErci
Non. Quand j'ai des vecteurs dans mes classes, j'ai autre chose à faire que de rajouter des indirections et/ou encapsuler mes push_back. Même combat pour mes mutex, ... Ceci dit, parfois, il m'arrive de définir des accesseurs à accessiblité restreinte (protégés) juste pour montrer que je fais des accès en lecture seule sur tel ou tel attribut. C'est loin d'être systématique.Citation:
Envoyé par poukill
Grave. Un attribut n'est pas nécessairement une propriété. Si tu rajoutes un truc public, c'est pour rajouter un nouveau service, une nouvelle responsabilité. Ce qui faut se demander, c'est si c'est ajout a du sens ou non. En fonction de cela => public ou pas.Citation:
On pourrait déclarer cette méthode publique, dans ce cas, ça va modifier un poil l'interface publique de la classe (grave? pas grave?).
Tout à fait. C'est tout le principe de "attribut qui sert à l'implémentation", "détail d'implémentation", ...Citation:
La déclarer en privée va restreindre l'utilisation de celle-ci dans la classe même, donc en local.
Euh .. Oui.Citation:
Si l'attribut en question n'est recopié que par commodité, alors pour moi il vaudrait mieux laisser private.
Pourquoi "donc" ? Les calculs intermédiaires que tu réalises ne font pas nécessairement parti des services que tu rends. Le maçon ne va pas te laisser la truelle quand il a fini, ni le béton qu'il a gaché et qui n'a pas été utilisé. Les deux sont des données qui servent à l'implémentation, la seconde est calculé. Et le service, c'est monter les agglos.Citation:
Si c'est un attribut calculé ici, et donc devant être accessible par les autres classes, alors évidemment la méthode sera publique!
Tout cela me fait penser au point de FAQ sur les accesseurs. En particulier le distingo attribut (donnée d'implémentation) <-> propriété (donnée exposée via l'interface publique généralisée)
Je dois avouer que je n'ai pas tout compris. :aie:Citation:
Envoyé par Luc Hermitte
Un espace de noms? Je ne vois pas pour l'instant l'intérêt. Pour l'instant, je n'ai fait que les utiliser, mais je n'en ai jamais créé ! ;)
Oui d'accord. C'est finalement très logique. Une fois que l'on a bien en tête qui fait quoi, celà devient relativement facile à écrire!Citation:
Envoyé par Luc Hermitte
Ceci m'amène à une nouvelle question assez générale : celle du couplage entre classes. Admettons que je crée d'autres classes. Apparemment, il vaut mieux créer plus de classes, et ainsi minimiser les couplages entre elles, que de rattacher à tout prix des fonctions ou attribut faisant moyennement parti des classes déjà existantes!Citation:
J'écris régulièrement des classes sans données. Parce que le pattern stratégie ne requiert pas nécessairement la présence d'une donnée -- je spécialise des comportements en fonction de la stratégie courante (qui se substitue à une classe qui décrit de manière assez "abstraite" le traitement à réaliser). Parce que parfois en méta-prog j'ai besoin de classes particulières polices, traits ou autres qui ne définissent que des types ou des fonctions.
Question : est-ce que le design des classes est mauvais si l'ordre de création des classes depuis la classe principale est important?
Exemple : Ma classe Choc est la classe principale, base du programme.
Voici la déclaration de son constructeur:
En rouge, la partie qui coince pour moi... En effet, il est par exemple possible que Camera aie besoin d'Ecran, car dans son constructeur, je fais appel à camera.getLargeurEcran().Code:
1
2
3
4
5 Choc::Choc(int num_choc, std::string nom_cfp) :numero_choc(num_choc), Camera(num_choc, nom_cfp), Ecran(), ... { std::cout << "Choc numero " << num_choc << "cree" <<std::endl ; }
Question donc: Parmis ces deux solutions, laquelle est "bonne":
1) Mes constructeurs sont très complets, et remplissent tous les attributs privés du premier coup (et pas par 0 ou NULL). Dans ce cas, ils vont avoir besoin d'info chez d'autres classes (mieux placés pour contenir l'info) via une méthode publique...
Problème : il faut que la classe qui détinet l'info en question soit déjà crée.
2) Mes constructeurs de classes ne remplissent que les champs qu'ils sont sûr de connaître, et on remplit ensuite gentillement au fur et à mesure ce qu'il manque via méthodes...
J'espère avoir été clair!
Merci beaucoup!:D
Je me demandais... Je suis toujours parti sur :
* de l'héritage
* de la composition
pour créer mon diagramme des classes
Alors voilà : une classe seule (c'est à dire qui n'utilise pas d'héritage et où aucunes autres classes ne l'utilisent par composition) est-elle une abérration?
Je me pose la question puisque :
PDC pourrait être retiré de cette classe. Ainsi ma classe PDC serait sans liens avec les autres classes. Mais elle possederait des méthodes pour interagir avec les autres...Code:
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 class CFP { friend ajusterTailleVisibleEtIR(); public: CFP(int num_choc, std::string nom_cfp); ~CFP(); CImg <unsigned short> getImageIR(); virtual setImageIR(CImg <unsigned short>); CImg <unsigned short> getImageVisible(); setImageVisible(); CImg <unsigned short> warping(); std::string getNomComposant(); setNomComposant(std::string); virtual setZone(int); int getZone(); affichageMix(float, bool, float, bool); private: PDC pdc; CImg <unsigned short> image_IR; CImg <unsigned short> image_visible; CImg <>champ_deformation; std::string nom_composant; int zone; int numero_choc; float coeff_mul; }
Y a t-il une règle générale à suivre dans mon cas?
Merci
Poukill, qui pose et se pose bcp de questions ! ;)
Est-ce que la classe CFP a besoin d'une instance de PDC ?