Guide de style C ++ de Google. Partie 2

Partie 1. Introduction

Partie 2. Fichiers d'en-tĂȘte

...





Lors de l'Ă©criture de code, nous utilisons tous les rĂšgles de formatage du code. Parfois, des rĂšgles sont inventĂ©es, dans d'autres cas des guides de style prĂȘts Ă  l'emploi sont utilisĂ©s. Bien que tous les programmeurs C ++ lisent l'anglais plus facilement que le natif, il est plus agrĂ©able d'avoir un manuel dans ce dernier.

Cet article est une traduction d'une partie du guide de style C ++ de Google en russe.

Article original (fork sur github), traduction mise Ă  jour .



Fichiers d'en-tĂȘte



Il est souhaitable que chaque fichier source .cc ait un fichier d'en-tĂȘte .h correspondant . Il existe Ă©galement des exceptions connues Ă  cette rĂšgle, telles que les tests unitaires ou les petits fichiers .cc contenant uniquement la fonction main () .



L'utilisation correcte des fichiers d'en-tĂȘte peut avoir un impact Ă©norme sur la lisibilitĂ©, la taille et les performances de votre code.



Les rĂšgles suivantes vous aideront Ă  Ă©viter les problĂšmes frĂ©quents avec les fichiers d'en-tĂȘte.



Fichiers d'en-tĂȘte indĂ©pendants



Les fichiers d'en-tĂȘte doivent ĂȘtre autonomes (en termes de compilation) et avoir l'extension .h . Les autres fichiers (sans en-tĂȘte) destinĂ©s Ă  ĂȘtre inclus dans le code doivent avoir l'extension .inc et ĂȘtre associĂ©s au code d'inclusion.



Tous les fichiers d'en-tĂȘte doivent ĂȘtre autonomes. Les utilisateurs et les outils de dĂ©veloppement ne doivent pas dĂ©pendre de dĂ©pendances spĂ©ciales lors de l'utilisation du fichier d'en-tĂȘte. Le fichier d'en-tĂȘte doit ĂȘtre verrouillable et inclure tous les fichiers requis.



Il est prĂ©fĂ©rable de placer les dĂ©finitions des modĂšles et des fonctions en ligne dans le mĂȘme fichier avec leurs dĂ©clarations. Et ces dĂ©finitions doivent ĂȘtre incluses dans chaque .ccles utiliser, sinon il peut y avoir des erreurs de lien sur certaines configurations de construction. Si les dĂ©clarations et dĂ©finitions se trouvent dans des fichiers diffĂ©rents, l'un doit inclure l'autre. Ne sĂ©parez pas les dĂ©finitions dans des fichiers d'en-tĂȘte sĂ©parĂ©s ( -inl.h ). Auparavant, cette pratique Ă©tait trĂšs populaire, maintenant elle n'est plus souhaitable.



Par exception, si toutes les variantes d'arguments de modÚle disponibles sont créées à partir du modÚle, ou si le modÚle implémente des fonctionnalités utilisées par une seule classe, il est alors permis de définir le modÚle dans un (et un seul) fichier .cc , dans lequel ce modÚle est utilisé.



Il existe de rares situations oĂč le fichier d'en-tĂȘte n'est pas autonome. Cela peut se produire lorsqu'un fichier est inclus dans un emplacement non standard, par exemple au milieu d'un autre fichier. Dans ce cas, il se peut qu'il n'y ait pas de verrou de rĂ©activation et des fichiers d'en-tĂȘte supplĂ©mentaires peuvent ne pas ĂȘtre inclus non plus. Nommez ces fichiers avec l'extension .inc . Utilisez-les par paires et essayez de rĂ©pondre le plus possible aux exigences gĂ©nĂ©rales.



Redémarrer le verrouillage



Tous les fichiers d'en-tĂȘte doivent ĂȘtre #define protĂ©gĂ©s contre la rĂ©-inclusion . Le format de dĂ©finition de la macro doit ĂȘtre: <PROJET> _ <CHEMIN> _ <FICHIER> _H_ .



Pour garantir l'unicité, utilisez les composants de chemin de fichier complet dans l'arborescence du projet. Par exemple, le fichier foo / src / bar / baz.h dans le projet foo peut avoir le verrou suivant:



