12
votes

Getter and Setter, des pointeurs ou des références et une bonne syntaxe à utiliser en C ++?

J'aimerais connaître une bonne syntaxe pour les getters et les configurateurs C ++.

YourClass *Member() const{
  return this->member;
}


3 commentaires

Vous voudrez peut-être modifier vos exemples pour refléter votre édition. Pour le moment, vous retournez un pointeur non-Const.


Mais alors je ne pourrai pas supprimer la mémoire? J'ai besoin de savoir comment posséder à juste titre les variables et que les autres appellent les getters sans modifier la variable sublingeuse ...


Les getters et les setters sont très java / c # style (pas C ++). Ils résultent de ces langues dépendant de la réflexion et des cadres pour créer l'objet. Getters et Setter détruisent la nature de la nature d'une langue et vous permettent explicitement de vous mêler de la structure interne d'un objet. Ceci est une alternance d'APON en C ++, il est plus courant d'avoir l'objet entièrement formé après la fin du constructeur.


8 Réponses :


17
votes

comme une loi générale:

  • Si NULL est un paramètre ou une valeur de retour valide, utilisez des pointeurs.
  • Si NULL est pas un paramètre ou une valeur de retour valide, utilisez des références.

    Donc, si le setter doit éventuellement être appelé avec NULL, utilisez un pointeur comme paramètre. Sinon, utilisez une référence.

    S'il est valide pour appeler le getter d'un objet contenant un pointeur NULL, il doit renvoyer un pointeur. Si un tel cas est un invariant illégal, la valeur de retour devrait être une référence. Le getter devrait alors lancer une exception si la variable de membre est null.


3 commentaires

Du: si NULL n'est pas un paramètre ou une valeur de retour valide, utilisez le retour par valeur? (Pas de pointeurs, pas de REF)


C'est bien trop simplifié. Mais là encore, la question est une façon de généraliser pour répondre correctement.


J'utiliserais le retour par valeur uniquement pour les bâtiments, pour le reste, je préfère éviter le coût de la construction de copie. // pour getters, bien sûr, si vous devez calculer quelque chose, alors c'est bien différent



2
votes

Quelle est la différence entre eux?

La référence est un alias de la chose (il est la chose *). Un pointeur est l'adresse de la chose. S'il y a une chance que ce qui soit dirigé ne soit pas là, vous ne voulez probablement pas retourner des références. Les références disent à l'appelant "Je vais vous donner un alias qui existera quand je le retournerai". En fait, il n'y a vraiment aucun moyen de vérifier la référence pour voir si ce qui est sous-jacent est valide.

Avec le pointeur, sémantiquement, vous impliquez que l'appelant souhaitera peut-être vérifier si le membre existe avant de l'utiliser. USsudiquement ceci est fait avec un chèque null.

En fin de compte, il n'y a pas de réponse "droite". Cela dépend du contrat de la classe et si l'appelant / devrait / souhaite vérifier si "membre" est toujours autour.

La réponse courte est les pointeurs pour des choses qui peuvent être pointées ailleurs et des références pour des alias "non produits".


1 commentaires

Désolé, je vais éditer ma question ... Je connais des références et des indicateurs, je posais des références et des indicateurs de const, comme getters, quelle serait la différence entre eux dans mon code, comme dans l'avenir HTE, qu'est-ce que je m'attendais à perdre si je vais un moyen ou un autre ...



7
votes

La meilleure chose à faire est de fournir une réelle interface OO au client qui cache des détails de mise en œuvre. Getters et setters ne sont pas OO.


6 commentaires

Je suis, mais j'aime les getters et les setters au lieu de variables publiques. J'utilise à peine des variables publiques, uniquement en cas de besoin, ou au moins des variables protégées


Je pense que ce que Devfred suggère que vous évitez les getters / setters et les variables publiques. Au lieu de cela, essayez de définir des méthodes actives qui font le travail pour vous.


Peux-tu me donner un exemple? Je crée des classes abstraites et je dérive d'eux et la plupart de mes getters, setters et fonctions sont virtuels ... je suppose que je n'ai pas eu ce qu'il voulait dire


Les getters et les setters sont très java / c # style (pas C ++). Ils résultent de ces langues dépendant de la réflexion et des cadres pour créer l'objet. Getters et Setter détruisent la nature de la nature d'une langue et vous permettent explicitement de vous mêler de la structure interne d'un objet. Ceci est une alternance d'APON en C ++, il est plus courant d'avoir l'objet entièrement formé après la fin du constructeur.


