45 votes

Avantages et Inconvénients de mettre tout le code dans les fichiers d'en-Tête dans le C++?

Vous pouvez la structure d'un programme C++, de sorte que (presque) tout le code réside dans les fichiers d'en-Tête. Essentiellement, il ressemble à un C# ou Java. Cependant, vous avez besoin d'au moins un .cpp le fichier à tirer dans tous les fichiers d'en-tête lors de la compilation. Maintenant, je sais que certaines personnes seraient absolument horreur de cette idée. Mais je n'ai pas trouvé de convaincre les inconvénients de cette situation. Je peux énumérer quelques avantages:

[1] plus Rapide temps de compilation. Tous les fichiers d'en-tête seulement obtenir analysée une fois, parce qu'il n'y en a qu'une .fichier cpp. Aussi, un fichier d'en-tête ne peut pas être inclus plus d'une fois, sinon vous obtiendrez un build pause. Il y a d'autres moyens d'atteindre plus rapidement compile lorsque vous utilisez l'autre, mais ce n'est si simple.

[2] Il évite les dépendances circulaires, pour le rendre absolument clair. Si ClassA en ClassA.h a une dépendance circulaire sur ClassB en ClassB.h, je dois mettre une référence vers l'avant et il colle. (Notez que c'est à la différence de C# & Java où le compilateur résout automatiquement les dépendances circulaires. Cela encourage les mauvaises pratiques de codage de l'OMI). Encore une fois, vous pouvez éviter des dépendances circulaires si votre code a été en .cpp fichiers, mais dans un monde réel projet, .cpp fichiers ont tendance à inclure des en-têtes jusqu'à ce que vous ne pouvez pas comprendre qui dépend pour qui.

Vos pensées?

33voto

paercebal Points 38526

La raison [1] plus Rapide temps de compilation

Pas dans mes projets: les fichiers source (RPC) ne comprennent que les en-têtes (HPP) dont ils ont besoin. Donc quand j'ai besoin de recompiler un seul RPC en raison d'un changement minuscule, j'ai dix fois le même nombre de fichiers qui ne sont pas recompilés.

Vous devriez peut-être briser votre projet plus logique sources/en-têtes: Une modification dans la classe A de la mise en œuvre ne devrait PAS avoir besoin de la recompilation des implémentations de classe B, C, D, E, etc..

La raison[2]. Il évite les dépendances circulaires

Les dépendances circulaires dans le code?

Désolé, mais je n'ai pas encore eu ce genre de problème à un problème réel: disons que A dépend de B, et B dépend de A:

struct A
{
   B * b ;
   void doSomethingWithB() ;
} ;

struct B
{
   A * a ;
   void doSomethingWithA() ;
} ;

void A::doSomethingWithB() { /* etc. */ }
void B::doSomethingWithA() { /* etc. */ }

Une bonne façon de résoudre le problème serait de briser cette source dans au moins une source de/en-tête de chaque classe (de manière similaire à Java, mais avec une seule source et un seul en-tête de chaque classe):

// A.hpp

struct B ;

struct A
{
   B * b ;
   void doSomethingWithB() ;
} ;

.

// B.hpp

struct A ;

struct B
{
   A * a ;
   void doSomethingWithA() ;
} ;

.

// A.cpp
#include "A.hpp"
#include "B.hpp"

void A::doSomethingWithB() { /* etc. */ }

.

// B.cpp
#include "B.hpp"
#include "A.hpp"

void B::doSomethingWithA() { /* etc. */ }

Ainsi, pas de problème de dépendance, et encore rapide temps de compilation.

Ai-je raté quelque chose?

Lorsque l'on travaille sur le "monde réel" des projets

dans un monde réel projet, les fichiers cpp ont tendance à inclure des en-têtes jusqu'à ce que vous ne pouvez pas comprendre qui dépend pour qui

Bien sûr. Mais alors, si vous avez le temps de réorganiser les fichiers pour construire votre "un RPC" solution, alors vous avez le temps de nettoyer les têtes. Mes règles pour les en-têtes sont:

  • briser en-tête pour les rendre aussi modulaire que possible
  • Ne jamais inclure les en-têtes que vous n'avez pas besoin
  • Si vous avez besoin d'un symbole, de l'avant-déclarer
  • seulement si le ci-dessus a échoué, inclure l'en-tête

De toute façon, tous les en-têtes doivent être auto-suffisante, qui signifie:

  • Un en-tête comprennent tous besoin des en-têtes (et nécessaire uniquement les en-têtes - voir ci-dessus)
  • un vide fichier CPP dont un en-tête doit compiler sans avoir besoin d'inclure quoi que ce soit d'autre

Cela permettra d'éliminer la commande de problèmes et les dépendances circulaires.

Est temps de compilation d'un problème? Alors...

Devrait moment de la compilation être vraiment un problème, je voudrais envisager:

  • En utilisant les en-têtes précompilés (ce qui est assez utile pour les STL et BOOST)
  • Diminuer le couplage à travers le PImpl idiome, comme expliqué dans http://en.wikipedia.org/wiki/Opaque_pointer
  • L'utilisation partagée en réseau compilation

Conclusion

Ce que vous faites est de ne pas tout mettre dans les en-têtes.

Vous êtes fondamentalement, y compris tous vos fichiers en une seule et unique source final.

