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

Devriez-vous jamais utiliser des variables membres protégées? Quels sont les avantages et quels problèmes peuvent-ils causer?

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

    Dépend de la façon dont vous êtes difficile de cacher l’état.

    • Si vous ne voulez pas de fuite d’état interne, alors la déclaration de toutes les variables membres est la voie à suivre.
    • Si vous ne vous souciez pas vraiment de ce que les sous-classes puissent accéder à l’état interne, alors la protection est suffisante.

    Si un développeur vient et sous-classe votre classe, ils peuvent le gâcher car ils ne le comprennent 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 de la façon dont les choses se passent, ce qui vous donne la possibilité de le modifier ultérieurement.

    De nos jours, le sentiment général est qu’ils provoquent un couplage excessif entre les classes dérivées et leurs bases.

    Ils n’ont aucun avantage particulier sur les méthodes / propriétés protégées (il était une fois qu’ils pouvaient avoir un léger avantage en termes de performances), et ils étaient également plus utilisés à une époque où l’inheritance était très en vogue, 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 passe de privé à protégé.

    Cela n’arrive presque jamais – je ne suis pas du tout un fan de l’inheritance, 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 d’avoir besoin d’accéder à votre variable de membre privé, il va simplement modifier le code, le modifier pour le protéger et poursuivre ses activités.

    Les seules véritables exceptions à cette règle sont si vous expédiez des DLL binarys sous forme de boîte noire à des tiers. Il s’agit essentiellement de Microsoft, de ces fournisseurs «Custom DataGrid Control» et peut-être de quelques autres applications volumineuses livrées avec des bibliothèques d’extensibilité. À moins d’être dans cette catégorie, il ne vaut pas la peine de consacrer du temps et des efforts à se soucier de ce genre de choses.

    En général, je garderais vos variables membres protégées dans le cas rare où vous avez un contrôle total sur le code qui les utilise également. Si vous créez une API publique, je dirais jamais. Ci-dessous, nous nous référons à la variable membre en tant que “propriété” de l’object.

    Voici ce que votre super-classe ne peut pas faire après avoir protégé une variable membre plutôt qu’avec un accesseur privé:

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

    2. savoir quand la propriété a été modifiée ou supprimée. Cela peut introduire des bogues lorsque la super-classe fait des suppositions sur l’état de cette variable. Faire une méthode setter protégée pour la variable conserve ce contrôle.

    3. Définissez un point d’arrêt ou ajoutez un résultat 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 que je recommande de créer une variable membre protégée. Vous feriez mieux de passer quelques minutes à exposer la propriété à travers des getters / setters que des heures plus tard, en traçant un bogue dans un autre code modifiant 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 l’implémentation, je ne vois aucun avantage à mapper cette propriété à une variable membre protégée plutôt qu’à des méthodes accesseur / 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 classe de base. Cela empêche la classe de base de conserver efficacement ses invariants.

    Pour la même raison, les variables de membre protégées rendent également beaucoup plus difficile l’écriture de code multithread sécurisé, sauf si elles sont garanties constantes ou limitées à un seul thread.

    Les méthodes d’accesseur / mutateur offrent une stabilité et une flexibilité de mise en œuvre beaucoup plus importantes en matière de maintenance.

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

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

    Le problème majeur pour moi est qu’une fois que vous avez protégé une variable, vous ne pouvez plus permettre à aucune méthode de votre classe de compter sur sa valeur, car une sous-classe peut toujours la placer hors de scope.

    Par exemple, si j’ai une classe qui définit la largeur et la hauteur d’un object pouvant être rendu, et que je rends ces variables protégées, je ne peux alors pas faire d’hypothèses (par exemple) sur les proportions.

    De manière critique, je ne peux jamais faire ces hypothèses à partir du moment où le code est publié en tant que bibliothèque, car même si je mets à jour les parameters, je ne peux pas garantir que les variables sont définies via les getters dans le code existant.

    Une sous-classe de ma classe ne peut pas non plus choisir de faire cette garantie, car elle ne peut pas non plus appliquer les valeurs des variables, même si c’est le point entier de leur sous-classe .

    Par exemple:

    • J’ai une classe de 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”, où la seule différence est que je limite les largeurs et les hauteurs aux valeurs valides pour un affichage graphique.
    • Mais c’est impossible maintenant , car ma classe DisplayedRectangle ne peut pas vraiment contraindre ces valeurs, car toute sous-classe de celle-ci pourrait remplacer directement les valeurs, tout en étant traitée comme un DisplayedRectangle.

    En contraignant les variables à être privées, je peux alors imposer le comportement que je veux à travers les régleurs ou les getters.

    La plupart du temps, il est dangereux d’utiliser protégé, car vous cassez quelque peu l’encapsulation de votre classe, qui pourrait être décomposé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 offrir au moins trois access publics à ses données: map, hash_map, vector-like. Ensuite, vous avez quelque chose comme:

     template  class Base { // etc. protected TContainer container ; } template  class DerivedMap : public Base > { /* etc. */ } template  class DerivedHashMap : public Base > { /* etc. */ } template  class DerivedVector : public Base > { /* etc. */ } 

    J’ai utilisé ce type de code il y a moins d’un mois (le code provient donc de la mémoire). Après quelques reflections, je pense que le conteneur Base générique devrait être une classe abstraite, même s’il peut très bien vivre, car utiliser directement Base serait une telle douleur qu’il devrait être interdit.

    Résumé Ainsi, vous avez des données protégées utilisées par la classe dérivée. Cependant, nous devons tenir compte du fait que la classe de base doit être abstraite.

    En bref, oui.

    Les variables membres protégées permettent d’accéder à la variable à partir de toutes les sous-classes ainsi que de toutes les classes du même package. Cela peut être très utile, en particulier pour les données en lecture seule. Je ne crois toutefois 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é et de quelques getters et setters.

    Pour plus d’informations sur les modificateurs d’access .Net, cliquez ici

    Il n’y a pas d’avantages ni d’inconvénients réels pour les 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 accepté de déclarer les variables membres comme privées et de permettre un access extérieur via des propriétés. En outre, certains outils (par exemple, certains mappeurs O / R) s’attendent à ce que les données object 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 voulez que vos sous-classes (et UNIQUEMENT vos sous-classes) accèdent à une certaine variable, il n’y a aucune raison de ne pas le déclarer comme protégé.

    Juste pour mémoire, sous Point 24 de “C ++ Exceptionnel”, dans l’une des notes de bas de page, Sutter dit “vous n’écrirez jamais une classe ayant une variable membre publique ou protégée. .) ”