Question

Quel ordre les en-têtes doivent-ils être déclarés dans un fichier header / cpp? De toute évidence, ceux qui sont requis par les en-têtes suivants doivent être antérieurs et les en-têtes spécifiques à une classe doivent être dans la portée cpp et non dans la portée de l'en-tête, mais existe-t-il une convention ou une pratique exemplaire en matière d'ordre?

Était-ce utile?

La solution

Dans un fichier d'en-tête, vous devez inclure TOUS les en-têtes pour le rendre compilable. Et n'oubliez pas d'utiliser des déclarations forward au lieu de certains en-têtes.

Dans un fichier source:

  • fichier d'en-tête correspondant
  • en-têtes de projet nécessaires
  • en-têtes de bibliothèques tierces
  • en-têtes de bibliothèques standard
  • en-têtes système

Dans cet ordre, vous ne manquerez aucun de vos fichiers d'en-tête ayant oublié d'inclure les bibliothèques par leurs propres moyens.

Autres conseils

Bonne pratique: chaque fichier .h devrait avoir un fichier .cpp incluant ce fichier .h avant tout. Cela prouve que tout fichier .h peut être placé en premier.

Même si l'en-tête ne nécessite aucune implémentation, vous créez un fichier .cpp ne contenant que ce fichier .h et rien d'autre.

Cela signifie que vous pouvez répondre à votre question comme bon vous semble. Peu importe l'ordre dans lequel vous les incluez.

Pour d'autres astuces intéressantes, essayez ce livre: Conception de logiciels C ++ à grande échelle - Dommage que ce soit si cher, mais c’est pratiquement un guide de survie pour l’agencement du code source C ++.

Dans les fichiers d'en-tête, j'ai tendance à placer les en-têtes standard en premier, puis les propres en-têtes (les deux listes étant classées par ordre alphabétique). Dans les fichiers d'implémentation, je mets d'abord l'en-tête correspondant (le cas échéant), puis les en-têtes de normes et les autres en-têtes de dépendances.

