Comment dois-je commander les membres d’une classe C ++?

Vaut-il mieux avoir tous les membres privés, puis tous les protégés, puis tous les publics? Ou l’inverse? Ou devrait-il y avoir plusieurs étiquettes privées, protégées et publiques pour que les opérations puissent être séparées des constructeurs, etc.? Quels problèmes devrais-je prendre en compte pour prendre cette décision?

Je mets d’abord l’interface publique, mais je ne l’ai pas toujours fait. J’avais l’habitude de faire les choses en arrière, avec privé, puis protégé, puis public. Avec le recul, cela n’avait pas beaucoup de sens.

En tant que développeur d’une classe, vous serez probablement familiarisé avec ses “entrailles”, mais les utilisateurs de la classe ne se soucient pas beaucoup, ou du moins ils ne devraient pas. Ils s’intéressent surtout à ce que la classe peut faire pour eux, non?

Donc, je mets le public en premier et l’organise généralement par fonction / utilitaire. Je ne veux pas qu’ils aient à parcourir mon interface pour trouver toutes les méthodes liées à X, je veux qu’ils voient tous ces éléments ensemble de manière organisée.

Je n’utilise jamais plusieurs sections publiques / protégées / privées – trop compliqué à suivre à mon avis.

Google privilégie cet ordre : “Typedefs et Enums, Constants, Constructeurs, Destructor, Méthodes, y compris les méthodes statiques, Membres de données, y compris les membres de données statiques.”

Matthew Wilson (abonnement Safari requirejs) recommande l’ordre suivant: “Construction, opérations, atsortingbuts, itération, état, implémentation, membres et mon favori, à ne pas implémenter”.

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

C’est mon avis, et je parierais que la plupart des gens seraient d’accord, que les méthodes publiques devraient passer en premier. L’un des principes fondamentaux d’OO est que vous ne devriez pas avoir à vous soucier de la mise en œuvre. Il suffit de regarder les méthodes publiques pour savoir tout ce que vous devez savoir pour utiliser la classe.

En général, je définis d’abord l’interface (à lire), qui est publique, puis protégée, puis privée. Maintenant, dans de nombreux cas, je fais un pas en avant et (si je peux le gérer) utilise le pattern PIMPL, en cachant complètement tous les éléments privés 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 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 postfixe des membres privés (et également protégés) avec un trait de soulignement. La version PIMPL a une classe interne pour laquelle le monde extérieur ne voit même pas les opérations. Cela maintient l’interface de classe complètement propre: seule l’interface réelle est exposée. Pas besoin de discuter de l’ordre.

Il y a un coût associé pendant la construction de la classe car un object alloué dynamicment doit être construit. En outre, cela fonctionne très bien pour les classes qui ne sont pas destinées à être étendues, mais comporte des raccourcis avec les hiérarchies. Les méthodes protégées doivent faire partie de la classe externe, vous ne pouvez donc pas vraiment les insérer dans la classe interne.

Comme toujours, écrivez d’abord votre code pour les humains . Pensez à la personne qui utilisera votre classe et placez-leur les membres / énumérations / typedefs / quoi les plus importants en haut.

Habituellement, cela signifie que les membres du public sont au sumt car c’est ce qui intéresse le plus la plupart des consommateurs de votre classe. Habituellement.

Il y a quelques exceptions.

Parfois, l’ordre d’initialisation est important et parfois, un privé doit être déclaré devant un public. Parfois, il est plus important qu’une classe soit héritée et étendue, auquel cas les membres protégés peuvent être placés plus haut. Et quand on pirate les tests unitaires sur le code hérité, il est parfois plus facile d’exposer des méthodes publiques – si je dois commettre ce quasi-péché, je les placerai au bas de la définition de la classe.

Mais ce sont des situations relativement rares.

Je trouve que la plupart du temps “public, protégé, privé” est le plus utile pour les consommateurs de votre classe. C’est une règle de base décente à respecter.

Mais il s’agit moins de commander en accédant et plus de commander en fonction des intérêts du consommateur .

Je pense que tout est une 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 des données publiques.

En général, j’estime que les choses les plus importantes devraient être prioritaires. Pour 99,6% de toutes les classes, en gros, cela signifie les méthodes publiques, et en particulier le constructeur. Viennent ensuite les membres des données publiques, le cas échéant (rappelez-vous: l’encapsulation est une bonne idée), suivie de toutes les méthodes et membres de données protégés et / ou privés.