#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif  // FOO_BAR_BAZ_H_


Annonce préliminaire



Si possible, n'utilisez pas d'annonces anticipĂ©es. #Incluez plutĂŽt les fichiers d'en-tĂȘte requis.



Définition La

"pré-déclaration" est une déclaration d'une classe, d'une fonction, d'un modÚle sans définition correspondante.



Par



  • . #include ( ) .
  • . #include - .




  • , .
  • API, . , API: , , .
  • std:: .
  • , : #include. , #include ( ) :



          // b.h:
          struct B {};
          struct D : B {};
          // good_user.cc:
          #include "b.h"
          void f(B*);
          void f(void*);
          void test(D* x) { f(x); }  // calls f(B*)
          


    #include B D, test() f(void*).
  • , .
  • Une structure de code qui permet une dĂ©claration prĂ©liminaire (et, en outre, l'utilisation de pointeurs comme membres de classe) peut rendre le code confus et lent.


Verdict



  • Essayez d'Ă©viter de prĂ©-dĂ©clarer les entitĂ©s dĂ©clarĂ©es dans un autre projet.
  • Lorsque vous utilisez une fonction dĂ©clarĂ©e dans un fichier d'en-tĂȘte, #incluez toujours ce fichier.
  • Lors de l'utilisation d'un modĂšle de classe, il est prĂ©fĂ©rable de #inclure son fichier d'en-tĂȘte.


Consultez également les rÚgles d'inclusion dans les noms et l'ordre d'inclusion .



Fonctions en ligne



Définissez les fonctions en tant que fonctions en ligne uniquement lorsqu'elles sont petites, par exemple pas plus de 10 lignes.



Définition



Vous pouvez déclarer des fonctions comme étant en ligne et dire au compilateur de les inclure directement dans le code appelant, en plus de la maniÚre standard d'appeler une fonction.



Avantages L'



utilisation des fonctions en ligne peut générer un code plus efficace, en particulier lorsque les fonctions sont petites. Utilisez cette fonction pour les fonctions get / set, d'autres fonctions courtes et critiques pour les performances.



Contre



La surutilisation des fonctions en ligne peut ralentir le programme. En outre, les fonctions en ligne, en fonction de leur taille, peuvent augmenter ou diminuer la taille du code. S'il s'agit de petites fonctions, le code peut ĂȘtre rĂ©duit. Si la fonction est volumineuse, la taille du code peut augmenter considĂ©rablement. Notez que sur les processeurs modernes, le code allĂ©gĂ© s'exĂ©cute plus rapidement grĂące Ă  une meilleure utilisation du cache d'instructions.



Verdict



Une bonne rĂšgle de base est de ne pas rendre les fonctions insĂ©rables si elles dĂ©passent 10 lignes de code. Évitez de crĂ©er des destructeurs en ligne, car ils peuvent implicitement contenir beaucoup de code supplĂ©mentaire: des appels Ă  des destructeurs de variables et des classes de base!



Une autre bonne rĂšgle de base est que cela n'a gĂ©nĂ©ralement pas de sens pour les fonctions en ligne qui ont des boucles ou des instructions de commutation (sauf dans les cas dĂ©gĂ©nĂ©rĂ©s oĂč la boucle ou d'autres instructions ne sont jamais exĂ©cutĂ©es).



Il est important de comprendre qu'une fonction en ligne ne sera pas nĂ©cessairement compilĂ©e en code de cette façon. Par exemple, les fonctions gĂ©nĂ©ralement virtuelles et rĂ©cursives sont compilĂ©es avec un appel standard. En gĂ©nĂ©ral, les fonctions rĂ©cursives ne doivent pas ĂȘtre dĂ©clarĂ©es comme des fonctions en ligne. La principale raison de faire des fonctions virtuelles en ligne est de placer la dĂ©finition (code) dans la dĂ©finition de classe elle-mĂȘme (pour documenter le comportement ou la lisibilitĂ©) - souvent utilisĂ©e pour les fonctions get / set.



Noms et ordre d'inclusion



