web-dev-qa-db-fra.com

Comment devrais-je commander les membres d'une classe C ++?

Est-il préférable d'avoir tous les membres privés, puis tous les protégés, alors tous les publics? Ou l'inverse? Ou devrait-il y avoir plusieurs étiquettes privées, protégées et publiques afin que les opérations puissent être séparées des constructeurs et ainsi de suite? Quels problèmes devrais-je prendre en compte lors de la prise de cette décision?

56
Tommy Herbert

Google favorise cette commande : "Typefefs et Enums, constantes, constructeurs, destructeurs, méthodes, y compris les méthodes statiques, les membres de données, y compris les membres statiques de données."

Matthew Wilson (Safari Abonnement requis) Recommande l'ordre suivant: "Construction, opérations, attributs, itération, état, mise en œuvre, membres et mon préféré, à ne pas être mis en œuvre."

Ils offrent de bonnes raisons et ce type d'approche semble être assez standard, mais quoi que ce soit, soyez cohérent à ce sujet.

37
Josh Kelley

C'est mon avis, et je devrais remis à ce que la plupart des gens soient d'accord, que les méthodes publiques devraient d'abord aller. L'un des principes fondamentaux de OO est-ce que vous ne devriez pas avoir à vous soucier de la mise en œuvre. Juste regarder les méthodes publiques devraient vous dire tout ce dont vous avez besoin pour savoir utiliser la classe.

8
korona

Comme toujours, écrivez votre code pour Humains d'abord. Considérez la personne qui utilisera votre classe et placera les membres les plus importants/ENUMS/TYPEDEFS/Peu importe à eux en haut.

généralement Cela signifie que les membres du public sont au sommet, car c'est ce que la plupart des consommateurs de votre classe sont les plus intéressés. Protégé vient ensuite suivi de nos privés. D'habitude.

Il y a quelques exceptions.

L'ordre d'initialisation occasionnellement est important et parfois un privé devra être déclaré avant un public. Il est parfois plus important que la classe soit héritée et étendue auquel cas les membres protégés puissent être placés plus haut. Et lorsque l'unité de piratage teste un code héritée, il est parfois plus facile d'exposer des méthodes publiques - si je dois commettre ce pays proche, je les placerai au bas de la définition de la classe.

Mais ils sont relativement rares situations.

Je trouve que la plupart du temps "public, protégé, privé" est le plus utile aux consommateurs de votre classe. C'est une règle de base décente à coller.

Mais il est moins de commander par accès et plus sur commander par intérêt pour le consommateur.

5
MattyT

Je définis généralement d'abord l'interface (à lire), qui est public, puis protégée, puis des trucs privés. Maintenant, dans de nombreux cas, je passe un pas en avant et (si je peux le gérer), utilisez le motif PIMPL, caché entièrement toutes les choses privées de l'interface de la classe réelle.

class Example1 {
public:
   void publicOperation();
private:
   void privateOperation1_();
   void privateOperation2_();

   Type1 data1_;
   Type2 data2_;
};
// example 2 header:
class Example2 {
   class Impl;
public:
   void publicOperation();
private:
   std::auto_ptr<Example2Impl> impl_;
};
// example2 cpp:
class Example2::Impl
{
public:
   void privateOperation1();
   void privateOperation2();
private: // or public if Example2 needs access, or private + friendship:
   Type1 data1_;
   Type2 data2_;
};

Vous pouvez remarquer que je postfix privés (et également protégés) membres avec un soulignement. La version PIMPL a une classe interne pour laquelle le monde extérieur ne voit même pas les opérations. Ceci maintient l'interface de classe complètement propre: seule une interface réelle est exposée. Pas besoin de discuter à propos de l'ordre.

Il y a un coût associé au cours de la construction de classe comme un objet attribué de manière dynamique doit être construit. Cela fonctionne également très bien pour les cours qui ne sont pas destinés à être étendus, mais ont de courtes allées avec des hiérarchies. Les méthodes protégées doivent faire partie de la classe externe, de sorte que vous ne pouvez pas vraiment les pousser dans la classe interne.

Le style de codage est une source de conversation étonnamment chauffée, avec cela à l'esprit, je risque de fournir une opinion différente:

Le code doit être écrit afin qu'il soit le plus lisible pour les humains. Je suis tout à fait d'accord avec cette déclaration qui a été donnée ici plusieurs fois.

La déviation est à quel rouleau prenons-nous.

Pour aider le tilisateur de la classe comprennent comment l'utiliser, il faut écrire et maintenir la bonne documentation. Un utilisateur ne doit jamais avoir besoin de lire le code source pour pouvoir utiliser la classe. Si cela est fait (manuellement ou utiliser des outils de documentation à source), l'ordre dans lequel les membres du groupe public et privé sont définis dans la source n'a pas d'importance pour l'utilisateur.

Cependant, pour quelqu'un qui a besoin de comprendre le code, lors de l'examen du code, de la demande de traction ou de la maintenance, la commande compte une grande transaction - la règle est simple:

