Question

Devriez-vous un jour utiliser des variables membres protégées ?Quels sont les avantages et quels problèmes cela peut-il engendrer ?

Était-ce utile?

La solution

Devriez-vous un jour utiliser des variables membres protégées ?

Cela dépend de votre niveau de difficulté en matière de masquage.

  • Si vous ne voulez pas de fuite de l'état interne, alors déclarer toutes vos variables membres privées est la voie à suivre.
  • Si vous ne vous souciez pas vraiment du fait que les sous-classes puissent accéder à l'état interne, alors protected est suffisant.

Si un développeur arrive et sous-classe votre classe, il risque de tout gâcher car il ne la comprend pas complètement.Avec les membres privés, autres que l'interface publique, ils ne peuvent pas voir les détails spécifiques à l'implémentation sur la façon dont les choses sont faites, ce qui vous donne la possibilité de les modifier ultérieurement.

Autres conseils

Le sentiment général aujourd’hui est qu’ils provoquent des couplages excessifs entre les classes dérivées et leurs bases.

Ils n'ont pas d'avantage particulier par rapport aux méthodes/propriétés protégées (autrefois, ils pouvaient avoir un léger avantage en termes de performances), et ils étaient également davantage utilisés à une époque où l'héritage très profond était à la mode, ce qui n'est pas le cas actuellement.

Généralement, si quelque chose n’est pas délibérément conçu comme public, je le rends privé.

Si une situation survient où j'ai besoin d'accéder à cette variable ou méthode privée à partir d'une classe dérivée, je la change de privée à protégée.

Cela n'arrive presque jamais - je ne suis vraiment pas du tout fan de l'héritage, car ce n'est pas un moyen particulièrement efficace de modéliser la plupart des situations.En tout cas, continuez, pas de soucis.

Je dirais que c'est bien (et probablement la meilleure façon de procéder) pour la majorité des développeurs.

Le simple fait est que, si un autre développeur arrive un an plus tard et décide qu'il a besoin d'accéder à votre variable de membre privé, il va simplement modifier le code, le changer en protégé et poursuivre ses activités.

Les seules véritables exceptions à cette règle sont si vous expédiez des DLL binaires sous forme de boîte noire à des tiers.Il s'agit essentiellement de Microsoft, de ces fournisseurs de « Contrôle DataGrid personnalisé » et peut-être de quelques autres grandes applications livrées avec des bibliothèques d'extensibilité.À moins que vous n'apparteniez à cette catégorie, cela ne vaut pas la peine de consacrer du temps et des efforts à vous soucier de ce genre de choses.

En général, je conserverais vos variables membres protégées dans les rares cas où vous avez également un contrôle total sur le code qui les utilise.Si vous créez une API publique, je dirais jamais.Ci-dessous, nous ferons référence à la variable membre comme à une « propriété » de l’objet.

Voici ce que votre superclasse ne peut pas faire après avoir rendu une variable membre protégée plutôt que privée avec accesseurs :

  1. créer paresseusement une valeur à la volée lors de la lecture de la propriété.Si vous ajoutez une méthode getter protégée, vous pouvez créer paresseusement la valeur et la renvoyer.

  2. savoir quand la propriété a été modifiée ou supprimée.Cela peut introduire des bugs lorsque la superclasse fait des hypothèses sur l'état de cette variable.Créer une méthode de définition protégée pour la variable conserve ce contrôle.

  3. Définissez un point d'arrêt ou ajoutez une sortie de débogage lorsque la variable est lue ou écrite.

  4. Renommez cette variable membre sans rechercher dans tout le code qui pourrait l'utiliser.

En général, je pense que ce serait le cas rare où je recommanderais de créer une variable membre protégée.Il est préférable de passer quelques minutes à exposer la propriété via des getters/setters plutôt que des heures plus tard à rechercher un bogue dans un autre code qui a modifié la variable protégée.Non seulement cela, mais vous êtes assuré contre l’ajout de fonctionnalités futures (telles que le chargement différé) sans casser le code dépendant.Il est plus difficile de le faire plus tard que de le faire maintenant.

Au niveau de la conception, il peut être approprié d'utiliser une propriété protégée, mais pour la mise en œuvre, je ne vois aucun avantage à la mapper à une variable membre protégée plutôt qu'à des méthodes d'accès/mutateur.

Les variables membres protégées présentent des inconvénients importants car elles permettent effectivement au code client (la sous-classe) d'accéder à l'état interne de la classe de base.Cela empêche la classe de base de maintenir efficacement ses invariants.

Pour la même raison, les variables membres protégées rendent également l'écriture de code multithread sécurisé beaucoup plus difficile à moins qu'elles ne soient garanties constantes ou limitées à un seul thread.

