données membres et retour par référence de ces dernières

données membres et retour par référence de ces dernières - C++ - Programmation

Marsh Posté le 12-12-2004 à 18:40:55    

J'ai un petit peu de mal a comprendre quelle est la meilleure facon de coder les accesseurs aux attributs privés d'une classe et vous demande un peu d'éclaircissement à ce propos.
 
Illustrons mon problème avec le code suivant que j'ai l'occasion de voir régulièrement.
 

Code :
  1. class CMaClasse
  2. {
  3.   CMachin m_machin;
  4. public:
  5.   CMachin& getMachin()
  6.   {
  7.     return m_machin;
  8.   }
  9. };


 
Comment se fait-il qu'on renvoie l'objet membre de CMaClasse par référence alors que ça signifie qu'on va donner la possibilité à l'utilisateur de modifier l'attribut sans aucun controle ?

Reply

Marsh Posté le 12-12-2004 à 18:40:55   

Reply

Marsh Posté le 12-12-2004 à 18:46:08    

j'ajouterais un const au début de l'accesseur justement.


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 12-12-2004 à 18:49:23    

C'est ce qui me semble le plus sain mais dans ce cas pourquoi est ce que l'on trouve l'écriture précédente dans une grande majorité des cas ?

Reply

Marsh Posté le 12-12-2004 à 18:50:15    

j'ajouterais egallement un const à la fin de l'accesseur ;-)


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 12-12-2004 à 18:51:01    

Soit parce que les gens ne savent pas/sont stupides
soit parce qu'ils veulent effectivement laisser l'attribut modifiable sans contrôle


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 12-12-2004 à 19:01:46    

moi j'aime bien la façon CORBA
 

Code :
  1. class Foo
  2. {
  3.   T member;
  4. public:
  5.   T Member() const { return this->member; }
  6.   void Member(const T &m) { this->member = m; }
  7. };


 
la copie défensive est peut être de trop, si oui, mettre

Code :
  1. const T& Member() const { return this->member; }

Reply

Marsh Posté le 12-12-2004 à 19:02:33    

Masklinn a écrit :

Soit parce que les gens ne savent pas/sont stupides
soit parce qu'ils veulent effectivement laisser l'attribut modifiable sans contrôle


 
Je suis d'accord avec toi. D'ailleurs dans le deuxième cas, la signature  reste:
 
Machin & CMaClasse::getMachin () const;
 
Et ça, c'est pas automatique pour tout le monde de laisser en const tout ce qui doit l'être par défaut.

Reply

Marsh Posté le 12-12-2004 à 19:04:50    

manque un const là, c'est pas correct

Reply

Marsh Posté le 12-12-2004 à 19:11:01    

Je lis les choses suivantes sur le net :
 

Citation :

A public member function must never return a non-const reference or pointer to member data ([5], Rule 29).
Returning a non-const reference to member data violates the encapsulation of the class.


 
source : http://geosoft.no/development/cppp [...] troduction
 

Citation :

Accessor Styles
 
Accessor methods provide access to the attibutes of an object. Accessing an object's attributes directly, as is commonly done in C structures, is greatly discouraged in C++. It exposes implementation details of the object and degrades encapsulation.
 
There are two accepted ways to implement accessors, the preferable way is the following :
Attributes as objects
 
Example 4-3. Attributes as object accessor style
 
class X
{
public:
    int             age() const     { return mAge; }
    int&            rAge()          { return mAge; }  
     
    const String&   name() const    { return mName; }
    String&         rName()         { return mName; }
private:
    int              mAge;
    String           mName;
}


 
source : http://www.uwyn.com/resources/uwyn [...] /x496.html
 
Ainsi, ok l'accesseur à name est bien retourné en const . Mais pour le mutateur, il renvoie name en reference simple, contredisant la phrase plus haut comme quoi il ne faut jamais renvoyer une reference non constante d'un membre d'une classe .
 
Il faut donc savoir ce que l'on veut.  :??:


Message édité par Blakstaf le 12-12-2004 à 19:18:42
Reply

Marsh Posté le 12-12-2004 à 19:18:37    

Taz a écrit :

manque un const là, c'est pas correct


Oui, tiens, je me suis emmelé les pinceaux en cours de route. Je pensais à la double-signature (une avec const des deux côtés, et une sans rien), et du coup, j'ai oublié d'enlever la référence en retour.
 