Les éléments doivent être définis avant qu'ils ne soient utilisés

Ce n'est ni une règle de compilateur qui n'est pas un strictement public V.S. Règle privée, mais bon sens - Règle de lisibilité humaine. Nous lisons le code de manière séquentielle et si nous avons besoin de "jongler" à chaque fois que nous voyons un membre de classe utilisé, mais je ne connais pas son type par exemple, il affecte négativement la lisibilité du code.

Faire une division strictement sur le v. Le public enfreint cette règle car les membres de la classe privée apparaîtront après avoir été utilisés dans une méthode publique.

3
PolarBear2015

J'ai tendance à suivre le Guide de style de codage Poco C++ .

2
ayaz

En pratique, cela compte rarement. C'est avant tout une question de préférence personnelle.

Il est très populaire de mettre d'abord des méthodes publiques, ce qui vient d'abord pour que les utilisateurs de la classe puissent les trouver plus facilement. Mais les en-têtes ne devraient jamais être votre principale source de documentation, ce qui explique les "meilleures pratiques" autour de l'idée que les utilisateurs examineront vos en-têtes semble manquer la marque pour moi.

Il est plus probable que les gens soient dans vos en-têtes s'ils sont modifier la classe, auquel cas ils devraient Soin de l'interface privée.

Quel que soit votre choix, rendez vos en-têtes propres et faciles à lire. Être capable de trouver facilement toutes les informations que je cherche, que je sois un utilisateur de la classe ou d'un responsable de la classe, est la chose la plus importante.

2
Dan Olson

je pense que tout est question de lisibilité.

Certaines personnes aiment les regrouper dans un ordre fixe, de sorte que chaque fois que vous ouvrez une déclaration de classe, vous savez rapidement où chercher par exemple. les membres de la Données publiques.

En général, je pense que les choses les plus importantes devraient venir en premier. Pour 99,6% de toutes les classes, à peu près, cela signifie les méthodes publiques, en particulier le constructeur. Vient ensuite des membres de données publiques, le cas échéant (rappelez-vous: l'encapsulation est une bonne idée), suivie de toute méthode protégée et/ou privée et membres de données.

C'est des choses qui pourraient être couvertes par les normes de codage des grands projets, cela peut être une bonne idée de vérifier.

2
unwind

Globalement, votre interface publique devrait venir avant quoi que ce soit, car c'est la principale chose que les utilisateurs de vos classes devraient être intéressées. (Bien sûr, en réalité qui ne tient pas toujours, mais c'est un bon début.)

Dans ce cas, les types de membres et les constantes sont les meilleurs premiers, suivis des opérateurs de construction, des opérations, puis des variables des membres.

1
dcw

Notez que (selon votre compilateur et votre liaison dynamique), vous pouvez conserver la compatibilité avec les versions précédentes d'une bibliothèque partagée en ajoutant uniquement à la fin de la classe (c'est-à-dire à la fin de l'interface) et ne pas enlever ou changer quoi que ce soit d'autre. (Ceci est vrai pour G ++ et libtool, et le schéma de la version en trois parties pour les bibliothèques partagées GNU/Linux le reflète.)

Il y a aussi l'idée que vous devriez commander des membres de la classe pour éviter les espaces gaspillés en raison de l'alignement de la mémoire; Une stratégie est de commander des membres de la plus petite à la plus grande taille. Je n'ai jamais fait cela non plus en C++ ou C cependant.

1
Reed Hedges

Dans notre projet, nous ne commandons pas les membres selon l'accès, mais par usage. Et par là, je veux dire, nous commandons les membres comme ils sont utilisés. Si un membre public utilise un membre privé dans la même classe, ce membre privé est généralement situé devant le membre public quelque part, comme dans l'exemple suivant (simpliste):

class Foo
{
private:
  int bar;

public:
  int GetBar() const
  {
    return bar;
  }
};

Ici, le membre bar est placé avant le membre getbar () car le premier est utilisé par ce dernier. Cela peut entraîner plusieurs sections d'accès, comme dans l'exemple suivant:

class Foo
{
public:
  typedef int bar_type;

private:
  bar_type bar;

public:
  bar_type GetBar() const
  {
    return bar;
  }
};

Le membre bar_type est utilisé par le membre bar, voir?

Pourquoi est-ce? Je ne sais pas, il semblait plus naturel que si vous rencontrez un membre quelque part dans la mise en œuvre et que vous avez besoin de plus de détails à ce sujet (et IntelliSense est bousillé à nouveau) que vous pouvez le trouver quelque part au-dessus de votre travail.

1
Dave Van den Eynde

Il est vraiment utile pour les gens qui utiliseront votre classe pour répertorier d'abord l'interface publique. C'est la partie qui se soucient et peuvent utiliser. Protégé et privé peut suivre après.

Dans l'interface publique, il est pratique de collecter des constructeurs, des accesseurs de propriétés et des mutateurs, ainsi que des opérateurs de groupes distincts.

1
Todd