Peut-être que vous êtes en train de gagner dans des conditions de pleine-projet de compilation.

Mais lors de la compilation pour un petit changement, vous aurez toujours perdre.

Lors du codage, je sais que je compile souvent de petits changements (si ce n'est que le compilateur valider mon code), puis un dernier temps, faire un changement de projet.

Je voudrais perdre beaucoup de temps si mon projet a été organisée à votre façon.

25voto

Milan Babuškov Points 20423

Je suis en désaccord avec le point 1.

Oui, il n'y en a qu'une .le rpc et le construit du temps à partir de zéro est plus rapide. Mais, il est rare de construire à partir de zéro. Vous faites de petits changements, et il aurait besoin de recompiler l'ensemble du projet à chaque fois.

Je préfère le faire dans l'autre sens:

  • garder les déclarations communes dans .h fichiers
  • garder définition pour les classes qui ne sont utilisés que dans un seul endroit .fichiers cpp

Ainsi, certains de mes .fichiers cpp commencer à regarder comme le Java ou le C# code ;)

Mais, "garder les choses dans .h' approche est bonne lors de la conception du système, parce que du point 2. que vous avez fait. J'ai l'habitude de le faire pendant que je suis en train de construire la hiérarchie de classe et, plus tard, lorsque le code de l'architecture devient stable, j'ai passer le code de .fichiers cpp.

16voto

Vincent Robert Points 16530

Vous avez raison de dire que votre solution fonctionne. Il peut-être même pas les inconvénients pour votre projet actuel et de l'environnement de développement.

Mais...

Comme d'autres ont dit, mettre votre code dans les fichiers d'en-tête des forces d'une compilation complète chaque fois que vous changer une ligne de code. Cela peut ne pas être un problème, mais encore votre projet peut devenir suffisamment gros pour le point de temps de compilation sera un problème.

Un autre problème est que lors du partage de code. Alors que vous pourriez ne pas être directement concerné pourtant, il est important de garder un maximum de code caché provenant d'un utilisateur potentiel de votre code. En mettant votre code dans le fichier d'en-tête, n'importe quel programmeur à l'aide de votre code doit regarder l'ensemble du code, alors que les intéressés à la façon de l'utiliser. Mettre votre code dans le fichier cpp permet de ne livrer un composant binaire (statique ou dynamique de la bibliothèque) et de son interface que les fichiers d'en-tête, qui peut être plus simple dans certains environnement.

C'est un problème si vous voulez être en mesure de transformer votre code actuel dans une bibliothèque dynamique. Parce que vous n'avez pas une bonne déclaration d'interface découplé du code actuel, vous ne serez pas en mesure de fournir un compilé dynamique de la bibliothèque et son utilisation de l'interface lisible fichiers d'en-tête.

Vous ne pouvez pas avoir ces problèmes encore, c'est pourquoi je disais que votre solution peut être ok dans votre environnement actuel. Mais il est toujours mieux d'être préparé à tout changement et à certaines de ces questions devraient être abordées.

PS: a Propos de C# ou Java, vous devez garder à l'esprit que ces langues ne sont pas à faire ce que vous dites. Ils sont en fait la compilation des fichiers de manière indépendante (comme les fichiers cpp) et les magasins de l'interface à l'échelle mondiale pour chaque fichier. Ces interfaces (et toutes les autres interfaces) sont ensuite utilisés pour lier l'ensemble du projet, c'est pourquoi ils sont capables de gérer les références circulaires. Parce que le C++ ne fait qu'une compilation de passer par fichier, il n'est pas en mesure à l'échelle mondiale des interfaces de magasin. C'est pourquoi vous devez les écrire explicitement dans les fichiers d'en-tête.

11voto

nlaq Points 11379

Vous ne comprenez pas comment le langage a été conçu pour être utilisé. .fichiers cpp sont vraiment (ou devrait l'être, à l'exception de inline et le modèle de code) les modules de code exécutable que vous avez dans votre système. .fichiers cpp sont compilées dans des fichiers objets sont ensuite liés ensemble. .h fichiers existent uniquement pour la déclaration anticipée de le code mis en œuvre .fichiers cpp.

Cela accélère le temps de compilation et plus petit exécutable. Aussi, il semble beaucoup plus propre parce que vous pouvez obtenir un aperçu rapide de votre classe, en regardant son .h déclaration.

Comme pour inline et le modèle de code - parce que ces deux sont utilisés pour générer du code par le compilateur et non pas l'éditeur de liens - ils doivent toujours être disponibles pour le compilateur par .fichier cpp. Donc la seule solution est de l'inclure dans votre .h fichier.

Cependant, j'ai développé une solution où j'ai ma déclaration de classe dans un .h de fichier, tous les modèles et le code en ligne dans une .inl fichier et la mise en œuvre de la non modèle/code en ligne dans mon .fichier cpp. L' .inl fichier est inclus dans le fond de mon .h fichier. Cela permet de maintenir les choses propre et cohérente.

9voto

Chris Jester-Young Points 102876

L'inconvénient évident pour moi, c'est que vous avez toujours à construire tout le code à la fois. Avec .cpp fichiers, vous pouvez avoir compilation séparée, de sorte que vous êtes seulement à la reconstruction de bits qui ont vraiment changé.

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