Ce sont des éléments qui pourraient être couverts par les normes de codage des grands projets, cela peut être une bonne idée de vérifier.

J’ai tendance à suivre le guide de style de codage POCO C ++ .

C’est très utile pour les gens qui utiliseront votre classe pour lister l’interface publique en premier. C’est la partie dont ils se soucient et qu’ils peuvent utiliser. Protégé et privé peut suivre après.

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

Notez que (selon votre compilateur et l’éditeur de liens dynamic), 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 (à la fin de l’interface), sans rien supprimer ou modifier. (Cela est vrai pour G ++ et libtool, et le schéma de gestion des versions en trois parties pour les bibliothèques partagées GNU / Linux le reflète.)

Il y a aussi l’idée que vous devez commander les membres de la classe pour éviter le gaspillage d’espace dû à l’alignement de la mémoire; Une stratégie consiste à commander les membres de la plus petite à la plus grande taille. Je n’ai jamais fait cela en C ++ ou en C cependant.

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

Il est très populaire de mettre les méthodes publiques au premier plan, apparemment 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, par conséquent, baser les «meilleures pratiques» autour de l’idée que les utilisateurs regarderont vos en-têtes semble manquer la cible pour moi.

Il est plus probable que les utilisateurs soient dans vos en-têtes s’ils modifient la classe, auquel cas ils doivent se soucier de l’interface privée.

Quel que soit votre choix, rendez vos en-têtes propres et faciles à lire. Pouvoir trouver facilement les informations recherchées, que je sois un utilisateur de la classe ou un responsable de la classe, est la chose la plus importante.

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

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

Ici, la barre de membre est placée avant le membre GetBar () car la première est utilisée par la seconde. Cela peut entraîner plusieurs sections d’access, 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 de la barre , voir?

Pourquoi est-ce? Je ne sais pas, il a semblé plus naturel que si vous rencontrez un membre quelque part dans l’implémentation et que vous ayez besoin de plus de détails à ce sujet (et IntelliSense est foutu à nouveau) que vous pouvez le trouver quelque part d’où vous travaillez.

Dans l’ensemble, votre interface publique devrait être avant tout, car c’est la seule et unique chose qui devrait intéresser les utilisateurs de vos classes. (Bien sûr, en réalité, cela ne tient pas toujours, mais c’est un bon début.)

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

Le style de codage est une source de conversation étonnamment animée, dans cet esprit, je risque de donner une opinion différente:

Le code doit être écrit de manière à ce qu’il soit le plus lisible pour les humains. Je suis d’accord avec cette déclaration qui a été donnée ici à plusieurs resockets.

La déviation est quel rouleau nous prenons environ.

Pour aider l’ utilisateur de la classe à comprendre comment l’utiliser, il convient d’écrire et de conserver une documentation appropriée. Un utilisateur ne devrait jamais avoir besoin de lire le code source pour pouvoir utiliser la classe. Si cela est fait (manuellement ou à l’aide d’outils de documentation internes), l’ordre dans lequel les membres de classes publics et privés 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 la révision du code, de la requête d’extraction ou de la maintenance, la commande compte beaucoup: la règle est simple:

les éléments doivent être définis avant d’être utilisés

Ce n’est ni une règle du compilateur, ni une règle ssortingctement publique vs privée, mais du sens commun – règle de lisibilité humaine. Nous lisons le code de manière séquentielle, et si nous avons besoin de “jongler” d’avant en arrière chaque fois que nous voyons un membre de classe utilisé, mais ne connaissons pas son type par exemple, cela nuit à la lisibilité du code.

Rendre une division ssortingctement privée ou publique viole cette règle car les membres de la classe privée apparaîtront après avoir été utilisés dans une méthode publique.

Mettez les champs privés en premier.

Avec les IDE modernes, les gens ne lisent pas la classe pour savoir quelle est son interface publique.

Ils utilisent juste intellisence (ou un navigateur de classe) pour cela.

Si quelqu’un lit la définition de la classe, c’est généralement parce qu’il veut comprendre son fonctionnement.

Dans ce cas, connaître les champs aide le plus. Il vous indique quelles sont les parties de l’object.

Dépend entièrement de vos préférences. Il n’y a pas “le bon chemin”.

Quand je fais du C ++ dans mes propres projets pour animaux de compagnie, je garde personnellement comme convention que je mets un modificateur d’access avant chaque déclaration de membre ou de méthode.