web-dev-qa-db-fra.com

Organisation des fichiers d'en-tête de classe C ++

Quelles sont les directives de codage C++ et d'organisation de fichiers que vous suggérez pour les personnes qui doivent gérer de nombreuses classes interdépendantes réparties sur plusieurs fichiers source et en-tête?

J'ai cette situation dans mon projet et résoudre les erreurs liées à la définition de classe traversant plusieurs fichiers d'en-tête est devenu un vrai casse-tête.

50
Ashwin Nanjappa

Quelques directives générales:

  • Associez vos interfaces avec des implémentations. Si tu as foo.cxx, tout ce qui y est défini devrait être déclaré dans foo.h.
  • Assurez-vous que chaque fichier d'en-tête #inclut tous les autres en-têtes ou déclarations nécessaires nécessaires à une compilation indépendante.
  • Résistez à la tentation de créer un en-tête "tout". Ils ont toujours des problèmes sur la route.
  • Mettez un ensemble de fonctionnalités liées (et interdépendantes) dans un seul fichier. Java et d'autres environnements encouragent une classe par fichier. Avec C++, vous voulez souvent une ensemble de classes par fichier. Cela dépend de la structure de votre code .
  • Préférez la déclaration directe sur #includes autant que possible. Cela vous permet de rompre les dépendances cycliques de l'en-tête. Essentiellement, pour les dépendances cycliques sur des fichiers distincts, vous voulez un graphique de dépendance de fichier qui ressemble à ceci:
    • A.cxx a besoin A.h et B.h
    • B.cxx a besoin A.h et B.h
    • A.h a besoin B.h
    • B.h est indépendant (et déclare en amont les classes définies dans A.h)

Si votre code est destiné à être une bibliothèque consommée par d'autres développeurs, certaines étapes supplémentaires sont importantes à suivre:

  • Si nécessaire, utilisez le concept d '"en-têtes privés". Autrement dit, les fichiers d'en-tête qui sont requis par plusieurs fichiers source, mais jamais requis par l'interface publique. Il peut s'agir d'un fichier avec des fonctions en ligne communes, des macros ou des constantes internes.
  • Séparez votre interface publique de votre implémentation privée au niveau du système de fichiers. J'ai tendance à utiliser include/ et src/ sous-répertoires de mes projets C ou C++, où include/ a tous mes en-têtes publics, et src/ a toutes mes sources. et en-têtes privés.

Je recommanderais de trouver une copie du livre de John Lakos Large-Scale C++ Software Design. C'est un livre assez lourd, mais si vous parcourez simplement certaines de ses discussions sur l'architecture physique, vous apprendrez beaucoup.

66
Tom

Consultez les normes de codage C et C++ au NASA Goddard Space Flight Center . La seule règle que j'ai spécialement notée dans la norme C et que j'ai adoptée dans mon propre code est celle qui applique la nature "autonome" des fichiers d'en-tête. Dans le fichier d'implémentation xxx.cpp pour l'en-tête xxx.h, assurez-vous que xxx.h est le premier en-tête inclus. Si l'en-tête n'est pas autonome à tout moment, la compilation échouera. C'est une règle magnifiquement simple et efficace.

La seule fois où il vous échoue, c'est si vous transférez entre les machines et que l'en-tête xxx.h inclut, par exemple, <pqr.h>, mais <pqr.h> nécessite des installations qui sont mises à disposition par un en-tête <abc.h> sur la plate-forme d'origine (donc <pqr.h> comprend <abc.h>), mais les installations ne sont pas mises à disposition par <abc.h> sur l'autre plate-forme (ils sont dans def.h à la place, mais <pqr.h> n'inclus pas <def.h>). Ce n'est pas une faute de la règle, et le problème est plus facilement diagnostiqué et résolu si vous suivez la règle.

8
Jonathan Leffler

Vérifiez la section du fichier d'en-tête dans guide de style Google

6
yesraaj

la réponse de Tom est excellente!

La seule chose que j'ajouterais est de ne jamais avoir "à l'aide de déclarations" dans les fichiers d'en-tête. Ils ne doivent être autorisés que dans les fichiers d'implémentation, par exemple foo.cpp.

La logique est bien décrite dans l'excellent livre "Accelerated C++" ( lien Amazon - aseptisé pour les nazis de script pour les enfants)

5
Rob Wells

Je voudrais ajouter une très bonne pratique (à la fois en C et C++) qui est souvent abandonnée:

foo.c

#include "foo.h" // always the first directive

Tous les autres en-têtes nécessaires devraient suivre, puis coder. Le fait est que vous avez presque toujours besoin de cet en-tête pour cette unité de compilation de toute façon et l'inclure comme première directive garantit que l'en-tête reste auto-suffisant (sinon, il y aura des erreurs). Cela est particulièrement vrai pour les en-têtes publics.

Si à tout moment vous devez mettre quelque chose avant cette inclusion d'en-tête (sauf les commentaires bien sûr), il est probable que vous faites quelque chose de mal. Sauf si vous savez vraiment ce que vous faites ... ce qui conduit à une autre règle plus cruciale => commentez vos hacks!

3
Alex

Un point en plus des autres ici:

N'incluez aucune définition privée dans un fichier include. Par exemple. toute définition qui n'est utilisée que dans xxx.cpp doit être dans xxx.cpp, pas xxx.h.

Cela semble évident, mais je le vois souvent.

3
Steve Fallows