web-dev-qa-db-fra.com

Quand / pourquoi rendre la fonction privée en classe?

Quand devrais-je faire une fonction private et pourquoi est-ce une bonne idée?

22
Ramilol

Vous devez faire une fonction private lorsque vous n'avez pas besoin d'autres objets ou classes pour accéder à la fonction, lorsque vous l'invoquerez dans la classe.

Tenez-vous au principe du moindre privilège, autorisez uniquement l'accès aux variables/fonctions absolument nécessaires. Tout ce qui ne correspond pas à ce critère ne devrait pas être private.

28
Jacob Relkin

Je fais habituellement les fonctions d'assistance private. Mais qu'est-ce que assistant semble être vague. Alors laissez-moi vous donner un exemple. Supposons que vous ayez la classe _ suivante Sample; Il expose peu de fonctions publiques, l'une d'elles, par exemple, est DoWork(). Cette fonction prend un paramètre. Mais cela ne suppose pas que le paramètre sera toujours valide, de sorte qu'il premier vérifie la validité du paramètre pour lequel il a beaucoup de code au début de la fonction. Quelque chose comme ça:

class Sample
{
   public:
      void DoWork(SomeClass param)
      {
               /*
                *lots of code related to validation of param
                */  

                //actual code that operates on the param 
                //and other member data IF the param is valid
      }
};

Étant donné que vous avez écrit beaucoup de code liés à la validation du paramètre, il rend la fonction encombrante et difficile à lire. Vous avez donc décidé de déplacer ce code de validation pour fonctionner, IsValidParam(), puis vous appelez cette fonction de DoWork() Passer le paramètre param à celui-ci. Quelque chose comme ça:

class Sample
{
   public:
      void DoWork(SomeClass param)
      {       
            if ( IsValidParam(param))       
            {
                //actual code that operates on the param 
                //and other member data IF the param is valid
            }
      }
};

Ça a l'air plus propre, non?

Ok, vous avez écrit IsValidParam() quelque part dans la classe, mais la question que vous rencontrez maintenant est de faire cette fonction public? Si cette fonction est utilisée seulement par vos autres fonctions telles que DoWork(), alors rendant IsValidParam() publique n'a pas de sens. Vous avez donc décidé de faire cette fonction private.

class Sample
{
   public:
      void DoWork(SomeClass param)
      {       
            if ( IsValidParam(param))       
            {
                //actual code that operates on the param 
                //and other member data IF the param is valid
            }
      }
  private:
      bool IsValidParam(SomeClass param)
      {
          //check the validity of param.
          //return true if valid, else false.
      }
};

Les fonctions de ce type (isvalidparam) devraient être private. J'appelle ces fonctions Fonctions d'assistance .

J'espère que cette explication vous aide!

21
Nawaz

L'un des directeurs fondateurs de OOP est l'encapsulation. C'est là que la fonctionnalité pour la manière dont un objet fonctionne est maintenu interne à cet objet. L'idée est qu'elle est plus facile pour le code d'utiliser un objet s'il ne le fait pas. Il faut savoir comment ça fonctionne. Comme acheter un micro-ondes - il vous suffit de savoir comment l'utiliser et non de la façon dont cela fonctionne.

La même approche doit être prise avec OOP. Gardez tout nécessaire pour maintenir l'objet privé. Ne faites que ce qui est nécessaire pour utiliser pleinement l'objet public.

6
Jonathan Wood

Si vous concevez une classe - en tenant compte de la manière dont le code client doit l'utiliser - alors vous dérivez inévitablement une interface composée de public et peut-être protected membres.

private Les membres sont des fonctions et des données prises en charge et permettent à ces membres publics/protégés. private Les fonctions doivent facturer et/ou modulariser/structurer le code requis par les membres non -private, rendant leur mise en œuvre moins redondante et plus facile à comprendre.

Sumess, vous créez un membre private s'il n'est pas destiné à une utilisation directe par code client, et n'existe que pour prendre en charge les membres non -private.

2
Tony Delroy

Comment voulez-vous être puriste? :)

La bonne réponse à cette question est liée à la maintenance des invariants. La bonne façon de le faire est plutôt compliquée.

