11
votes

Devrait-il répéter "#incluant" et "utiliser" des déclarations d'en-tête et de mise en œuvre (C ++)?

Je suis assez nouveau à C ++, mais ma compréhension est qu'une déclaration de #include videra essentiellement du contenu du fichier #Inclus dans l'emplacement de cette déclaration. Cela signifie que si j'ai un certain nombre d'instructions "#include" et "en utilisant" dans mon fichier d'en-tête, mon fichier de mise en œuvre peut simplement #include le fichier d'en-tête et que le compilateur ne vous dérange pas si je ne répète pas les autres déclarations. .

Qu'en est-il des gens cependant? P>

Ma principale préoccupation est que si je ne répète pas le "#include", "Utiliser", ainsi que "Typedef" (maintenant que j'y pense) déclarations, il faut ces informations du dossier dans lesquelles il est utilisé, ce qui pourrait conduire à une confusion. P>

Je travaille juste sur de petits projets pour le moment où cela ne causera pas vraiment de problèmes, mais je peut imaginer que dans des projets plus importants avec plus de personnes qui travaillent sur eux, cela pourrait devenir un problème important. p>

Un exemple suit: P>

STRY> Mise à jour: strong> Mes prototypes de fonction pour « Unité » ont chaîne, ostream et StringSet parmi leurs types de retour et les paramètres - Je ne suis pas compris tout dans mon dossier d'en-tête qui est utilisé uniquement dans le fichier de mise en œuvre p>

//Unit.h

#include <string>
#include <ostream>
#include "StringSet.h"

using std::string;
using std::ostream;

class Unit {

public:
    //public members with string, ostream and StringSet
    //in their return values/parameter lists
private:
    //private members
    //unrelated side-question: should private members
    //even be included in the header file?
} ;


//Unit.cpp

#include "Unit.h"

//The following are all redundant from a compiler perspective:
#include <string>
#include <ostream>
#include "StringSet.h"

using std::string;
using std::ostream;

//implementation goes here


4 commentaires

Une question non liée que je ne voulais pas encombrer la question principale avec est, puisque chacun semble dire que les déclarations «en utilisant» globales sont une mauvaise idée, comment puis-je avoir juste une classe "en utilisant STD :: String" ou quelque chose? Déménager cette affirmation dans la déclaration de classe provoque une erreur de compilateur car elle n'ame pas les espaces de noms dans une déclaration "Utilisation" à cet endroit.


Quel est le problème avec explicitement dire std :: chaîne ?


Jusqu'à ce qu'il ne commence à causer des lignes à casser quand ils ne le feraient pas, ce qui réduit la lisibilité. Éloignons de STD :: pendant un moment et disant que je voulais utiliser ThelongestNamesPecenameIntheknowniversee :: String - Juste pour éviter le commun "Vous devriez toujours simplement taper STD :: String 'Mantra (puisque je l'ai entendu beaucoup de fois déjà, et bien qu'un point valide ne aide pas vraiment à la question à portée de main).


Je pense que la manière C ++ n'est pas d'utiliser des noms d'espace de nom long pour cette raison :) J'utilise simplement des noms entièrement qualifiés dans les en-têtes et utilisez à l'aide de directives dans les fichiers du CPP, je n'ai pas trouvé de mieux manière. Je garde la plupart des définitions de la fonction dans les fichiers du CPP et qui aide à la quantité de noms entièrement qualifiés et le nombre d'inclut dans les en-têtes.


5 Réponses :


9
votes

A à l'aide de la directive ( à l'aide de NAMESPACE STD; ) ne doit pas résider dans une en-tête sauf si elle est contenue dans une fonction. C'est une mauvaise pratique. Il est peu probable que chaque utilisateur de votre en-tête souhaite une recherche non qualifiée pour tout dans un espace de noms donné; L'inclusion d'en-têtes non liées peut conduire à des échecs d'ambiguïté et de compilation inattendus. Personnellement, j'évite les à l'aide de la directive à l'intérieur des fonctions pour le même raisonnement, mais cela est généralement considéré comme moins nocif.

