Guide de style C ++ de Google. Partie 4

Partie 1. Introduction

...

Partie 4. Classes

...





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 .





Des classes





Les classes sont le bloc de construction principal en C ++. Et, bien sûr, ils sont souvent utilisés. Cette section décrit les rÚgles de base et les interdictions à suivre lors de l'utilisation des classes.



Code dans le constructeur





N'appelez pas de mĂ©thodes virtuelles dans le constructeur. Évitez les initialisations qui peuvent Ă©chouer (et il n'y a aucun moyen de signaler une erreur. Remarque: notez que Google n'aime pas les exceptions).



DĂ©finition



En gĂ©nĂ©ral, toute initialisation peut ĂȘtre effectuĂ©e dans un constructeur (c'est-Ă -dire que toute initialisation peut ĂȘtre effectuĂ©e dans un constructeur).



Par



  • Pas besoin de s'inquiĂ©ter de la classe non initialisĂ©e.
  • Les objets qui sont entiĂšrement initialisĂ©s dans le constructeur peuvent ĂȘtre const et sont Ă©galement plus faciles Ă  utiliser dans des conteneurs et des algorithmes standard.




Contre



  • Si des fonctions virtuelles sont appelĂ©es dans le constructeur, les implĂ©mentations de la classe dĂ©rivĂ©e ne sont pas appelĂ©es. MĂȘme si la classe n'a plus de descendants, cela pourrait devenir un problĂšme Ă  l'avenir.
  • ( ) ( ).
  • , ( — ) . : bool IsValid(). .
  • . , , .




Les



constructeurs de verdict ne doivent pas appeler de fonctions virtuelles. Dans certains cas (si autorisĂ©), les erreurs de conception peuvent ĂȘtre traitĂ©es par l'arrĂȘt du programme. Sinon, considĂ©rez le modĂšle de mĂ©thode d'usine ou utilisez Init () (plus de dĂ©tails ici: TotW # 42 ). Utilisez Init () uniquement si l'objet a des indicateurs d'Ă©tat qui permettent d'appeler certaines fonctions publiques (car il est difficile de travailler entiĂšrement avec un objet partiellement construit).



Conversions implicites





Ne déclarez pas de conversions implicites. Utilisez le mot clé explicite pour les opérateurs de conversion de type et les constructeurs à argument unique.



DĂ©finition



Les conversions implicites permettent Ă  un objet d'un type source d'ĂȘtre utilisĂ© lĂ  oĂč un autre type (type de destination) est attendu, par exemple en passant un argument int Ă  une fonction qui attend un double .



En plus des conversions implicites spécifiées par le langage de programmation, vous pouvez également définir vos propres conversions personnalisées en ajoutant les membres appropriés à la déclaration de classe (source et destination). La conversion implicite cÎté source est déclarée comme type opérateur + récepteur (par exemple, opérateur bool () ). La conversion implicite cÎté récepteur est implémentée par un constructeur qui prend le type source comme seul argument (en plus des arguments par défaut).



Le mot-clĂ© explicite peut ĂȘtre appliquĂ© Ă  un constructeur ou Ă  un opĂ©rateur de conversion pour indiquer explicitement qu'une fonction ne peut ĂȘtre utilisĂ©e qu'en cas de correspondance de type explicite (par exemple, aprĂšs une conversion). Cela s'applique non seulement aux conversions implicites, mais Ă©galement aux listes d'initialisation en C ++ 11:



class Foo {
  explicit Foo(int x, double y);
  ...
};
void Func(Foo f);

      
      







Func({42, 3.14});  // 

      
      







Cet exemple de code n'est techniquement pas une conversion implicite, mais le langage le traite comme s'il Ă©tait censĂ© ĂȘtre explicite .



Par



  • , .
  • , string_view std::string const char*.
  • .








  • , ( ).
  • , : , .
  • , .
  • explicit : , .
  • , . — , .
  • , , , .








Les opĂ©rateurs de conversion de verdict et les constructeurs Ă  argument unique doivent ĂȘtre dĂ©clarĂ©s avec le mot clĂ© explicite . Il y a aussi une exception: les constructeurs de copie et de dĂ©placement peuvent ĂȘtre dĂ©clarĂ©s sans explicite , car ils n'effectuent pas de conversion de type. En outre, des conversions implicites peuvent ĂȘtre nĂ©cessaires dans le cas de classes wrapper pour d'autres types (dans ce cas, assurez-vous de demander Ă  votre gestion en amont l'autorisation d'ignorer cette rĂšgle importante).



Les constructeurs qui ne peuvent pas ĂȘtre appelĂ©s avec un seul argument peuvent ĂȘtre dĂ©clarĂ©s sans explicite . Constructeurs acceptant un seul std :: initializer_listdoit Ă©galement ĂȘtre dĂ©clarĂ© sans explicite pour prendre en charge l'initialisation de la copie (par exemple, MyType m = {1, 2}; ).



Types copiables et déplaçables





L'interface publique de la classe doit indiquer explicitement la possibilité de copier et / ou déplacer, ou vice versa, tout interdire. Prend en charge la copie et / ou le déplacement uniquement si ces opérations ont un sens pour votre type.



DĂ©finition Un



type rĂ©adressable est un type qui peut ĂȘtre initialisĂ© ou attribuĂ© Ă  partir de valeurs temporaires.



Type copiable - peut ĂȘtre initialisĂ© ou attribuĂ© Ă  partir d'un autre objet du mĂȘme type (c'est-Ă -dire identique Ă  celui qui peut ĂȘtre dĂ©placĂ©), Ă  condition que l'objet d'origine reste inchangĂ©. Par exemple , std :: unique_ptr <int> peut ĂȘtre dĂ©placĂ©, mais pas le type Ă  copier (car la valeur de l'objet std :: unique_ptr <int> d'origine doit changer lorsqu'elle est affectĂ©e Ă  la cible). intet std :: string sont des exemples de types relocalisables qui peuvent Ă©galement ĂȘtre copiĂ©s: pour int, les opĂ©rations de dĂ©placement et de copie sont les mĂȘmes, pour std :: string l' opĂ©ration de dĂ©placement nĂ©cessite moins de ressources que copy.



Pour les types définis par l'utilisateur, la copie est spécifiée par le constructeur de copie et l'opérateur de copie. Le mouvement est spécifié soit par le constructeur de déplacement avec l'opérateur de déplacement, soit (s'il n'est pas présent) par les fonctions de copie correspondantes.



Les constructeurs de copie et de dĂ©placement peuvent ĂȘtre appelĂ©s implicitement par le compilateur, par exemple, lors du passage d'objets par valeur.



Par



Les objets de types copiables et dĂ©plaçables peuvent ĂȘtre passĂ©s et reçus par valeur, ce qui rend l'API plus simple, plus sĂ»re et plus polyvalente. Dans ce cas, il n'y a aucun problĂšme avec la propriĂ©tĂ© de l'objet, son cycle de vie, le changement de valeur, etc., et il n'est pas non plus nĂ©cessaire de les spĂ©cifier dans le "contrat" ​​(tout cela est diffĂ©rent du passage d'objets par pointeur ou rĂ©fĂ©rence). La communication paresseuse entre le client et l'implĂ©mentation est Ă©galement empĂȘchĂ©e, ce qui rend le code beaucoup plus facile Ă  comprendre, Ă  maintenir et Ă  optimiser pour le compilateur. Ces objets peuvent ĂȘtre utilisĂ©s comme arguments pour d'autres classes qui nĂ©cessitent de passer par valeur (par exemple, la plupart des conteneurs), et en gĂ©nĂ©ral, ils sont plus flexibles (par exemple, lorsqu'ils sont utilisĂ©s dans des modĂšles de conception).



Les constructeurs de copie / dĂ©placement et les opĂ©rateurs d'assignation associĂ©s sont gĂ©nĂ©ralement plus faciles Ă  dĂ©finir que des alternatives telles que Clone () , CopyFrom () ou Swap () car le compilateur peut gĂ©nĂ©rer les fonctions requises (implicitement ou avec = default ). Elles (fonctions) sont faciles Ă  dĂ©clarer et vous pouvez ĂȘtre sĂ»r que tous les membres de la classe seront copiĂ©s. Les constructeurs (copier et dĂ©placer) sont gĂ©nĂ©ralement plus efficaces car ne nĂ©cessitent pas d'allocation de mĂ©moire, une initialisation sĂ©parĂ©e, des affectations supplĂ©mentaires, sont bien optimisĂ©es (voir Ă©lision de copie ).



Les opérateurs de déplacement vous permettent de manipuler efficacement (et implicitement) les ressources rvalue des objets. Cela facilite parfois le codage.



Contre



Certains types ne doivent pas nĂ©cessairement ĂȘtre copiables et la prise en charge des opĂ©rations de copie peut ĂȘtre contre-intuitive ou entraĂźner un fonctionnement incorrect. Les types de singletones ( Registerer ), les objets Ă  nettoyer (par exemple, en sortie de champ) ( Cleanup ) ou contenant des donnĂ©es uniques ( Mutex ) sont, dans leur sens, non copiables. En outre, les opĂ©rations de copie pour les classes de base qui ont des descendants peuvent entraĂźner un dĂ©coupage d'objets.... Les opĂ©rations de copie par dĂ©faut (ou mal Ă©crites) peuvent entraĂźner des erreurs difficiles Ă  dĂ©tecter.



Les constructeurs de copie sont appelĂ©s implicitement et cela est facile Ă  ignorer (en particulier pour les programmeurs qui Ă©crivaient auparavant dans des langages oĂč les objets sont passĂ©s par rĂ©fĂ©rence). Vous pouvez Ă©galement rĂ©duire les performances en effectuant des copies inutiles.



Verdict L'



interface publique de chaque classe doit indiquer explicitement les opérations de copie et / ou de déplacement qu'elle prend en charge. Cela se fait généralement dans la section publique sous la forme de déclarations explicites des fonctions requises ou en les déclarant comme delete.



En particulier, la classe copiée doit déclarer explicitement les opérations de copie; seule une classe réadressable doit déclarer explicitement les opérations de déplacement; une classe non copiable / non déplaçable doit explicitement refuser ( = supprimer ) les opérations de copie. La déclaration ou la suppression explicite des quatre fonctions de copie et de déplacement est également autorisée, bien que non obligatoire. Si vous implémentez l'opérateur de copie et / ou de déplacement, vous devez également créer le constructeur correspondant.



class Copyable {
 public:
  Copyable(const Copyable& other) = default;
  Copyable& operator=(const Copyable& other) = default;
  //       (..  )
};
class MoveOnly {
 public:
  MoveOnly(MoveOnly&& other);
  MoveOnly& operator=(MoveOnly&& other);
  //     .  ( )    :
  MoveOnly(const MoveOnly&) = delete;
  MoveOnly& operator=(const MoveOnly&) = delete;
};
class NotCopyableOrMovable {
 public:
  //       
  NotCopyableOrMovable(const NotCopyableOrMovable&) = delete;
  NotCopyableOrMovable& operator=(const NotCopyableOrMovable&)
      = delete;
  //     (),    :
  NotCopyableOrMovable(NotCopyableOrMovable&&) = delete;
  NotCopyableOrMovable& operator=(NotCopyableOrMovable&&)
      = delete;
};

      
      







Les dĂ©clarations ou suppressions de fonctions dĂ©crites peuvent ĂȘtre omises dans des cas Ă©vidents:



  • Si une classe ne contient pas de section privĂ©e (par exemple, une structure ou une classe d'interface), la possibilitĂ© de copie et la relocalisation peuvent ĂȘtre dĂ©clarĂ©es via une propriĂ©tĂ© similaire de n'importe quel membre public.
  • , . , , .
  • , () /, / (.. ). / . .




Un type ne doit pas ĂȘtre dĂ©clarĂ© copiable / relocalisable Ă  moins qu'un programmeur ordinaire ne comprenne la nĂ©cessitĂ© de ces opĂ©rations, ou si les opĂ©rations sont trĂšs gourmandes en ressources et en performances. Les opĂ©rations de dĂ©placement pour les types copiĂ©s sont toujours une optimisation des performances, mais elles sont en revanche une source potentielle de bogues et de complications. Par consĂ©quent, ne dĂ©clarez pas les opĂ©rations de dĂ©placement Ă  moins qu'elles ne fournissent des gains de performances significatifs par rapport Ă  la copie. En gĂ©nĂ©ral, il est souhaitable (si des opĂ©rations de copie sont dĂ©clarĂ©es pour une classe) de tout concevoir de maniĂšre Ă  ce que les fonctions de copie par dĂ©faut soient utilisĂ©es. Et assurez-vous de vĂ©rifier l'exactitude de toutes les opĂ©rations par dĂ©faut.



En raison du risque de «découpage», il est préférable d'éviter les opérateurs de copie publique et de déplacement pour les classes que vous prévoyez d'utiliser comme classes de base (et de préférence ne pas hériter d'une classe avec de telles fonctions). Si vous avez besoin de rendre la classe de base copiable, créez une fonction virtuelle publique Clone () et un constructeur de copie protégée afin que la classe dérivée puisse les utiliser pour implémenter des opérations de copie.



Structures vs classes





Utilisez des structures uniquement pour les objets passifs qui stockent des données. Dans d'autres cas, utilisez les classes ( classe ).



Les mots-clés struct et class sont presque identiques en C ++. Cependant, nous avons notre propre compréhension de chaque mot-clé, alors utilisez celui qui convient à son objectif et à sa signification.



Les structures doivent ĂȘtre utilisĂ©es pour les objets passifs, uniquement pour le transfert de donnĂ©es. Ils peuvent avoir leurs propres constantes, mais il ne devrait y avoir aucune fonctionnalitĂ© (Ă  l'exception possible des fonctions get / set). Tous les champs doivent ĂȘtre publics, disponibles pour un accĂšs direct, ce qui est prĂ©fĂ©rable Ă  l'utilisation des fonctions get / set. Les structures ne doivent pas contenir d'invariants (par exemple, des valeurs calculĂ©es), qui sont basĂ©s sur des dĂ©pendances entre diffĂ©rents champs de la structure: la possibilitĂ© de modifier directement les champs peut invalider l'invariant. Les mĂ©thodes ne doivent pas restreindre l'utilisation de la structure, mais peuvent attribuer des valeurs aux champs: c.-Ă -d. comme constructeur, destructeur ou fonctions Initialize () , Reset () .



Si des fonctionnalités supplémentaires sont requises dans le traitement des données ou des invariants, il est préférable d'utiliser les classes ( classe ). De plus, en cas de doute, utilisez des classes.



Dans certains cas ( modÚles de méta-fonctions , traits, certains foncteurs) par souci de cohérence avec la STL, il est permis d'utiliser des structures au lieu de classes.



N'oubliez pas que les variables des structures et des classes sont nommées dans des styles différents.



Structures vs paires et tuples





Si des Ă©lĂ©ments individuels d'un bloc de donnĂ©es peuvent ĂȘtre nommĂ©s de maniĂšre significative, il est prĂ©fĂ©rable d'utiliser des structures au lieu de paires ou de tuples.



Tout en utilisant des paires et tuples Ă©vite de rĂ©inventer la roue avec votre propre type et vous permettra d' Ă©conomiser beaucoup de temps l' Ă©criture du code, des champs avec des noms significatifs ( au lieu de .first , .SECOND, ou std :: get <X> ) sera plus facile Ă  lire lors de la lecture du code. Et bien que C ++ 14 ajoute l'accĂšs au type ( std :: get <Type> , et le type doit ĂȘtre unique) pour les tuples en plus de l'accĂšs Ă  l'index , le nom du champ est beaucoup plus informatif que le type.



Les paires et les tuples sont appropriĂ©s dans le code oĂč il n'y a pas de distinction spĂ©ciale entre les Ă©lĂ©ments d'une paire ou d'un tuple. Ils sont Ă©galement tenus de travailler avec du code ou des API existants.



HĂ©ritage





La composition de classe est souvent plus appropriée que l'héritage. Lorsque vous utilisez l'héritage, rendez-le public .



DĂ©finition



Lorsqu'une classe enfant hérite d'une classe de base, elle inclut les définitions de toutes les données et opérations de la base. "L'héritage d'interface" est l'héritage d'une classe de base abstraite pure (aucun état ni aucune méthode n'y sont définis). Tout le reste est "héritage d'implémentation".



Par



L'hĂ©ritage d'implĂ©mentation rĂ©duit la taille du code en rĂ©utilisant des parties de la classe de base (qui devient une partie de la nouvelle classe). Car l'hĂ©ritage est une dĂ©claration Ă  la compilation, il permet au compilateur de comprendre la structure et de trouver des erreurs. L'hĂ©ritage d'interface peut ĂȘtre utilisĂ© pour que la classe prenne en charge l'API requise. Et aussi, le compilateur peut trouver des erreurs si la classe ne dĂ©finit pas la mĂ©thode requise de l'API hĂ©ritĂ©e.



Inconvénients



Dans le cas de l'héritage d'implémentation, le code commence à se brouiller entre les classes de base et enfant, ce qui peut compliquer la compréhension du code. En outre, la classe enfant ne peut pas remplacer le code des fonctions non virtuelles (ne peut pas modifier leur implémentation).



L'hĂ©ritage multiple est encore plus problĂ©matique et conduit parfois Ă  une dĂ©gradation des performances. Souvent, la baisse des performances lors du passage de l'hĂ©ritage unique Ă  l'hĂ©ritage multiple peut ĂȘtre plus importante que la transition des fonctions rĂ©guliĂšres vers les fonctions virtuelles. C'est aussi une Ă©tape de l'hĂ©ritage multiple Ă  l'hĂ©ritage rhombique, ce qui conduit dĂ©jĂ  Ă  l'ambiguĂŻtĂ©, Ă  la confusion et, bien sĂ»r, aux bugs.



Verdict



Tout hĂ©ritage doit ĂȘtre public . Si vous souhaitez le rendre privĂ© , il est prĂ©fĂ©rable d'ajouter un nouveau membre avec une instance de la classe de base.



N'abusez pas de l'hĂ©ritage d'implĂ©mentation. La composition des classes est souvent prĂ©fĂ©rĂ©e. Essayez de limiter l'utilisation de la sĂ©mantique d'hĂ©ritage "is": Bar , vous pouvez hĂ©riter du Foo , si je peux dire que le Bar "est» le Foo (c'est-Ă -dire, lĂ  oĂč on utilise le Foo , vous pouvez Ă©galement utiliser le Bar ).



Protected ( protected ) n'exĂ©cute que les fonctions qui devraient ĂȘtre disponibles pour les classes enfants. Notez que les donnĂ©es doivent ĂȘtre privĂ©es.



Déclarez explicitement les remplacements de fonction / destructeur virtuels à l'aide de spécificateurs: soit un remplacement, soit (si nécessaire) final . N'utilisez pas le spécificateur virtuel lors de la substitution de fonctions. Explication: Une fonction ou un destructeur marqué override ou final mais pas virtuel ne sera tout simplement pas compilé (ce qui permet de détecter les erreurs courantes). Les prescripteurs fonctionnent également comme de la documentation; et s'il n'y a pas de spécificateurs, le programmeur sera obligé de vérifier toute la hiérarchie pour clarifier la virtualité de la fonction.



L'hĂ©ritage multiple est autorisĂ©, cependant l'hĂ©ritage multiple la mise en Ɠuvre n'est pas du tout recommandĂ©e par le mot.



Surcharge de l'opérateur





Surcharger les opérateurs aussi raisonnablement que possible. N'utilisez pas de littéraux personnalisés.



La détermination du



code C ++ permet à l'utilisateur de remplacer les opérateurs intégrés en utilisant l' opérateur de mot-clé et le type d'utilisateur comme l'un des paramÚtres; également l' opérateur vous permet de définir de nouveaux littéraux en utilisant l' opérateur "" ; vous pouvez également créer des fonctions de conversion comme l' opérateur bool () .



Par



L'utilisation de la surcharge d'opĂ©rateurs pour les types dĂ©finis par l'utilisateur (similaire aux types intĂ©grĂ©s) peut rendre votre code plus concis et intuitif. Les opĂ©rateurs surchargĂ©s correspondent Ă  certaines opĂ©rations (par exemple, == , < , = et << ) et si le code suit la logique d'application de ces opĂ©rations, les types dĂ©finis par l'utilisateur peuvent ĂȘtre clarifiĂ©s et utilisĂ©s lorsque vous travaillez avec des bibliothĂšques externes qui reposent sur ces opĂ©rations.



Les littéraux personnalisés sont un moyen trÚs efficace de créer des objets personnalisés.



Contre



  • (, ) — , , .
  • , .
  • , , .
  • , , .
  • , .
  • / ( ), «» . , foo < bar &foo < &bar; .
  • . & , . &&, || , () ( ) .
  • , . , .
  • (UDL) , C++ . : «Hello World»sv std::string_view(«Hello World»). , .
  • Car aucun espace de noms n'est spĂ©cifiĂ© pour l'UDL, vous devrez soit utiliser une directive using (ce qui est interdit ) ou une dĂ©claration using (qui est Ă©galement interdite (dans les fichiers d'en-tĂȘte) , sauf si les noms importĂ©s font partie de l'interface affichĂ©e dans le fichier d'en-tĂȘte). Pour de tels fichiers d'en-tĂȘte, il est prĂ©fĂ©rable d'Ă©viter les suffixes UDL, et il est souhaitable d'Ă©viter les dĂ©pendances entre les littĂ©raux qui sont diffĂ©rents dans l'en-tĂȘte et le fichier source.




Verdict



Définissez les opérateurs surchargés uniquement si leur signification est évidente, claire et cohérente avec la logique générale. Par exemple, utilisez | au sens de l'opération OR; implémenter la logique de canal à la place n'est pas une bonne idée.



DĂ©finissez des opĂ©rateurs uniquement pour vos propres types, faites-le dans le mĂȘme en-tĂȘte et le mĂȘme fichier source, et dans le mĂȘme espace de noms. En consĂ©quence, les opĂ©rateurs seront disponibles au mĂȘme endroit que les types eux-mĂȘmes, et le risque de dĂ©finitions multiples est minime. Dans la mesure du possible, Ă©vitez de dĂ©finir des opĂ©rateurs comme des modĂšles. vous devez faire correspondre n'importe quel ensemble d'arguments de modĂšle. Si vous dĂ©finissez un opĂ©rateur, dĂ©finissez-lui Ă©galement des "frĂšres et sƓurs". Et veillez Ă  la cohĂ©rence des rĂ©sultats qu'ils renvoient. Par exemple, si vous dĂ©finissez l'opĂ©rateur < , dĂ©finissez tous les opĂ©rateurs de comparaison et assurez-vous que les opĂ©rateurs < et > ne renvoient jamais true pour les mĂȘmes arguments.



Il est souhaitable de dĂ©finir des opĂ©rateurs binaires immuables comme des fonctions externes (non membres). Si l'opĂ©rateur binaire est dĂ©clarĂ© membre de la classe, la conversion implicite peut ĂȘtre appliquĂ©e Ă  l'argument de droite, mais pas Ă  l'argument de gauche. Cela peut ĂȘtre un peu frustrant pour les programmeurs si (par exemple) le code a <b se compilera, mais b <a ne le fera pas.



Pas besoin d'essayer de contourner les remplacements d'opĂ©rateurs. Si une comparaison (ou une fonction d'affectation et de sortie) est requise, il est prĂ©fĂ©rable de dĂ©finir == (ou = et << ) au lieu de vos Equals () , CopyFrom () et Imprimer vers () . Inversement, vous n'avez pas besoin de redĂ©finir un opĂ©rateur simplement parce que les bibliothĂšques externes l'attendent. Par exemple, si le type de donnĂ©es ne peut pas ĂȘtre triĂ© et que vous souhaitez le stocker dans std :: set , il est prĂ©fĂ©rable de crĂ©er une fonction de comparaison personnalisĂ©e et de ne pas utiliser l'opĂ©rateur < .



Ne remplacez pas && , || , , (Comma) ou unaire & . Ne remplacez pas l' opérateur "" , c'est-à-dire n'ajoutez pas vos propres littéraux. N'utilisez pas de littéraux précédemment définis (y compris la bibliothÚque standard et autres).



Informations supplémentaires:

La conversion de type est décrite dans la section sur les conversions implicites . L'opérateur = est écrit dans le constructeur de copie . Le sujet de la surcharge << pour travailler avec des flux est traité dans les flux . Vous pouvez également vous familiariser avec les rÚgles de la section sur les fonctions de surcharge , qui conviennent également aux opérateurs.



AccĂšs aux membres de la classe





Rendez toujours les données de classe privées , à l'exception des constantes . Cela simplifie l'utilisation des invariants en ajoutant les fonctions d'accÚs les plus simples (souvent constantes).



Il est permis de déclarer les données de classe comme protégées pour une utilisation dans des classes de test (par exemple, lors de l'utilisation de Google Test ) ou dans d'autres cas similaires.



Procédure d'annonce





Placez des annonces similaires au mĂȘme endroit, faites apparaĂźtre les parties communes.



La définition de classe commence généralement par une partie du public: , va plus loin protégée: et privé: . Ne spécifiez pas de sections vides.



Dans chaque section, regroupez les déclarations similaires. L'ordre préféré est les types (y compris typedef , using , classes et structures imbriquées), constantes, méthodes de fabrique, constructeurs, opérateurs d'affectation, destructeurs, autres méthodes, données membres.



Ne placez pas de définitions de méthode volumineuses dans la définition de classe. Habituellement, seules les méthodes triviales, trÚs courtes ou critiques pour les performances sont «intégrées» dans la définition de classe. Voir aussi Fonctions en ligne .



All Articles