Mais en relisant le commentaire de Masklinn, ça colle pas. Je dois être fatigué...
 

Reply

Marsh Posté le 12-12-2004 à 19:18:37   

Reply

Marsh Posté le 12-12-2004 à 21:43:11    

Dans quel cas on prefere la copie defensive ?


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 14-12-2004 à 21:43:50    

Il est pas un peu pourri ton code ?


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 14-12-2004 à 21:53:29    

Si je réécris ton code dans un C++ un peu moins pourri (surtout la ligne9), mon compilateur me repond  "error: static_cast from type `const std::string*' to type `std::string*' casts away constness / error: invalid conversion from `const std::basic_string<char, std::char_traits<char>, std::allocator<char> >*' to `std::string*'
 

Code :
  1. #include<string>
  2. #include<iostream>
  3. using namespace std;
  4. struct CTest 
  5. {
  6.   CTest( const string& s ) : m_strTest( s ) {}
  7.   const string& GetTest() const { return m_strTest; }
  8. private :
  9.   string m_strTest;
  10. };
  11. int main()
  12. {
  13.   CTest o("test" );
  14.   string* p(static_cast<string*>(&(o.GetTest())));
  15.   *p = "Test2";
  16.   cout << o.GetTest();
  17. }


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 14-12-2004 à 21:55:10    

Donc tout va bien, on peut faire un passage par référence de manière sécurisé. Mais ca ne repond pas à ma question.


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 14-12-2004 à 21:59:07    

Non, le complateur ne l'accepte pas visiblement. Je ne pense pas que ton code soit représentatif.


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 14-12-2004 à 22:04:06    

Je crois que ce que tu as démontré, c'est la faiblesse du cast C.
 

Code :
  1. {
  2. const string s = "test";
  3. string* p( (string*)&s );
  4. *p = "test2";
  5. cout << *p << s; // test2test2
  6. }


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 14-12-2004 à 22:14:32    

je dis que ça me donne envie de vomir. Tant que les gens comprendront pas que plus on a de liberté, plus il faut établir des règles strictes, on aura toujours des merdes comme ça. Dans le cas d'une programmation saine, ceci n'arrive jamais. D'ailleurs, je fais gueuler mon compilo pour jeter les cast C

Reply

Marsh Posté le 14-12-2004 à 22:27:32    

aucun. À moins d'avoir un veritable impératif de sécurité (genre mot_de_passe, etc), si quelqu'un s'amuse à corrompre ta bibliothèque, c'est son problème si ça plante comme une merde.
 
Pour les types de bases, une copie suffit amplement cependant.

Reply

Marsh Posté le 14-12-2004 à 22:56:44    

ben si tu travailles en équipe, la moindre des choses c'est d'avoir une charte de codage et comme déjà dit, le compilateur peut aider.
 
Quand je parler de faire une bibliothèque, je voulais dire que si elle est correcte, tu livres, si tes utilisateurs font n'importe quoi, tu les envoies chier, c'est pas ton problème.
 
On va pas se faire chier pour des mecs qui ont un niveau C++ 0. Tu verra souvent sur le forum des gens faire des  

Code :
  1. ((char*)s.c_str())[i] = 'x';

c'est leur problème. Y a un moment, faut être adulte : si tu paies un mec dont le raisonnement se résume à "le compilateur veut pas, je cast"... C'est encore pire si tu paies un mec qui fout des cast machinalement.
 
Faut prendre c'est responsabilité : si tu cast "pour que ça compile", c'est ton problème. Quelqu'un qui fait ça fera également d'autre saloperies. Bref tu peux le réassigner à la documentation.

Reply

Marsh Posté le 14-12-2004 à 23:03:09    

ni l'un, ni l'autre. Je vois juste quand dans les projets OpenSources auxquels je participe, le mec qui vient se plaindre pour des trucs comme ça, on lui rit à la gueule.
 
Et si je travaillais en entreprise, ça serait pareil.
 
je vois pas de différence entre
 
((char*)"bla" )[1] = 'x';
 
et
 
abort();

Reply

Marsh Posté le 14-12-2004 à 23:12:43    

ben ça change rien si t'intègres du C : tu le compiles avec une compilateur C et tu link avec .|
 
 
Niveau exception : d'accord. Mais sur le moyen-terme, quand le volume de code augmente ... les exception / GError, ça t'oblige à penser ta politique de gestion d'erreur __avant__

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed