Getter et setter, des pointeurs ou des références, et une bonne syntaxe à utiliser dans c ++?

StackOverflow https://stackoverflow.com/questions/1596432

Question

Je voudrais savoir une bonne syntaxe pour C ++ accesseurs.

private:
YourClass *pMember;

le poseur est facile, je suppose:

void Member(YourClass *value){
  this->pMember = value; // forget about deleting etc
}

et le getter? dois-je utiliser des références ou des pointeurs const?

exemple:

YourClass &Member(){
   return *this->pMember;
}

ou

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

Quelle est la différence entre eux?

Merci,

Joe

EDIT:

désolé, je vais modifier ma question ... Je sais que sur les références et les pointeurs, je demandais sur les références et les pointeurs const, comme getters, quelle serait la différence entre eux dans mon code, comme à l'avenir hte, ce shoud Je me attends à perdre si je vais une façon ou d'une autre ...

donc je suppose que je vais utiliser des pointeurs const au lieu de références

pointeurs const ne peuvent pas être supprimer ou setted, droit?

Était-ce utile?

La solution

En tant que loi générale:

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

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

Si elle 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 doit être une référence. Le getter doit alors lancer une exception, si la variable membre est NULL.

Autres conseils

La meilleure chose est de fournir une véritable interface OO au client qui cache les détails implementaton. Accesseurs ne sont pas OO.

Votre code ressemble beaucoup comme si vous êtes habitué à une autre langue - en C ++ en utilisant this->x (pour un exemple) est relativement rare. Lorsque le code est tout bien écrit, donc utilise un accesseur ou mutator.

Bien que je suis assez inhabituel à cet égard particulier, je vais aller sur le dossier (encore une fois) en disant que forçant code client à utiliser un accesseur ou mutator est une mauvaise idée directement. Si vous avez honnêtement une situation où il est logique pour le code client pour manipuler une valeur dans votre objet, le code client doit utiliser l'affectation normale à lire et / ou écrire cette valeur.

Lorsque / si vous avez besoin de contrôler quelle valeur est affectée, la surcharge d'opérateur vous permet de prendre ce contrôle sans forcer la syntaxe get / set laid 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 / ensemble des fonctions est quelque chose comme un nombre qui est censé se limiter à une plage particulière. Le setXXX vérifie la nouvelle valeur étant dans la gamme, et la getXXX renvoie la valeur.

Si vous voulez que, un (assez) modèle simple peut faire le travail beaucoup plus proprement:

template <class T, class less=std::less<T> >
class bounded {
    const T lower_, upper_;
    T val_;

    bool check(T const &value) {
        return less()(value, lower_) || less()(upper_, value);
    }

    void assign(T const &value) {
        if (check(value))
            throw std::domain_error("Out of Range");
        val_ = value;
    }

public:
    bounded(T const &lower, T const &upper) 
        : lower_(lower), upper_(upper) {}

    bounded(bounded const &init) 
        : lower_(init.lower), upper_(init.upper)
    { 
        assign(init); 
    }

    bounded &operator=(T const &v) { assign(v);  return *this; }

    operator T() const { return val_; }

    friend std::istream &operator>>(std::istream &is, bounded &b) {
        T temp;
        is >> temp;

        if (b.check(temp))
            is.setstate(std::ios::failbit);
        else
            b.val_ = temp;
        return is;
    }
};

Cela rend également le code beaucoup plus proche de soi documentant - par exemple, lorsque vous déclarez un objet comme: bounded<int>(1, 1024);, il est immédiatement évident que l'intention est un entier dans la plage de 1 à 1024. La personne seule partie peut trouver ouverte à la question est de savoir si 1 et / ou 1024 est inclus dans la gamme. Ceci est considérablement différent de la définition d'un int dans la classe, et attendre que tout le monde qui regarde jamais la classe pour se rendre compte qu'ils sont censés utiliser le setXXX d'appliquer certaines (à ce moment-là inconnu) un ensemble de limites sur les valeurs qui peuvent être attribué.

Lorsque vous intégrez l'un de ceux-ci dans une classe, vous faites une variable publique, et la gamme est toujours appliquée. Dans le code client, il n'y a pas d'argument réel sur la syntaxe - vous simplement assigner à une variable publique, comme vous le feriez pour tout autre - avec le détail mineur qui tente d'attribuer une valeur qui est hors de portée jetteront une exception. En théorie, la classe devrait prendre probablement un modèle paramètre de stratégie pour spécifier exactement ce qu'il fait dans ce cas, mais je ne l'ai jamais eu une vraie raison de se préoccuper de cela.

Comme d'autres l'ont dit, l'utilisation des pointeurs si nul 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 à signaler la propriété. Je pense que des appels avec des références comme « prêt » un objet à une autre fonction ou une classe. La classe d'origine qui a passé ou retourné la référence est toujours propriétaire, et est responsable de sa création, l'entretien et le nettoyage. Lorsque mon code passe un pointeur non-const, d'autre part, cela signifie généralement qu'il ya une sorte de transfert ou le partage de la propriété en cours, avec toutes les responsabilités que cela implique.

(Et oui, je l'habitude d'utiliser des pointeurs intelligents. Ce sont des références dans semblable à mon esprit. Je parle de code de niveau inférieur à celui ici.)

  

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 est mis en évidence ne sera pas là, alors vous ne voulez probablement pas retourner des références. Références disent l'appelant « Je vais vous donner un alias qui existera quand je vous le retourner ». 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 insinuent que l'appelant voudra peut-être vérifier si membre existe avant de l'utiliser. Ussually cela se fait avec un chèque NULL.

En fin de compte, il n'y a pas de « bonne réponse ». Cela dépend du contrat de la classe et si l'appelant / doit / veut vérifier si « membre » est toujours là.

La réponse courte est des pointeurs pour des choses qui peuvent être pointées ailleurs et les références pour alias « détrôné ».

En plus des autres réponses, si vous choisissez des références pour le getter ne pas écrire comme dans votre exemple:

YourClass &Member(){
   return *this->pMember;
}

Votre getter permet effectivement la mise, comme dans instance->Member() = YourClass(); et contournant ainsi votre poseur. Cela pourrait ne pas être autorisé si YourClass est noncopyable, mais il est encore une autre chose à garder à l'esprit. Un autre inconvénient est le getter n'est pas const.

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

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

1 sur l'interrogation l'utilisation des setters et getters. Si vous devez les utiliser et la possibilité de nulls envisager d'utiliser boost :: shared_ptr. Cette propriété est gérée de façon pour vous.

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top