L'ordre n'a que peu d'importance, sauf si vous utilisez beaucoup les macros et #define; dans ce cas, vous devez vérifier qu'une macro que vous avez définie ne remplace pas une macro précédemment incluse (sauf si c'est ce que vous voulez, bien sûr).

À propos de cette déclaration

  

ceux qui sont requis par les en-têtes suivants doivent être antérieurs

Un en-tête ne devrait pas dépendre d'inclure d'autres en-têtes avant! S'il nécessite des en-têtes, il les inclut simplement. Les en-têtes empêcheront les inclusions multiples:

#ifndef FOO_HEADER_H
#define FOO_HEADER_H
...
#endif

EDIT

Depuis que j'ai écrit cette réponse, j'ai changé ma façon de commander les directives d'inclusion dans mon code. Maintenant, j'essaie de toujours placer les en-têtes dans un ordre croissant de normalisation, de sorte que les en-têtes de mon projet viennent en premier, suivis des en-têtes des bibliothèques tierces, suivis des en-têtes standard.

Par exemple, si l'un de mes fichiers utilise une bibliothèque que j'ai écrite, Qt, Boost et la bibliothèque standard, je commanderai l'include comme suit:

//foo.cpp
#include "foo.hpp"

#include <my_library.hpp>
// other headers related to my_library

#include <QtCore/qalgorithms.h>
// other Qt headers

#include <boost/format.hpp> // Boost is arguably more standard than Qt
// other boost headers

#include <algorithms>
// other standard algorithms

La raison pour laquelle je le fais est pour détecter les dépendances manquantes dans mes propres en-têtes: supposons par exemple que my_library.hpp utilise std::copy, mais n'inclut pas <algorithm>. Si je l'inclue après foo.cpp dans <=>, cette dépendance manquante passera inaperçue. Au contraire, avec l’ordre que je viens de présenter, le compilateur se plaint que <=> n’a pas été déclaré, ce qui me permet de corriger <=>.

Dans chaque " bibliothèque " groupe, j’essaie de conserver les directives d’inclusion dans l’ordre alphabétique pour les retrouver plus facilement.

Sur une note de bas de page, une bonne pratique consiste également à limiter au maximum la dépendance entre les fichiers d’en-tête. Les fichiers doivent inclure le moins d'en-têtes possible, en particulier le fichier des en-têtes. En effet, plus vous incluez d'en-têtes, plus le code doit être recompilé lorsque quelque chose change. Un bon moyen de limiter ces dépendances consiste à utiliser la déclaration aval, qui est très souvent suffisante dans les fichiers d’en-tête (voir Quand puis-je utiliser une déclaration forward? ? ).

Guide de style de Google C ++, noms et ordre des actions :

  

Dans dir / foo.cc, dont le but principal est d’implémenter ou de tester les éléments dans dir2 / foo2.h, commandez les éléments d’inclusion comme suit:

     
      
  • dir2 / foo2.h (emplacement préféré & # 8212; voir les détails ci-dessous).
  •   
  • Fichiers système C.
  •   
  • Fichiers système C ++.
  •   
  • Fichiers .h d'autres bibliothèques.
  •   
  • Les fichiers .h de votre projet.
  •   

J'avais l'habitude de les classer par ordre alphabétique (plus facile à trouver)

Le " comment " n’est pas évident, mais le " quel " est. Votre objectif est de vous assurer que l'ordre dans lequel vous incluez les fichiers d'en-tête n'a jamais d'importance (et je veux dire & "JAMAIS! &";).

Pour vérifier si les fichiers d’en-tête sont compilés lors de la création de fichiers cpp (un pour chaque fichier d’en-tête) qui ne contient qu’un d’eux.

Pour les fichiers .cpp, vous devez inclure l’en-tête de la classe ou tout ce que vous implémentez en premier, afin d’attraper le cas où cet en-tête manque des inclus. Ensuite, la plupart des instructions de codage ont tendance à inclure les en-têtes système en premier, puis les en-têtes de projet, par exemple Guide de style de Google C ++ .

C'est une question de dépendance et cela dépend en grande partie de ce que vous mettez dans nos en-têtes. Le fait est que vous pouvez être vraiment notoire à ce sujet et minimiser pour que vos inclus soient stricts, mais vous finirez par rencontrer un scénario dans lequel vous voudrez utiliser des protections d'inclusion.

#ifndef MY_HEADER_H
#define MY_HEADER_H
//...
#endif

Le problème n’est pas évident au début, mais vos dépendances augmentent en même temps que la complexité de votre logiciel. Vous pouvez bien faire et être intelligent à ce sujet, mais les plus gros projets C ++ sont généralement compliqués. Vous pouvez essayer, mais vous ne pouvez faire que beaucoup. Alors soyez assidu et pensez à vos inclus, OUI! Mais vous aurez très certainement des dépendances cycliques à un moment donné et c'est pourquoi vous avez besoin de gardes d'inclusion.

Si un en-tête a besoin d'autres en-têtes, il les inclut simplement dans cet en-tête.

Essayez de structurer votre code de manière à transmettre des pointeurs ou des références et à déclarer en avant où vous le pouvez.

Dans l'implémentation, l'en-tête qui le définit doit être répertorié en premier (sauf dans Visual Studio, si vous utilisez pch, stdafx est le premier).

Je les répertorie généralement selon mes besoins.

J'ai trouvé la convention suivante la plus utile:

module.cpp:

// this is the header used to trigger inclusion of precompiled headers
#include <precompiled.h> 
// this ensures that anything that includes "module.h" works
#include "module.h"
// other headers, usually system headers, the project

L'important est de placer l'en-tête du module en tant que premier en-tête non précompilé. Cela garantit que & Quot; module.h & Quot; n'a pas de dépendances inattendues.

Si vous travaillez sur un projet volumineux avec des temps d’accès au disque lents, j’ai vu ce style utilisé pour réduire les temps de construction:

module.cpp:

// this is the header used to trigger inclusion of precompiled headers
#include <precompiled.h> 
// this ensures that anything that includes "module.h" works
#include "module.h"
// other headers, usually system headers, the project
#if !defined _OTHER_MODULE_GUARD_
#include "other_module.h"
#endif 

#if !defined _ANOTHER_MODULE_GUARD_
#include "another_module.h"
#endif 

C'est un peu bavard, mais la sauvegarde sur disque est sauvegardée car l'en-tête ne sera pas recherché / ouvert s'il est déjà inclus. Sans la vérification de garde, le compilateur recherchera et ouvrira le fichier d’en-tête, analysera le fichier dans son intégralité pour obtenir #ifdef la totalité du fichier.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top