Bonjour,
J'ai recuperer une classe dont voici un apercu:
Je ne comprend pas a quoi ca sert de retourner le long&.Code:
1
2
3
4
5
6 class CTest { public: long m_Nb; inline long& getNb(void) {return m_Nb;} }
Si qu'elqu'un sait...
Merci
Version imprimable
Bonjour,
J'ai recuperer une classe dont voici un apercu:
Je ne comprend pas a quoi ca sert de retourner le long&.Code:
1
2
3
4
5
6 class CTest { public: long m_Nb; inline long& getNb(void) {return m_Nb;} }
Si qu'elqu'un sait...
Merci
PS: ca marche nickel, a la compilation et a l'execution, c'est juste que je vois pas l'interet.
Tu peux modifier ton attribut m_Nb alors que si tu renvoyais long tout court, tu ne pourrais pas... C'est pas forcément mieux, le comportement est différent...
Ben comment?8O
J'essaye ca mais ca change pas la valeur de ma variable:
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 class test { public: long n; test() { n = 3; } inline long& getTest(void) {return n;} void putTest(long m) { n = m; } }; int main(int argc, char* argv[]) { test* essai = new test(); long a; printf("Test = %d\n", essai->getTest()); essai->putTest(5); printf("Test = %d\n", essai->getTest()); a = essai->getTest(); printf("Test = %d\n", a); a = 2; printf("Test = %d\n", essai->getTest()); return 0; }
a est un long, pas une référence, si tu veux modifier n, il faut le faire avant de transformer la référence en long !
Ensuite, si tu a un getTest comme ça, tu devrais aussi avoir le même qui ne retourne pas de référence en version constante.Code:essai->getTest() = 4;
wow puissant!!!
Donc je suppose que l'interet c'est de faire d'une pierre 2 coups: un put/get en quelque sorte!
Ok, merci a vous:DCode:
1
2
3
4
5
6 long getNb() putNb(long) devient long& Nb()
C'est juste une manière masquée et plus verbeuse de rendre publique une donnée membre. D'autant plus que dans ton cas elle l'était déjà, c'est donc complétement inutile.
lol:D c'etait justement ce que j'etais en train de me dire.
en fait ca sert pas a grand chose, meme si la variable etait priver, si c'est pour faire ca, autant la rendre public, ca evitera de taper des parenthese en plus:mouarf:
et c'est mem plutot dangereux, car généralement, un getter est une fonction const :
ce qui veut dire qu'elle n'a pas le droit de modifier l'intégrité de l'objet sur lequel elle travailleCode:long getVal(void) const { ... }
Ah non, ça sert tout de même à plus que cela. On peut protéger l'accès tout de même, c'est pas mal.
Le jour où il faut effectuer une action à chaque accès, ça sera facile de le gérer avec une variable privée et ce type d'accesseur.
Alors dans ce cas question:
Pour les fonctions inline, le code est bien remplacer, n'est-ce-pas?
Donc pour le compilo:
Pour cette fonction, le code :Code:inline long& Nb() {return m_Nb;}
deviendrait:Code:pointeur->Nb() = 5;
Non? (j'avoue que je sais pas trop comment ca marche mais si j'ai bien compris, c'est comme ca).Code:pointeur->m_Nb = 5;
Je suppose qu'il faudrait voir en assembleur ce qui sort(comment on fait avec VisualC++2005).
Dans ce cas quel interet de ne pas mettre la variable directement en public?
cf mon message précédent.
parce qu'on ne met jamais des données membre en public d'une facon généraleCitation:
Envoyé par kacedda
Bouh... le mauvais conseil ;)Citation:
Envoyé par toxcct
C'est comme ça qu'on se retrouve à écrire ce genre de code pas beau :
De manière plus générale, lorsqu'on a à manipuler des données sans aucune encapsulation, l'accès publique est beaucoup plus pratique.Code:
1
2
3
4
5 Vector3D v; v.SetX(v.GetX() + v.GetZ()); // Moi je préfère écrire ça : v.x += v.z;
:applo:Citation:
Envoyé par toxcct
Perso, je préfère :Citation:
Envoyé par Laurent Gomila
Code:v.x() += v.z();
A moi!
Je préfère soit vraiment encapsuler (classe orientée rôles/services),
(ce qui dans un cas pareil est vite ridicule)Code:v.addZintoX();
soit vraiment ne pas faire semblant d'encapsuler (=> comme laurent) (classe orientée données)
Perso, j'aimerai bien qu'il y ait des propriétés en C++, histoire de pouvoir écrire v.x += v.z; et que ça fasse v.setX(v.getX()+v.gtZ()). Ne serait-ce que parce que j'ai déjà eu dans des cas de ce type à devoir modifier les accès, par exemple pour logger le nombre d'accès, ou ce genre d'instrumentation. Ou encore pour les classes mathématiques pour pouvoir faire : a.x = 12; cout << a.theta; et autres choses de ce genre.
Malheureusement, ça n'existe pas, et il y a des gens qui y sont assez opposés au comité (je ne sais pas vraiment pourquoi. La principale raison, je crois, c'est que de code qui a l'air de ne pas faire grand'chose peut faire alors beaucoup de choses). Du coup, on se retrouve à devoir choisir entre écrire du code moche, ou écrire du code non évolutif. :pleure:
J'avais une idée que je trouvais pas mal pour surcharger l'opérateur . (que ce soit pour les fonctions ou les variables membres) et qui permettait de faire ce genre de chose, entre autres.
J'en ai parlé sur comp.std.c++ mais j'ai même pas eu une réponse...
Salut,
Si cette manière de voir reste correcte quand tu n'as qu'un seul membre d'un type donné (ici un long) et que tu es sur que ta classe n'en aura jamais qu'un seul, elle devient vite tendancieuse si ta classe doit contenir plusieurs membres d'un meme type, ou qu'elle risque d'évoluer dans ce sens...Citation:
Envoyé par kacedda
Je vais prendre l'exemple tout simple d'une classe "coordonées" (avec un membre x et un membre y s'il s'agit de coordonnées deux dimentions, ou un membre x, un y et un z pour les coordonnées spaciales), mais ce pourrait etre une classe "couleur" (RGB) ou bien d'autres ;)
Ces deux (ou trois) valeurs de meme type peuvent tres bien etre mémorisées au sein de la classe de trois manière différentes:
sous forme séparée
sous la forme d'un tableau "C style"Code:
1
2
3
4
5
6
7
8
9
10 class maclass { public: (...) private: long x; long y; long z; };
sous la forme d'un std::vector (finalement, fort proche du tableau "C style" ;))Code:
1
2
3
4
5
6
7
8 class maclass { public: (...) private: long coord[3]; };
Et tu peux, à tout moment (ou presque) décider de modifier ta classe dans l'une ou l'autre de ces optiques.Code:
1
2
3
4
5
6
7
8
9 class maclass { public: (...) private: std::vector<long> coord[3];//ou n'importe quel autre conteneur, //d'ailleurs (std::list<long> par exemple ;) ) };
Le tout, sans oublier que tu peux tres bien décider à n'importe quel moment que les noms x, y, z ou coord manquent un peu de précision, et donc de leur donner un nom plus explicite :D
Et le problème est toujours le meme, y compris avec les classes "orientées données":
Si tu modifie, pour une raison ou une autre, l'implémentation des membres de ta classe et qu'ils étaient en visibilité publique (donc, sans accesseurs/mutateurs), tout le code qui en dépend (aussi bien le code metier que le code écrit par un utilisateur de la classe que tu aurais fournie sous la forme d'une bibliothèque) devra etre parcourru afin de chercher les endroits où tu accede aux membres afin de le faire correspondre à la nouvelle implémentation (exception faite du passage long coord[3]<==>std::vector<long> coord)...
Et cela peu etre réparti sur un nombre quasi illimité de fichiers :P
Alors que, si tu fournis la classe avec une encapsulation forte (membres privés avec accesseurs et mutateurs ), finalement, si tu décide de modifier l'implémentation, tout ce que tu as à faire, c'est à modifier les mutateurs et accesseurs, vraissemblablement dans un seul fichier, et le tour est joué :D
Et, dans un tel cas, la seule raison de s'éviter à avoir écrire les parenthèses devient... pour le moins légère par rapport au travail d'adaptation à fournir en cas de changements :P
Sauf, bien sur, s'il est clair, sur et certain, que la classe n'évolura plus par la suite (soit par conception, soit par décision arbitraire)...
Comme tu précise que "c'est une classe que tu as récupérée", il semble cohérent que le créateur ait décidé de mettre un accesseur...
Par contre, c'est incohérent par le simple fait d'avoir laissé le membre en visibilité publique, vu que l'accesseur et le membre sont tous les deux visibles de partout :P (une visibilité privée ou, au minimum protégée aurait vraissemblablement été préférable)
A titre personnel, et bien que ce soit plus lourd à l'utilisation, je présume - n'ayant jamais été réellement confronté au problème - que j'aurais tendance à utiliser plutot l'accesseur que le membre lui-même, en espérant (car, si le concepteur a su faire cette erreur, on peut craindre que l'espoir soit vain) que le concepteur aie le bon gout de laisser l'accesseur s'il vient à modifier l'implémentation de la classe :P