Les méthodes accesseurs/mutateurs offrent considérablement plus de stabilité de l’API et de flexibilité de mise en œuvre sous maintenance.

De plus, si vous êtes un puriste OO, les objets collaborent/communiquent en envoyant des messages, et non en lisant/définissant un état.

En contrepartie, ils offrent très peu d’avantages.Je ne les supprimerais pas nécessairement du code de quelqu'un d'autre, mais je ne les utilise pas moi-même.

Le problème clé pour moi est qu'une fois que vous avez protégé une variable, vous ne pouvez alors autoriser aucune méthode de votre classe à compter sur sur sa valeur étant dans une plage, car une sous-classe peut toujours la placer hors plage.

Par exemple, si j'ai une classe qui définit la largeur et la hauteur d'un objet rendu et que je protège ces variables, je ne peux alors faire aucune hypothèse sur (par exemple) le rapport hauteur/largeur.

De manière critique, je peux jamais faites ces hypothèses à tout moment à partir du moment où ce code est publié en tant que bibliothèque, car même si je mets à jour mes setters pour conserver les proportions, je n'ai aucune garantie que les variables sont définies via les setters ou accessibles via les getters dans le code existant.

Aucune sous-classe de ma classe ne peut non plus choisir de faire cette garantie, car elle ne peut pas non plus appliquer les valeurs des variables, même si c'est tout l'intérêt de leur sous-classe.

Par exemple:

  • J'ai une classe rectangle dont la largeur et la hauteur sont stockées en tant que variables protégées.
  • Une sous-classe évidente (dans mon contexte) est une classe "DisplayedRectangle", dont la seule différence est que je limite les largeurs et les hauteurs à des valeurs valides pour un affichage graphique.
  • Mais c'est impossible maintenant, depuis ma classe DisplayedRectangle ne peut pas vraiment contraindre ces valeurs, car n'importe quelle sous-classe de celle-ci pourrait remplacer les valeurs directement, tout en étant toujours traitée comme un DisplayedRectangle.

En contraignant les variables à être privées, je peux ensuite appliquer le comportement souhaité via des setters ou des getters.

La plupart du temps, il est dangereux d'utiliser protected car vous cassez quelque peu l'encapsulation de votre classe, qui pourrait bien être cassée par une classe dérivée mal conçue.

Mais j'ai un bon exemple :Disons que vous pouvez utiliser une sorte de conteneur générique.Il a une implémentation interne et des accesseurs internes.Mais vous devez proposer au moins 3 accès publics à ses données :map, hash_map, de type vectoriel.Ensuite, vous avez quelque chose comme :

template <typename T, typename TContainer>
class Base
{
   // etc.
   protected
   TContainer container ;
}

template <typename Key, typename T>
class DerivedMap     : public Base<T, std::map<Key, T> >      { /* etc. */ }

template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }

template <typename T>
class DerivedVector  : public Base<T, std::vector<T> >        { /* etc. */ }

J'ai utilisé ce genre de code il y a moins d'un mois (le code vient donc de mémoire).Après réflexion, je pense que même si le conteneur générique Base devrait être une classe abstraite, même s'il peut très bien vivre, car utiliser directement Base serait tellement pénible qu'il devrait être interdit.

Résumé Ainsi, vous avez protégé les données utilisées par la classe dérivée.Néanmoins, nous devons prendre en compte le fait que la classe Base doit être abstraite.

Bref, oui.

Les variables membres protégées permettent d'accéder à la variable à partir de n'importe quelle sous-classe ainsi que de n'importe quelle classe du même package.Cela peut être très utile, notamment pour les données en lecture seule.Cependant, je ne pense pas qu'ils soient nécessaires, car toute utilisation d'une variable membre protégée peut être répliquée à l'aide d'une variable membre privée et de quelques getters et setters.

Juste pour le dossier, sous le point 24 de "C ++ exceptionnel", dans l'une des notes de bas de page, Sutter va ", vous n'écririez jamais une classe qui a une variable de membre public ou protégé.droite?(Indépendamment du mauvais exemple donné par certaines bibliothèques.)"

Pour des informations détaillées sur les modificateurs d'accès .Net va ici

Il n'y a pas de réels avantages ou inconvénients aux variables membres protégées, c'est une question de ce dont vous avez besoin dans votre situation spécifique.En général, il est courant de déclarer les variables membres comme privées et d'autoriser l'accès extérieur via les propriétés.De plus, certains outils (par ex.certains mappeurs O/R) s'attendent à ce que les données d'objet soient représentées par des propriétés et ne reconnaissent pas les variables membres publiques ou protégées.Mais si vous savez que vous souhaitez que vos sous-classes (et UNIQUEMENT vos sous-classes) accèdent à une certaine variable, il n'y a aucune raison de ne pas la déclarer comme protégée.

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