Pouvez-vous me donner un exemple de cette "méthodes active", etc.? Si je ne fais pas les variables publiques et ne créez pas de getters ou de setters, alors comment devrais-je utiliser la classe? O_o désolé si c'est un peu stupide, mais je ne l'obtiens vraiment pas :(


Cela mérite probablement sa propre question, en fait. Mais comme un exemple simple, imaginez que vous avez un personnage dans un jeu et que vous voulez essayer de vous déplacer vers le nord. Vous pouvez appeler getx () et gety () pour obtenir sa position, ajouter les bonnes valeurs à celles-ci, appelez l'objet Carte pour voir si cette position est libre et que l'appel Setx () et Sety () pour mettre à jour sa position. Si vous avez une méthode de déménagement () sur le personnage, cependant, vous avez centralisé cette logique. Vous êtes maintenant libre de modifier la manière dont le personnage stocke sa position sans aller surtout le code. Et maintenant, l'AI et le contrôle du joueur peuvent utiliser cette méthode courante.



1
votes

+1 sur la mise en cause de l'utilisation de setters et de getters. Si vous devez les utiliser et que vous avez la possibilité de NULLS, envisagez d'utiliser Boost :: Shared_Ptr. Cette appropriation est traitée pour vous.


2 commentaires

Je n'aimerais pas encore utiliser Boost, comme je l'apprenant, je voudrais créer ce projet avec les bibliothèques moins externes ...


Boost :: Shared_PTR est maintenant STD :: Shared_PTR Dans MODERN C ++, la dépendance externe n'est donc plus une excuse pour ne pas utiliser les pointeurs intelligents.



4
votes

Comme d'autres les ont dit, utilisez des pointeurs si NULL est une possibilité.

Dans la plupart des cas, je préfère utiliser des références lorsque cela est possible. Personnellement, dans mon code, j'aime utiliser la distinction entre les pointeurs et les références à la propriété du signal. Je pense aux appels avec des références en tant que "prêt" un objet à une autre fonction ou une autre classe. La classe d'origine adoptée ou renvoyée la référence le possède toujours et est responsable de sa création, de sa maintenance et de sa propreté. Lorsque mon code transmet un pointeur non constitué, d'autre part, cela signifie généralement qu'il existe une sorte de transfert ou de partage de propriété en cours, avec toutes les responsabilités qui impliquent.

(et oui, j'utilise habituellement des pointeurs intelligents. Ceux-ci semblent des références dans mon esprit. Je parle de code de niveau inférieur à celui ici.)


0 commentaires

0
votes

Jonathan, quel compilateur utilisez-vous? Il y a une bonne chance que partage_ptr est déjà livré avec elle dans le cadre de la mise en œuvre de la TR1 du compilateur.


0 commentaires

7
votes

Votre code semble beaucoup comme si vous êtes habitué à une langue différente - en C ++ en utilisant this-> x (pour un exemple) est relativement inhabituel. Lorsque le code est du tout bien écrit, vous utilisez donc un accesseur ou un mutateur.

Si je suis assez inhabituel dans ce respect particulier, je vais continuer à enregistrer (encore une fois) comme indiquant que forçant le code client à utiliser un L'accesseur ou le mutateur est directement une mauvaise idée. Si vous avez honnêtement une situation où il est logique que le code client manipule une valeur dans votre objet, le code client doit alors utiliser une affectation normale pour lire et / ou écrire cette valeur.

Quand / si vous avez besoin Pour contrôler quelle valeur est attribuée, la surcharge de l'opérateur vous permet de prendre ce contrôle sans forcer la syntaxe get / définie laide sur le code client. Plus précisément, ce que vous voulez est une classe proxy (ou modèle de classe). Juste pour un exemple, l'une des situations les plus courantes où les gens veulent obtenir des fonctions ou des fonctions sont quelque chose comme un nombre censé être limité à une portée particulière. Le Setxxx vérifie la nouvelle valeur pour être dans la plage et le getxxx renvoie la valeur.

Si vous le souhaitez, un modèle simple (équitable) peut faire le travail beaucoup plus proprement: xxx

Ceci rend également le code beaucoup plus proche de soi-même de la documentation automatique - par exemple, lorsque vous déclarez un objet comme: limité < int> (1, 1024); , il est immédiatement évident que l'intention est un entier dans la plage de 1 à 1024. La seule partie de quelqu'un pourrait trouver ouvert à la question est de savoir si 1 et / ou 1024 est inclus dans la gamme. Ceci est considérablement différent de définir une INT dans la classe et de s'attendre à ce que tout le monde qui examine la classe pour se rendre compte qu'il est censé utiliser le SETXXX pour appliquer une partie (à ce point inconnu). Ensemble de limites sur les valeurs qui peuvent être Assigné.

Lorsque vous avez incorporé l'un d'entre eux dans une classe, vous en faites une variable publique et la gamme est toujours appliquée. Dans le code du client, il n'y a pas de véritable argument sur la syntaxe - vous venez de vous assigner à une variable publique, comme si vous le feriez d'autre - avec le détail mineur qui tente d'attribuer une valeur hors limites vous fera une exception. En théorie, la classe devrait probablement adopter un paramètre de modèle de stratégie pour spécifier exactement ce qu'il fait dans ce cas, mais je n'ai jamais eu de vraie raison de la déranger avec ça.


2 commentaires

Désolé, mais regarder ce code rend beaucoup plus fort (au moins pour moi) de comprendre qu'un getter ou un setter. Il n'est pas facile pour moi de penser que la création d'une classe modélise ou d'une classe pour une règle simple est meilleure qu'une simple fonction définie. Pensez à une grande bibliothèque qui va être utilisée par d'autres bibliothèques ou exécutables, je pense que la surcharge de l'opérateur d'affectation n'est pas la meilleure approche, bien sûr, je suis juste un débutant, mais de ce que j'ai lu, l'opérateur d'affectation devrait Seulement être surchargé lorsque vous avez besoin strictement, comme la règle d'arbre que Martin a écrit dans un autre fil de la mienne


Si tout n'allait jamais écrire était un getter et un setter, vous auriez raison - ce code serait plus complexe. Lorsque vous pouvez remplacer des dizaines (centaines de centaines) de getters et de setters avec un modèle, cependant, il simplifie considérablement le code. Indépendamment de cela, il centralise toute la complexité. Un getter et un setter nécessitent tout le code pour connaître la mise en œuvre et ajouter une complexité pour y faire face. Cela met toute la complexité au même endroit et simplifie tout l'autre code.



2
votes

En plus des autres réponses, si vous choisissez des références pour le getter, n'écris pas comme dans votre exemple: xxx

Votre getter permet de définir, comme dans l'instance -> Membre () = votreclass (); et donc contourner votre setter. Cela pourrait ne pas être autorisé si votreclass est non gélifié, mais reste une autre chose à avoir à l'esprit. Un autre inconvénient est le getter n'est pas constitué.

Au lieu de cela, écrivez votre getter comme ceci: xxx


0 commentaires