124 votes

C++ - Ce qu'il devrait aller dans une .h fichier?

Lors de la division de votre code dans plusieurs fichiers juste exactement ce que devrait aller dans une .h de fichier et de ce qu'il devrait aller dans une .fichier cpp?

146voto

Amber Points 159296

Fichiers d'en-tête (.h) sont conçus pour fournir les informations qui seront nécessaires dans plusieurs fichiers. Des choses comme les déclarations de classe, les prototypes de fonction, et les énumérations généralement d'aller dans les fichiers d'en-tête. En un mot, "définitions".

Les fichiers de Code (.cpp) sont conçues pour assurer la mise en œuvre de l'information qui ne doit être connue dans un fichier. En général, le corps des fonctions et des variables internes qui devrait/ne sera jamais accessible par d'autres modules, sont ce qui appartient en .cpp fichiers. En un mot, "les implémentations".

Le plus simple question à vous poser afin de déterminer ce qui appartient là où il est "si je change ce, vais-je avoir à modifier le code dans d'autres fichiers pour rendre les choses compiler à nouveau?" Si la réponse est "oui", il appartient probablement dans le fichier d'en-tête; si la réponse est "non", il appartient probablement dans le fichier de code.

67voto

paercebal Points 38526

Le fait est, en C++, c'est un peu plus compliqué que les en-tête C/organisation de la source.

Ce que le compilateur voit?

Le compilateur voit une grande source (.rpc) fichier de avec ses en-têtes inclus. Le fichier source est l'unité de compilation qui sera compilé dans un fichier objet.

Alors, pourquoi les en-têtes sont nécessaires?

Parce qu'une unité de compilation pourrait avoir besoin d'informations sur la mise en œuvre dans une autre unité de compilation. Donc, on peut écrire par exemple la mise en œuvre d'une fonction à une seule source, et écrire la déclaration de cette fonction dans une autre source ayant besoin de l'utiliser.

Dans ce cas, il existe deux copies de la même information. Qui est le mal...

La solution est de partager quelques détails. Alors que la mise en œuvre doit rester dans la Source, la déclaration du partage des symboles, comme des fonctions ou de la définition de structures, classes, les énumérations, etc., pourrait avoir besoin d'être partagé.

Les en-têtes sont utilisés pour mettre ceux partagé des détails.

Passer à l'en-tête les déclarations de ce que doivent être partagées entre plusieurs sources

Rien de plus?

En C++, il y a quelques autres choses qui pourraient être mis dans l'en-tête parce que, ils doivent, eux aussi, être partagé:

  • code en ligne
  • modèles
  • les constantes (généralement ceux que vous souhaitez utiliser à l'intérieur des commutateurs...)

Passer à l'en-tête de TOUT ce qui doit être partagé, y compris partagé implémentations

Ensuite, il signifie qu'il y a peut être des sources dans les en-têtes?

Oui. En fait, il ya beaucoup de choses différentes qui pourraient être à l'intérieur d'un "en-tête" (c'est à dire partagé entre les sources).

  • Déclaration
  • déclarations/définition de fonctions/structures/classes/modèles
  • mise en ligne et basé sur un modèle de code

Cela devient compliqué, et dans certains cas (les dépendances circulaires entre les symboles), impossible de le garder dans l'en-tête.

Les en-têtes peut être décomposé en trois parties

Cela signifie que, dans un cas extrême, on pourrait avoir:

  • une déclaration anticipée d'en-tête
  • une déclaration/définition de l'en-tête
  • une mise en œuvre de l'en-tête
  • une mise en œuvre de la source

Imaginons que nous avons basé sur un modèle MyObject. On pourrait avoir:

// - - - - MyObject_forward.hpp - - - - 
// This header is included by the code which need to know MyObject
// does exist, but nothing more.
template<typename T>
class MyObject ;

.

// - - - - MyObject_declaration.hpp - - - - 
// This header is included by the code which need to know how
// MyObject is defined, but nothing more.
#include <MyObject_forward.hpp>

template<typename T>
class MyObject
{
   public :
      MyObject() ;
   // Etc.
} ;

void doSomething() ;

.

// - - - - MyObject_implementation.hpp - - - - 
// This header is included by the code which need to see
// the implementation of the methods/functions of MyObject,
// but nothing more.
#include <MyObject_declaration.hpp>

template<typename T>
MyObject<T>::MyObject()
{
   doSomething() ;
}

// etc.

.

// - - - - MyObject_source.cpp - - - - 
// This source will have implementation that does not need to
// be shared, which, for templated code, usually means nothing...
#include <MyObject_implementation.hpp>

void doSomething()
{
   // etc.
} ;

// etc.

Wow!

Dans la "vraie vie", il est généralement moins compliqué. La plupart du code aura seulement un simple en-tête/source de l'organisation, avec quelques inline code dans la source.

Mais dans d'autres cas (basé sur un modèle d'objets de savoir les uns des autres), j'ai dû avoir pour chaque objet séparé de déclaration et de mise en œuvre des en-têtes, avec un vide de source y compris ceux en-têtes pour m'aider à voir quelques erreurs de compilation.

Une autre raison pour briser les en-têtes dans un en-tête différent pourrait être pour accélérer la compilation, la limitation de la quantité de symboles analysée au strict nécessaire, et en évitant d'inutiles recompilation d'une source qui ne s'occupe que de la déclaration anticipée lorsqu'une ligne de la méthode de la mise en œuvre changé.

Conclusion

Vous devriez faire de votre code d'organisation à la fois aussi simple que possible, et aussi modulaire que possible. Mettre autant que possible dans le fichier source. Seulement exposer dans les en-têtes de ce qui doit être partagée.

Mais le jour où vous aurez circulaire dépendances entre basé sur un modèle d'objets, ne soyez pas surpris si votre code d'organisation devient un peu plus "intéressant" que la plaine en-tête/organisation de la source...

^_^

22voto

Adrien Plisson Points 9750

en plus de toutes les autres réponses, je vais vous dire ce que vous NE les placez PAS dans un fichier d'en-tête:
using déclaration (la plus courante étant using namespace std;) ne devrait pas figurer dans un fichier d'en-tête parce qu'ils polluent l'espace de noms du fichier source dans lequel il est inclus.

11voto

Pavel Radzivilovsky Points 11613

Ce compile en rien (zéro binaire de l'empreinte) va dans le fichier d'en-tête.

Les Variables ne compile pas en rien, mais les déclarations de type n' (coz ils ne décrivent comment les variables de comportement).

les fonctions ne sont pas, mais les fonctions inline faire (ou macros), parce qu'ils produisent du code que là où il est appelé.

les modèles ne sont pas de code, ils ne sont qu'une recette pour la création de code. donc, ils vont aussi dans les h des fichiers.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X