A type alias (soit via Typedef stdd :: chaîne de chaîne; ou à l'aide de string = std :: string; ) doit être utilisé avec précaution. Les définitions de type ont un sens, vous ne devez donc jamais la redéclairez. Par exemple, il s'agit d'une erreur: xxx

en raison de types contradictoires.

A utiliser-déclaration ( Utilisation de std :: string; ou à l'aide de std :: memcpy; ) rend un symbole accessible pour Nom non qualifié Recherche . Il est extrêmement utile lorsque vous obtenez Recherche dépendante de l'argument correct, ce qui ne fait généralement pas 'T Peu importe si vous écrivez une bibliothèque. Le conseil est différent selon si vous apportez un type ou une fonction. Pensez à utiliser-déclaration s avec des types de la même manière que l'alias type : il n'a aucun sens d'avoir plusieurs définitions sous le même nom. Avec des fonctions, tout ce que vous faites réellement est de prolonger la résolution de la surcharge pour inclure quelques autres choses (bien que cela ne soit généralement pas nécessaire). xxx

pour répéter #include < / Code>, vous devez considérer si vous devez réellement inclure le fichier dans l'en-tête en premier lieu. Peut-être un déclaration avant convient à vos besoins.


5 commentaires

J'ai mis à jour la question à clarifier: j'évite d'avoir des #includes dans mon fichier d'en-tête, à moins que je n'en ai plus besoin dans le fichier d'en-tête. Je ne sais pas si cet exemple de déclaration en avant s'applique si je fais une utilisation de STD :: String ou une autre classe que je ne définissais pas - pouvez-vous clarifier comment cela fonctionnerait si cela fonctionnerait-il?


Le problème avec std :: string est qu'il est vraiment juste juste typedef basic_string chaîne ... Les états standard: non défini pour un programme C ++ Pour ajouter des déclarations ou des définitions à Namespace Std ou espaces de noms dans les espaces de noms STD, sauf indication contraire. SO ... Vous ne pouvez pas le déclarer. En ce qui concerne la question vraiment_long_namespace_name , c'est là que les gens utilisent des types de membres. std :: allocator est un bon exemple de ceci: Cplusplus .com / référence / std / mémoire / allocator


En C ++ 11 Utiliser peut également être utilisé pour les déclarations d'alias de type, qui, selon la norme, est équivalente à une TYPEDEF. Et puisque TapeDeF est ok dans les en-têtes, la sentance "Vous ne devez jamais avoir une déclaration en en-tête dans un en-tête, à moins que cela ne contienne dans une fonction." ne semble plus vrai.


@Zitrax: D'accord. Je pense que les conseils C ++ 11 (et au-delà) seraient plus spécifiques: "Vous ne devriez jamais avoir un à l'aide de l'espace de noms directive ..." Après avoir lu mon conseil à nouveau, il semble un peu stupide / égaré . Pourquoi ai-je pensé qu'une déclaration d'utilisation est différente d'un Typedef ?


@Zitrax: À mi-parcours de l'édition, j'ai réalisé la majeure partie de cela est toujours applicable à Pre-C ++ 11, donc je l'ai réécrit pour travailler pour tout le monde.



0
votes

Gardez le fichier d'en-tête au minimum. Cela signifie que la petite inclusion est que possible. Le fichier .CPP inclura généralement l'en-tête correspondant ainsi que tout autre en-têtes nécessaire à la mise en œuvre.


0 commentaires

0
votes

Comme Travis dit, vous ne devriez pas avoir en utilisant des instructions dans un fichier d'en-tête, car cela signifie qu'elles seront incluses dans toutes les unités de traduction qui incluent ce fichier d'en-tête, ce qui peut provoquer des problèmes déroutants.

Si je n'ai besoin que de la fonctionnalité d'un fichier d'en-tête dans un fichier CPP, je n'inclut que dans ce fichier CPP. C'est une bonne pratique pour les projets plus importants car cela signifie moins de travail pour le compilateur. En outre, dans la mesure du possible, j'utilise des déclarations avant dans les en-têtes au lieu d'inclure (et encore, incluez les en-têtes du fichier CPP).


0 commentaires

0
votes

C'est considéré comme une mauvaise forme d'avoir un à l'aide de instruction dans un fichier d'en-tête, sauf si vous avez intentionnellement dupliquer un symbole dans un espace de nom différent. Il est correct d'utiliser dans un fichier CPP.

Chaque Typedef devrait exister une seule fois dans votre codeBase. Cela devrait être dans un fichier d'en-tête s'il doit être utilisé dans plusieurs fichiers CPP / H. Les dupliquer vous causera beaucoup de chagrin.

Un fichier d'en-tête doit avoir tous les énoncés #include dont il a besoin et pas d'autres. Si seulement les pointeurs d'une classe sont mentionnés, utilisez une déclaration avant plutôt que d'inclure l'en-tête. Toute autre inclut qui n'est requise que dans le fichier du CPP devrait y aller. La répétition de l'inclinaison de l'en-tête est correcte, mais pas requise. C'est juste un choix de style.


0 commentaires

5
votes
  • comprennent uniquement dans un en-tête / source ce que vous avez vraiment besoin (si les déclarations sont disponibles en avant, et assez, puis vers l'avant au lieu d'inclure déclarer)
  • Ne pas utiliser à l'aide (sauf fonction à l'intérieur des étendues) ... Ajout en utilisant dans l'en-tête Déclaration des en-têtes pollue les espaces de noms de toutes les sources, y compris l'en-tête.
  • Vous devez vous assurer que chaque fichier (en-tête de la source) comprend tout ce qu'il faut, et rien de plus.

    Vous n'avez pas besoin de prendre soin si certains sont redondants comprend. gardes d'en-tête et les optimisations précompilateur sont là pour gérer que pour vous.

    Vous devriez être en mesure de manipuler chaque fichier dans l'isolement.

    Par exemple, supposons que vous utilisez le :: string std dans l'en-tête et dans la source, mais comme une « optimisation », vous n'inclus la chaîne dans l'en-tête ... Si vous découvrirez plus tard, vous n'avez plus besoin de la chaîne dans l'en-tête, et que vous voulez le supprimer (nettoyage de code, et tout ...), vous devrez modifier la source pour inclure la chaîne. Maintenant, imaginez que vous avez dix sources, y compris l'en-tête ...

    Maintenant, bien sûr, vous pouvez avoir des exceptions à cette règle (par exemple, les en-têtes précompilés, ou même en-têtes malheur seul but est de faire plusieurs comprend à titre de courtoisie), mais par défaut, vous devriez avoir la tête autarcique et fichiers source (fichiers qui comprennent tout ce qu'ils utilisent, ni plus ni moins).


0 commentaires