Quelles choses ne doivent absolument jamais être incluses dans un fichier d'en-tête?
Si, par exemple, je travaille avec un format standard de l'industrie documenté qui a beaucoup de constantes, est-ce une bonne pratique de les définir dans un fichier d'en-tête (si j'écris un analyseur pour ce format)?
Quelles fonctions doivent aller dans le fichier d'en-tête?
Quelles fonctions ne devraient pas?
Que mettre dans les en-têtes:
#include
Nécessaires pour rendre l'en-tête compilable lorsque l'en-tête est inclus dans un fichier source.Ce qui n'appartient pas à un en-tête:
#include
. Ces gratifications incluent la recompilation de choses qui n'ont pas besoin d'être recompilées, et peuvent parfois faire en sorte qu'un système ne puisse pas compiler. Ne pas #include
Un fichier dans un en-tête si l'en-tête lui-même n'a pas besoin de cet autre fichier d'en-tête.#include
Supplémentaire, qui sont susceptibles de changer ou qui sont trop grandes. Ces fonctions en ligne devraient avoir peu ou pas de fan out, et si elles ont un fan out, elles devraient être localisées dans les éléments définis dans l'en-tête.Qu'est-ce qui constitue l'ensemble minimal d'instructions #include
?
Il s’agit là d’une question non triviale. Une définition TL; DR: un fichier d'en-tête doit inclure les fichiers d'en-tête qui définissent directement chacun des types directement utilisés dans ou qui déclarent directement chacune des fonctions utilisées dans le fichier d'en-tête en question, mais ne doit rien inclure d'autre. Un pointeur ou un type de référence C++ n'est pas considéré comme une utilisation directe; les références directes sont préférées.
Il y a une place pour une directive #include
Gratuite, et c'est dans un test automatisé. Pour chaque fichier d'en-tête dans un progiciel, je génère et compile automatiquement les éléments suivants:
#include "path/to/random/header_under_test"
int main () { return 0; }
La compilation doit être propre (c'est-à-dire exempte d'avertissements ou d'erreurs). Des avertissements ou des erreurs concernant des types incomplets ou des types inconnus signifient que le fichier d'en-tête sous test contient des directives #include
Manquantes et/ou des déclarations aval manquantes. Notez bien: ce n'est pas parce que le test réussit que l'ensemble des directives #include
Est suffisant, et encore moins minimal.
En plus de ce qui a déjà été dit.
Les fichiers H doivent toujours contenir:
Les fichiers H ne doivent jamais contenir:
static
.(Je dirais également qu'il n'y a jamais aucune raison d'utiliser des variables globales/externes non constantes, n'importe où, mais c'est une discussion pour un autre article.)
Le fichier d'en-tête doit avoir l'organisation suivante:
Les fichiers d'en-tête ne doivent jamais contenir de définitions d'objet, uniquement des définitions de type et des déclarations d'objet.
Je ne dirais probablement jamais jamais, mais les instructions qui génèrent des données et du code au fur et à mesure de leur analyse ne devraient pas figurer dans un fichier .h.
Les macros, les fonctions en ligne et les modèles peuvent ressembler à des données ou du code, mais ils ne génèrent pas de code au fur et à mesure de leur analyse, mais plutôt lorsqu'ils sont utilisés. Ces éléments doivent souvent être utilisés dans plusieurs .c ou .cpp, ils appartiennent donc au .h.
À mon avis, un fichier d'en-tête devrait avoir l'interface pratique minimale à un .c ou .cpp correspondant. L'interface peut inclure #defines, class, typedef, des définitions de structure, des prototypes de fonction et des définitions externes moins préférées pour les variables globales. Cependant, si une déclaration est utilisée dans un seul fichier source, elle doit probablement être exclue du fichier .h et contenue dans le fichier source à la place.
Certains peuvent être en désaccord, mais mes critères personnels pour les fichiers .h sont qu'ils #incluent tous les autres fichiers .h dont ils ont besoin pour pouvoir compiler. Dans certains cas, cela peut être beaucoup de fichiers, nous avons donc des méthodes efficaces pour réduire les dépendances externes comme les déclarations directes aux classes qui nous permettent d'utiliser des pointeurs vers les objets d'une classe sans inclure ce qui pourrait être une grande arborescence de fichiers d'inclusion.
Les instructions qui génèrent des données et du code lors de leur analyse ne doivent pas être dans un .h
fichier. En ce qui concerne mon point de vue, un fichier d'en-tête ne devrait avoir que l'interface pratique minimale vers un .c
ou .cpp
.