Déclaration à terme vs inclure

17

Reduce the number of #include files in header files. It will reduce build times. Instead, put include files in source code files and use forward declarations in header files.

J'ai lu ça ici. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++CodingStyle.html .

Il indique donc si une classe (classe A) dans le fichier d'en-tête n'a pas besoin d'utiliser la définition réelle d'une classe (classe B). À ce moment, nous pouvons utiliser la déclaration directe au lieu d'inclure le fichier d'en-tête particulier (classe B).

Question: Si la classe (classe A) dans l'en-tête n'utilise pas la définition réelle d'une classe particulière (classe B), alors comment la déclaration directe contribue à réduire le temps de compilation?

Nayana Adassuriya
la source

Réponses:

11

Le compilateur ne se soucie pas si la classe A utilise la classe B. Il sait seulement que lorsque la classe A est compilée et qu'il n'a pas de déclaration préalable de classe B (déclaration directe ou autre), il panique et le marque comme une erreur.

Ce qui est important ici, c'est que le compilateur sait que vous n'avez pas essayé de compiler un programme après que votre chat a marché sur votre clavier et créé des lettres aléatoires qui peuvent ou non être interprétées comme une classe.

Lorsqu'il voit une inclusion, pour pouvoir utiliser toutes les informations qu'il contient, il doit ouvrir le fichier et l'analyser (qu'il ait ou non réellement besoin de le faire). Si ce fichier comprend alors d'autres fichiers, ceux-ci doivent également être ouverts et analysés, etc. Si cela peut être évité, il est généralement préférable d'utiliser une déclaration directe à la place.

Modifier : l'exception à cette règle étant les en-têtes précompilés. Dans ce cas, tous les en-têtes sont compilés et enregistrés pour de futures compilations. Si les en-têtes ne changent pas, le compilateur peut utiliser intelligemment les en-têtes précompilés des compilations précédentes et ainsi réduire les temps de compilation, mais cela ne fonctionne bien que si vous n'avez pas souvent besoin de changer les en-têtes.

Neil
la source
Merci pour l'explication. Alors ok comme exemple , vous pensez qu'il ya trois fichiers d' en- tête vehicle.h, bus.h, toybus.h. vehicle.hinclure par bus.het bus.hinclure par toybus.h. donc si je change bus.h. le compilateur s'ouvre-t-il et analyse- vehicle.ht-il à nouveau? le compile-t-il à nouveau?
Nayana Adassuriya
1
@NayanaAdassuriya Oui, il est inclus et analysé à chaque fois, c'est pourquoi vous voyez #pragma onceou #ifndef __VEHICLE_H_tapez des déclarations dans les fichiers d'en-tête afin d'empêcher que ces fichiers soient inclus plusieurs fois (ou utilisés plusieurs fois au moins dans le cas d'ifndef).
Neil
4

car alors A.hpp n'a pas besoin de #inclure B.hpp

donc A.hpp devient

class B;//or however forward decl works for classes

class A
{
    B* bInstance_;
//...
}

donc quand A.hpp est inclus alors B.hpp n'est pas implicitement inclus et tous les fichiers qui ne dépendent que de A.hpp n'ont pas besoin d'être recompilés à chaque fois que b.hpp change

monstre à cliquet
la source
mais dans le fichier source (A.cpp). besoin d'inclure le fichier d'en-tête réel (Bh). Donc, chaque fois qu'il a besoin de compiler. Enfin, dans les deux sens, Bh doit être recompilé avec les modifications. Tout différent?
Nayana Adassuriya
@NayanaAdassuriya non car A utilise uniquement un pointeur vers B et les modifications apportées à B n'affecteront pas A.hpp (ou les fichiers qui l'incluent)
ratchet freak
@NayanaAdassuriya: Oui, A.cpp devra recompiler (s'il utilise la définition de B à l'intérieur des corps des méthodes de A, mais c'est généralement le cas), mais C.cpp, qui utilise A, mais pas B directement, ne le fera pas.
Jan Hudec
3

N'oubliez pas que le préprocesseur C / C ++ est une étape de traitement distincte, purement textuelle. La #includedirective extrait le contenu de l'en-tête inclus et le compilateur doit l'analyser. De plus, la compilation de chacun .cppest complètement séparée, donc le fait que le compilateur vient d'être analysé B.hlors de la compilation B.cppne l'aide pas du tout quand il en a besoin à nouveau lors de la compilation A.cpp. Et encore lors de la compilation C.cpp. Et D.cpp. Etc. Et chacun de ces fichiers doit être recompilé si l'un des fichiers qu'il contient a changé.

Disons que la classe Autilise la classe Bet les classes Cet Dutilise la classe A, mais n'a pas besoin de manipuler B. Si la classe Apeut être déclarée avec juste une déclaration directe de B, alors elle B.hest compilée deux fois: lors de la compilation B.cppet A.cpp(car elle Best toujours nécessaire dans Ales méthodes de).

Mais quand A.hcomprend B.h, il est compilé quatre fois lors de la compilation- B.cpp, A.cpp, C.cppet D.cppcomme plus tard , deux sont maintenant indirectement B.haussi.

De plus, lorsque l'en-tête est inclus plusieurs fois, le préprocesseur doit toujours le lire à chaque fois. Il sautera le traitement de son contenu à cause des protections #ifdef, mais il le lit toujours et doit rechercher la fin de la protection, ce qui signifie qu'il doit analyser toutes les directives du préprocesseur à l'intérieur.

(Comme mentionné dans l'autre réponse, les en-têtes précompilés tentent de contourner ce problème, mais ils sont leur propre boîte de vers; en gros, vous pouvez raisonnablement les utiliser pour les en-têtes du système et uniquement si vous n'en utilisez pas trop, mais pas pour en-têtes de votre projet)

Jan Hudec
la source
+1, les en-têtes ne deviennent un problème sérieux que lorsque vous avez un nombre assez important de classes, pas lorsque vous n'avez que deux classes A et B. Tous les autres messages semblent manquer ce point central.
Doc Brown
2

Une déclaration directe est beaucoup plus rapide à analyser qu'un fichier d'en-tête entier qui lui-même peut inclure encore plus de fichiers d'en-tête.

De plus, si vous modifiez quelque chose dans le fichier d'en-tête pour la classe B, tout ce qui comprend cet en-tête devra être recompilé. Avec une déclaration directe, cela ne peut être que le fichier source dans lequel l'implémentation de A réside. Mais si l'en-tête de A incluait réellement l'en-tête de B, tout y compris a.hppsera recompilé également, même s'il n'utilise rien de B.

Benjamin Kloster
la source