Bonjour tout le monde.
J'aurais quelques questions en C++, notamment sur certaine pratique de la POO (pas de grande notion,seulement des petites).
Premièrement, quand on est dans une classe et qu'on code un méthode, pourquoi sur code blocks on peut faire (this.variable) et sur Visual Studio je dois faire (this->variable) ?
Deuxièmement, faut-il privilégier l'envoi de paramètre par référence constante pour toutes les fonctions qui ne modifient pas les valeurs ? Ou bien est-ce conseillé seulement pour les grandes valeurs ? (tableau de 500 cases, ...)
Troisièmement, question de principe, imaginons qu'on ait une classe "Heure" et qu'on a une méthode "régler(h,m,s)" et des gets/sets pour des variables privées (heure,minute,seconde) pour le constructeur (heure(h,m,s)) mieux vaut faire
1) Appeller méthode régler
2) Dans la méthode régler, on appelle les setters qui contiennent les conditions nécessaires pour insérer les valeurs)
Où bien y-a-t-il une meilleure solution ?
Quatrièmement, est-il possible, dans un fichier class.cpp qu'avec une astuce quelconque, de ne pas devoir mettre devant chaque méthode class::méthode ? Par exemple utiliser qqch de semblable à un namespace ?
Cinquièmement, lorsque l'on instancie un objet, dans quel cas concret il ne faut PAS utiliser Class obj = new class(); puis utiliser obj->méthode/variable ? En d'autres mots, quand utiliser Class obj; obj.méthode/variable ... ?
Sixièmement, question de principe, est-ce qu'à l'intérieur de la classe, est-il conseillé de toujours utiliser this. ou -> selon l'IDE "ma variable" ou bien c'est une perte de temps inutile ?
Huitièmement, dans mon code, pourquoi dans ma fonction Heure::ajouter je ne peux mas mettre "const Heure&" ?
Et dernièrement, bien que mon code soit cout, y-a-t-il des choses à ne pas faire que j'ai fait ? (Exemple le if/else en ternaire) ? Comment bien organiser sa classe ? (Dans quelle ordre fait les choses? ... (C'est normal s'il n'y a pas de déstructeur, cette notion n'a pas encore été abordée en cours).
Je vous mets mon code ici : http://pastebin.com/NAgGagmn
Et vous remercie de vos réponses/remarques
" pourquoi sur code blocks on peut faire (this.variable) et sur Visual Studio je dois faire (this->variable) ? "
Ça marche vraiment le truc dont tu parles sur Code Blocks?
Car this est un pointeur et on doit donc bien écrire this->truc normalement. ![]()
Pocolo, le this. sur code blocks, c'est quand tu es dans class.cpp. Si tu instancie Classe *obj = new classe(); faudra faire obj->
Enfin, peut-etre la vrai "définition" ça a toujours été this-> dans la classe et code blocks à une option spécifique
"Premièrement, quand on est dans une classe et qu'on code un méthode, pourquoi sur code blocks on peut faire (this.variable) et sur Visual Studio je dois faire (this->variable) ?"
C'est vrai ce mensonge ? J'émets de sérieux doutes... et si ce que tu dis es vrai alors il faut absolument que code blocks corrige cette configuration par défaut bien étrange de la part de leur IDE. M'enfin.
"Deuxièmement, faut-il privilégier l'envoi de paramètre par référence constante pour toutes les fonctions qui ne modifient pas les valeurs ?"
Oui. Pourquoi perdre du temps a copier quelque chose quand on peut seulement le passer par référence, et ce quelle que soit sa taille sous-jacente de toute façon. C'est une bonne façon de coder dans le cas spécifique que tu énonces.
"Troisièmement, question de principe, imaginons qu'on ait une classe "Heure" et qu'on a une méthode "régler(h,m,s)" et des gets/sets pour des variables privées (heure,minute,seconde) pour le constructeur (heure(h,m,s)) mieux vaut faire
1) Appeller méthode régler
2) Dans la méthode régler, on appelle les setters qui contiennent les conditions nécessaires pour insérer les valeurs)
Où bien y-a-t-il une meilleure solution ?"
Pas sûr de comprendre la question. Le but est de toujours éviter du code dupliqué, donc s'il y a un truc que tu fais dans le constructeur qui est littéralement copié-collé d'une autre fonction ainsi la réponse et OUI appelle cette fonction, et comme ça s'il y a un bug tu sais où il est et comment tout régler d'un seul coup.
"Quatrièmement, est-il possible, dans un fichier class.cpp qu'avec une astuce quelconque, de ne pas devoir mettre devant chaque méthode class::méthode ? Par exemple utiliser qqch de semblable à un namespace ?"
Oublie ca tout de suite. Les using c'est mal de toute façon, il faut toujouurs que l'on sache de quoi tu parles en un coup d'oeil et savoir d'où tes méthodes viennent. Ce sont des bonnes pratiques de programmation encore.
"Cinquièmement, lorsque l'on instancie un objet, dans quel cas concret il ne faut PAS utiliser Class obj = new class(); puis utiliser obj->méthode/variable ? En d'autres mots, quand utiliser Class obj; obj.méthode/variable ... ?"
Pas compris. Tu veux dire quand faire un pointeur ou non c'est ça ta question ? En C++ à moins que tu en ais besoin de toute façon le réflexe de base c'est de ne pas faire un pointeur... pourquoi faire compliqué quand on peut faire simple ? Pourquoi prendre le risque des memory leaks ?
"Sixièmement, question de principe, est-ce qu'à l'intérieur de la classe, est-il conseillé de toujours utiliser this"
Non. D'ailleurs je trouve que c'est moche et ne doit pas être une manière de coder par défaut... ça ne l'est généralement pas d'ailleurs ? Me trompe-je ?
Tiens-toi en a des this-> ça t'empêchera de prendre cette mauvaise habitude inutile et d'éviter des erreurs futures.
Tes méthodes getXXX ne sont pas const. (Une méthode const indique que l'instance qui l'appelle ne sera pas modifiée)
Hors dans ajouter tu te sers de ces méthodes non const pour récupérer les secondes etc. de l'instance h de Heure, impossible donc de déclarer constant h.
Pour indiquer qu'une méthode est constante on rajoute const à la fin :
int getSeconde() const;
(voir http://www.parashift.com/c++-faq-lite/const-correctness.html )
En ce qui concerne l'utilisation de pointeurs (new), autant éviter d'en utiliser inutilement. Refais les 4 premières lignes de ton main sans utiliser de pointeurs et regarde la différence. :p
Donc quand tu peux faire sans, fais sans. Et si tu en utilises, n'oublie pas de les delete ensuite. ;)
Je vous remercie de vos réponses déjà.
tbop2, 3) Je disais si c'était mieux d'avoir la méthode de vérification dans le setter et l'avoir qu'une fois (cf code pour mieux comprendre ce que j'essayais d'expliquer)
5) Enfait, pour simplifier la question, est-ce possible d'avoir un constructeur sans utiliser forcément un pointeur avec "new". Si oui comment ? (ce qui reviendrait à ne pas utiliser de pointeur et utiliser this.)
Pour code blocks, je viens de vérifier,sur la dernière version il n'y a pas ce problème, mais mon collègue en classe avait une version 7 ou 8 (distribuée par l'école) maintenant que me rappelle, ça doit être pour ça.
Awesome_Guiber
Donc d'un point de vue logique et performance, est-ce qu'on gagne qqch si l'on met à chaque getter le mot-clé const ? Est-ce conseillé ? Oui/non pourquoi ?
Pour cette histoire de pointeur, même chose que tbop2,5)
encore merci de vos réponses ![]()
Heure h(12,59,52);
appelle tout autant le constructeur que
Heure *h = new Heure(12,59,52);
Ça ne change rien au code de Heure, c'est juste deux façons différentes d'instancier ton objet (statique ou dynamique).
Je ne sais pas si on gagne des performances ou pas à utiliser des const à chaque méthode qui ne modifie pas l'objet, mais c'est la bonne façon de coder. Et d'ailleurs comme tu as pu le constater avec ton ajouter, tu ne peux pas utiliser une méthode non const sur un objet const.
Je savais pas qu'on pouvait faire Heure h(12,59,52); c'est bon à savoir !
Donc si j'ai bien compris, d'un point de vue "bonne pratique", dès qu'on ne modifie pas une valeur, mieux vaut mettre directement const pour des raisons de clartés ?
En tout cas, merci pour ta réponse !
Ton cours est totalement à l'ouest excuse-moi. Ne pas savoir ce qu'est un destructeur à ce niveau là de l'apprentissage ni ne savoir comment initialiser une classe c'est totalement n'importe quoi.
Le const ce n'est pas pour plus de clareté du tout ! C'est pour préciser que l'entité en cause ne doit rien modifier ou ne modifie rien.
Mais un const à tous tes getters. Maintenant fais une fonction qui prend une autre de tes classes en const référence par paramètre et essaye d'appeler un setter dedans tu vas voir ce que ton compiler va dire.
"Oui. Pourquoi perdre du temps a copier quelque chose quand on peut seulement le passer par référence, et ce quelle que soit sa taille sous-jacente de toute façon. C'est une bonne façon de coder dans le cas spécifique que tu énonces. "
Est-ce aussi valable pour les types primitifs ?
Pour les types primitifs cela ne change rien, sauf si bien sûr tu dois les passer par référence.
J'ai quand même un doute pour le double sur x86 vu qu'on gagne 32bit en le passant par pointer, il se peut que le gain existe par référence dépendant du compilateur.
A confirmer.
« pourquoi sur code blocks on peut faire (this.variable) et sur Visual Studio je dois faire (this->variable) ? »
this.variable ça n'a aucun sens. Si Code Blocks laisse passé ça, arrête définitivement d'utiliser cet IDE.
« Deuxièmement, faut-il privilégier l'envoi de paramètre par référence constante pour toutes les fonctions qui ne modifient pas les valeurs ? »
quand ça coûte cher de faire une copie, oui. On ne passe pas un std::vector<> par valeur/copie (sauf s'il est de taille <= 2, et encore...). À l'inverse, pour un int, ça n'a pas de sens de passer une référence constante.
À ce propos, les types intégraux genre int sont toujours passés par valeur, qu'on dise int ou const int&, non ?
J'ai pas bien compris la question 3. Mais je vais de comment il faudrait initialiser les champs privés complexes au niveau d'un constructeur :
class A {
private:
std::vector<int> v;
public:
A::A(const std::vector<int>& _v) : v(_v) {}
A::~A() {}
};
Pour le 4, oublie. Si on utilise cette syntaxe qui peut paraître un peu lourde, c'est pour éviter les conflits de nom.
Pour le 5, la règle est extrêmement simple. N'utilise pas de pointeurs, sauf quand tu es absolument certain de ne pas pouvoir faire autrement (le seul exemple que j'ai en tête étant le cas des classes héritant d'une classe virtuelle pure).
Typiquement, dans ton code, utiliser un new est pour moi une erreur.
Pour le 6, moi j'utilise comme règle d'utiliser this->foo dans le code des méthodes et les destructeurs. En revanche, j'insiste sur le fait que ça n'a pas trop de sens dans un constructeur (vu que this il est entièrement défini uniquement au retour du constructeur).
Pour le 7, je dirais que c'est la réponse D.
Pour le 8, tu as oublié un truc essentiel. Quand tu déclares ta fonction getHeure (par exemple), il faut que tu dises qu'elle ne modifiera pas l'objet sur lequel elle est appelé. Donc ce n'est pas :
int getHeure();
mais
int getHeure() const;
qu'il faut mettre.
Avec le deuxième, tu pourras utiliser la méthode getHeure() sur les Heure ET sur les const Heure. ![]()
" À l'inverse, pour un int, ça n'a pas de sens de passer une référence constante.
À ce propos, les types intégraux genre int sont toujours passés par valeur, qu'on dise int ou const int&, non "
Non non si tu passes ton int il sera copié si tu passe int& c'est bien une référence vers le int normalement. Je vois souvent des "int& out" dans certains prototypes de fonctions si je ne m'abuse en C++ parfois.
Si on ne le fait pas sur les types primitifs c'est généralement par flemme c'est tout.
Merci a tous pour vos réponses !
Ce que je retiens,
- toujours utiliser const ref si valeur pas modifiée (variable de type primitif et composée)
- utiliser this-> pour plus de clarté, mais pas dans le constructeur car c'est un non-sens
- ne pas jouer avec les stds
(rectifiez moi si je dis une bêtise !)
Pour tbop2, j'ai dit que la notion de destructeur n'avait pas encore été vue, mais je savais ce que c'était. Après je dis pas que mon cours est parfait (la preuve il n'y a pas classe obj();
Donc dernière question pour en finir, est-ce que dans un getter faut-il mettre const ou laisser tel quel ? (tbop2 j'ai pas très bien compris la remarqué à ce sujet, d'où la question.
"toujours utiliser const ref si valeur pas modifiée (variable de type primitif et composée)."
Surtout pour un type compose, c'est souvent une mauvaise idee pour un type primitif.
"utiliser this-> pour plus de clarté, mais pas dans le constructeur car c'est un non-sens"
this-> est tres rarement obligatoire en C++. En general, les gens ne l'ecrivent pas. Les cas ou on trouve this est quand un objet du meme type est passe en parametre et on veut clairement faire la difference entre this->a et other->a.
"Donc dernière question pour en finir, est-ce que dans un getter faut-il mettre const ou laisser tel quel ?"
const dit au compilateur "cette fonction ne modifie pas l'etat de l'objet". Ca permet au compilateur de verifier que ce que tu fais est coherent. Dans une fonction const, si tu essaye de modifier une valeure, le compilateur va te retourner une erreur. C'est une protection fournit par le langage pour eviter les effets imprevus.
Bien sûr que si tu demandes un int& (référence vers un int modifiable) tu auras un passage par référence. Comment voudrais-tu modifier la valeur de la variable en argument si c'était un passage par copie. ![]()
Ma question porte spécifiquement sur les types du genre "const int&", où tu modifieras pas la valeur.
Il me semblait avoir lu un jour que dans ces cas là il y avait un passage par valeur/copie (malgré la présence du symbole &) pour éviter les pertes de perfs lorsque qu'on instancie un template avec un type intégral (bool, char, short, int, long et les versions unsigned).
Après, c'est peut-être juste une optim de g++. ![]()
"la preuve il n'y a pas classe obj(); "
Je peux permets juste de faire une petite remarque, quand aucun paramètre n'est passé au constructeur il ne faut pas de (). Donc c'est plutôt classe obj;
Merci pour vos réponses !
ArgentComptant oui je sais, je me suis mal exprimé et j'ai omis de mettre un paramètre.
Pour le passage par const& ou pas lorsque la variable n'est pas modifiée Scott Meyers a établi une règle simple:
-Si c'est un type primitif ou un iterateur STL ou un foncteur on le passe par valeur
-Sinon on le passe par const&
(chapitre 20 de Effective C++ 3rd edition pour les explications)