InsĂ©rez les fichiers d'en-tĂȘte dans l'ordre suivant: fichier appariĂ© (par exemple, foo.h - foo.cc), fichiers systĂšme C, bibliothĂšque standard C ++, autres bibliothĂšques, vos fichiers de projet.



Tous les en-tĂȘtes de projet doivent ĂȘtre relatifs au rĂ©pertoire source du projet sans utiliser d'alias UNIX tels que . (rĂ©pertoire courant) ou .. (rĂ©pertoire parent). Par exemple, google-awesome-project / src / base / logging.h doit ĂȘtre inclus comme suit :



#include "base/logging.h"


Autre exemple: si la fonction principale des fichiers dir / foo.cc et dir / foo_test.cc est d'implĂ©menter et de tester le code dĂ©clarĂ© dans dir2 / foo2.h , alors Ă©crivez les fichiers d'en-tĂȘte dans l'ordre suivant:



  1. dir2 / foo2.h .
  2. —
  3. C (: .h), <unistd.h>, <stdlib.h>.
  4. —
  5. C++ ( ), <algorithm>, <cstddef>.
  6. —
  7. .h .
  8. .h .


Séparez chaque groupe (non vide) de fichiers par une ligne vide.



Cet ordre des fichiers vous permet de dĂ©tecter des erreurs lorsque les fichiers d'en-tĂȘte requis (systĂšme, etc.) sont manquants dans le fichier d'en-tĂȘte appariĂ© ( dir2 / foo2.h ) et que l'assemblage des fichiers correspondants dir / foo.cc ou dir / foo_test.cc Ă©chouera. En consĂ©quence, l'erreur apparaĂźtra immĂ©diatement au dĂ©veloppeur travaillant avec ces fichiers (et non Ă  une autre Ă©quipe qui utilise uniquement une bibliothĂšque externe).



Habituellement, les fichiers associĂ©s dir / foo.cc et dir2 / foo2.h se trouvent dans le mĂȘme rĂ©pertoire (par exemple, base / basictypes_test.cc et base / basictypes.h ), bien que cela ne soit pas obligatoire.



Notez que les fichiers d'en-tĂȘte C tels que stddef.h sont gĂ©nĂ©ralement interchangeables avec les fichiers C ++ correspondants ( cstddef ). Toute variante peut ĂȘtre utilisĂ©e, mais il est prĂ©fĂ©rable de suivre le style du code existant.



Dans chaque section, les fichiers d'en-tĂȘte sont mieux classĂ©s par ordre alphabĂ©tique. Notez que le code prĂ©cĂ©demment Ă©crit peut ne pas suivre cette rĂšgle. Si possible (par exemple, lors de la correction d'un fichier), corrigez l'ordre des fichiers vers le bon.



Tous les fichiers d'en-tĂȘte qui dĂ©clarent les types souhaitĂ©s doivent ĂȘtre inclus, sauf lorsqu'ils ont Ă©tĂ© prĂ©cĂ©demment dĂ©clarĂ©s . Si votre code utilise des types de bar.h , ne comptez pas sur un autre fichier foo.h pour inclure bar.het vous pouvez vous limiter Ă  n'inclure que foo.h : include bar.h explicitement (Ă  moins qu'il ne soit explicitement indiquĂ© (peut-ĂȘtre dans la documentation) que foo.h vous donnera Ă©galement les types de bar.h ).



Par exemple, la liste des fichiers d'en - tĂȘte dans google-awesome-project / src / foo / internal / fooserver.cc pourrait ressembler Ă  ceci:



#include "foo/server/fooserver.h"
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/server/bar.h"


Exceptions



Il existe des cas oĂč vous devez inclure des fichiers d'en-tĂȘte en fonction des conditions du prĂ©processeur (par exemple, en fonction du systĂšme d'exploitation utilisĂ©). Essayez de garder cette inclusion aussi courte (localisĂ©e) que possible et placez-la aprĂšs les autres fichiers d'en-tĂȘte. Par exemple:



#include "foo/public/fooserver.h"
#include "base/port.h"  // For LANG_CXX11.
#ifdef LANG_CXX11
#include <initializer_list>
#endif  // LANG_CXX11


Remarques:



Image tirée de l' open source .



All Articles