FAQ C++Consultez toutes les FAQ
Nombre d'auteurs : 34, nombre de questions : 368, dernière mise à jour : 14 novembre 2021 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de http://www.developpez.com et de l'expérience personnelle des auteurs.
Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur ou si vous souhaitez devenir rédacteur, lisez ceci.
Sur ce, nous vous souhaitons une bonne lecture.
- Quels fichiers d'en-tête dois-je inclure ?
- Où dois-je inclure les fichiers d'en-tête ?
- Dans quel ordre dois-je mettre mes fichiers d'en-tête ?
- Comment structurer ma classe en un fichier .h et un fichier .cpp ?
- Comment faire avec les templates ?
- Comment vérifier que mon fichier d'en-tête peut être inclus indépendamment de tout autre ?
- Et avec les en-têtes précompilés ?
Le strict minimum : c'est-à-dire les seuls fichiers d'en-tête contenant les déclarations ou définitions de ce qui va être utilisé et permettant ainsi à la compilation de réussir.
Il est préférable d'avoir des déclarations anticipées (forward declaration) dans les fichiers d'en-tête et d'inclure l'en-tête de déclaration dans le fichier source. L'objectif à atteindre est que tout fichier d'en-tête doit pouvoir être inclus indépendamment des autres et compiler. Ce qui veut dire qu'un fichier d'en-tête doit contenir le moins de choses possibles.
Code c++ : | Sélectionner tout |
1 2 3 4 | class A { // déclaration de la classe A }; |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | class A; // déclaration anticipée class B { // déclaration de la classe B // … void do_someting_with_a_A(A const &); }; |
Code c++ : | Sélectionner tout |
1 2 3 | #include "B.h" #include "A.h" // définition de B… |
Pour aller plus loin avec les déclarations anticipées, jusqu'à présent vous avez l'habitude de découper votre code en deux fichiers : un fichier d'en-tête MyClass.h pour la déclaration et un fichier d'implémentation MyClass.cpp pour la définition. Notez qu'on peut associer un troisième fichier MyClassFwd.h pour regrouper les déclarations anticipées liées à CMyClass. Ce fichier contient tout naturellement une déclaration anticipée de la classe :
Code c++ : | Sélectionner tout |
class CMyClass;
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 | class CMyClass; enum E_options_my_class { // … }; std::ostream& operator << (std::ostream& O, const CMyClass& B); |
Code c++ : | Sélectionner tout |
#include "MyClassFwd.h"
- Le fichier d'en-tête de la déclaration de la classe ;
- les fichiers standards (STL) ;
- les fichiers d'en-tête de l'O.S. ;
- les fichiers d'en-tête des bibliothèques tierces (boost, xml, wxWidget…) ;
- les fichiers d'en-tête de mes bibliothèques externes ;
- les fichiers d'en-tête de mon projet.
Cet ordre est une proposition parmi d'autres qui ont aussi leur légitimité. Vous pouvez suivre un autre ordre d'inclusion si vous en sentez le besoin compte tenu de vos pratiques habituelles ou du contexte de votre application. En fait, l'idée maîtresse est de maintenir une cohérence sur l'ensemble du projet. Quelle que soit la politique que vous choisissez de mettre en ouvre, utilisez la même systématiquement dans tous vos fichiers.
Une classe est déclarée dans un fichier header (extension .h, .hpp. ou encore .hxx) dont l'inclusion multiple est protégée grâce à des directives du préprocesseur :
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | #ifndef MACLASSE_H #define MACLASSE_H class MaClasse { public: void Fonction(); }; #endif |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 | #include "maclasse.h" void MaClasse::Fonction() { // implémentation de la fonction } |
Certains seront parfois tentés d'inclure un fichier .cpp : c'est une erreur et cela ne doit jamais être fait (il en résulterait plusieurs corps pour une même fonction, par exemple).
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | #include "autreclasse.h" #include "maclasse.h" void AutreClasse::Fonction() { MaClasse M; M.Fonction(); } |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #ifndef MACLASSE_H #define MACLASSE_H class MaClasse { public: void FonctionInline() { // Placée dans la déclaration de la classe // cette fonction est considérée en ligne sans // que le mot clé inline ne figure } }; // Placée en dehors de la déclaration de la classe, le mot clé inline // est indispensable pour ne pas provoquer des définitions multiples // de la fonction et donc des erreurs à l'édition de liens inline void FonctionInline2() { } #endif |
Les templates nécessitent d'avoir toute la définition dans le fichier d'en-tête. Pour maintenir une politique cohérente, on peut séparer la déclaration d'une classe template (.h) et sa définition (.tpp). La définition est incluse à la fin du fichier de déclaration :
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 | template<class T> class TMyTemplateClass { public: void do_something(); }; #include "MyTemplateClass.tpp" |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 | // en-tête si besoin // définition template<class T> void TMyTemplateClass<T>::do_something() { } |
Inclure le fichier en tout premier dans un fichier .cpp. Ce dernier doit compiler sans erreur.
Les en-têtes précompilés n'offrent malheureusement pas de standard dans leur mise en ouvre. Tous les compilateurs ne les supportent pas, et ceux qui savent les gérer ne le font pas tous de la même façon. Est-ce une raison pour les abandonner ? Non. Car ils offrent de vrais avantages en terme de temps de compilation, surtout pour les projets utilisant des bibliothèques volumineuses ou complexes. La question qui se pose alors est de savoir quoi mettre dans les en-têtes précompilés ? Il faut garder à l'esprit l'objectif des en-têtes précompilés : accélérer la compilation. Il faut donc veiller à mettre les fichiers des bibliothèques externes récurrents dans vos sources ainsi que ceux qui sont susceptibles de provoquer des inclusions en cascade (afxXXX.h avec les MFC, wx.h dans wxWidgets). En revanche ne mettez pas des fichiers d'en-têtes du projet en cours car ce sont ceux qui sont le plus susceptibles de varier et dégradent ainsi le temps de compilation en forçant à tout recompiler.
Il faut être vigilant à ne pas transformer le fichier d'en-têtes précompilés en un fourre-tout contenant tous les fichiers de toutes les bibliothèques utilisées dans un projet. Cela rompt le principe qui veut que l'on minimise les dépendances entre les unités de compilation. Identifiez correctement les fichiers clés qui sont significatifs dans le temps de compilation de votre projet.
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.