Dans votre classe de base, vous définissez des méthodes publiques pour fournir le entier de l'accès à la classe. Toutes ces méthodes doivent être concrètes. La principale chose ici est que les invariants publics sont supposés tenir avant et après avoir appelé ces fonctions. Ces fonctions ne doivent jamais nous appeler, elles n'appellent que des méthodes protégées et privées. Ces fonctions doivent être axiomatiques: elles doivent être un ensemble assez minimal requis pour capturer la sémantique souhaitée.

La plupart des calculs pouvant être effectués en utilisant ces méthodes doivent être mondiaux ou au moins membres statiques publics.

Vous fournissez également des méthodes virtuelles pures qui sont des crochets pour mettre en œuvre les détails en fonction de la représentation dans les classes dérivées. Les fonctions virtuelles dans la base doivent être privées. Le conseil habituel ici (public) est complètement faux. Les fonctions virtuelles sont des détails sur la mise en œuvre. Une exception près: le destructeur virtuel doit être public.

Les fonctions d'assistant privées peuvent également être placées dans la base.

Il peut être utile d'avoir également des méthodes protégées dans la base: elles appelleront les assistants privés ou les virtualités. Comme ci-dessus: les méthodes protégées ne doivent jamais appeler des méthodes protégées ou publiques. Les fonctions protégées maintiennent un invariant plus faible que le public avant et après chaque appel.

Les fonctions privées entretiennent généralement des invariants très faibles.

La raison de cette hiérarchie stricte est de s'assurer que les invariants d'objets sont maintenus correctement.

Maintenant, dans une classe dérivée, vous fournissez une implémentation. Idéalement, les fonctions virtuelles ici seraient invisibles, une condition plus forte que simplement privée. Ces fonctions virtuelles ne doivent pas être appelées du tout dans la classe dérivée. Le seulement accès autorisé est via des fonctions protégées de la base.

Toutes les méthodes de cours dérivées, y compris le destructeur, doivent être privées. Les constructeurs doivent être publics, mais ce ne sont pas des méthodes de la classe.

Afin de bien comprendre ces règles, vous devez réfléchir attentivement les invariants. Les invariants publics peuvent être supposés tenir avant d'appeler une méthode publique et sont requis Une fois que c'est fini. Par conséquent, vous ne pouvez pas appeler de telles fonctions de l'intérieur de la classe ni de la classe dérivée de celle-ci, car ces fonctions sont utilisées pour modifier la représentation entre le début et la fin d'une fonction publique, et briser ainsi inévitablement les invariants publics: c'est pourquoi ils doivent ne pas appeler les fonctions publiques.

Le même argument s'applique aux fonctions protégées: Les fonctions ne peuvent appeler que des fonctions avec des invariants plus faibles.

Les fonctions virtuelles sont toujours appelées par le public à partir des wrappers publics de la classe de base afin de garantir la séquençage des opérations, qui brise des invariants publics, n'est jamais interrompue en revenant au public avec un invariant cassé. L'ensemble de virtuelles elles-mêmes représente la structure invariante toute représentation doit avoir. En faisant, toutes les manipulations de la représentation pour effectuer des calculs pour les clients publics peuvent être résumées dans la base.

En pratique, ces règles ne sont généralement pas suivies car elles généreraient souvent des emballages triviaux et c'est beaucoup de code supplémentaire pour écrire et entretenir. Les fonctions virtuelles finissent donc souvent par être publiques, même lorsque cela est complètement et totalement faux en principe.

1
Yttrill

Avant de créer une fonction ou une classe, nous devrions comprendre la portée de cette fonction ou une classe si elle est globalement ou locale.

par exemple: "ConnectionsRing ()". Chaque connexion de base de données nécessite "ConnectionsRing ()" donc son public déclaré.

0
Justinonday

privé: utilisé uniquement par cette classe, non utilisé par d'autres classes ni des cours dérivés.
Protégé: utilisé par cette classe et peut-être des cours dérivés, mais pas utilisé par d'autres classes.
[.____] public: utilisé par d'autres cours, cette classe et classe dérivée.

Il est difficile de choisir entre privé et protégé. Donc, je fais toujours une fonction protégée s'il y a 1% de chances que les classes dérivées puissent en avoir besoin.

0
wqking