« Style Code » : différence entre les versions

De Wiki du LAMA (UMR 5127)
Aller à la navigation Aller à la recherche
 
Ligne 185 : Ligne 185 :
** ajouter un exemple d'utilisation à chaque classe.
** ajouter un exemple d'utilisation à chaque classe.
** toute classe, méthode, données doit être commentée correctement.
** toute classe, méthode, données doit être commentée correctement.
** la fiabilité doit être importante, mais je n'ai pas trop de soucis car nous travaillons sur des entiers et nous avons pas de probèmes numériques.
** La généricité est importante, il faut donc veiller à travailler sur des concepts, réalisés ensuite par des classes.
** mais la performance est fondamentale... sinon personne n'utilisera cette lib. Ainsi, avant de faire ImaGene, j'avais une bibliothèque qui representait des espaces discrets quelconques, 2D, 3D, réguliers ou non. J'aurai peut-être pu faire mieux, mais en tous cas ce qui est en sorti à l'époque est une usine à gaz, peu rapide pour les images 2D. Je n'ai donc gardé la généricité que sur des espaces cartésiens nD, grâce à un codage des cellules.
* divers
* divers
** il faudrait générer nos classes avec un patron, pour être sûr que chaque fois qu'on rajoute du code, on suit la norme choisie. Je vous joins ci-dessous mes patrons :
** il faudrait générer nos classes avec un patron, pour être sûr que chaque fois qu'on rajoute du code, on suit la norme choisie. Je vous joins ci-dessous mes patrons :

Dernière version du 7 novembre 2009 à 16:00

Guillaume D. (CGAL like)

<source lang=cpp> /**

  • Nom des classes, type, et paramètres templates avec 1ère lettre majuscule
  • (tout le reste 1ère lettre minuscule)
  • des _ entre les mots
  • variables membres commencent par m
  • variables paramètres commencent par a
  • constantes en majuscules
  • indentation : { et } sur la même colonne que le dessus et à
  • l'intérieur décalage (type ANSI)
    • /

template <Type> class Object_toto { public:

  Object_toto(const Object_toto& atoto)
  {
     ...
     code
     indenté
     ...
  }


  int is_valid()
  {}

private:

  Type mdata;
  static const int MA_CONSTANTE;

}


</source>


Seb F.

<source lang=cpp> /** -*- mode: c++ ; c-basic-offset: 3 -*-

* @file   ByteInput.h
* @author S.
* @date   Nov 2007
* 
* @brief  Comme son nom l'indique
* 
* @copyright  // Informations sur la licence, etc.
*
* Puis détails.
*
* Conventions :
*
*  - ClasseToto = ClasseToto.h + ClasseToto.cpp
*    (Ni plus, ni moins, sauf bien entendu si le .cpp est inutile).
*  - Le nom du fichier est exactement le nom de la classe.
*  - Identifiants : convention "CamelCase"
*  - Tous les identifiants de types utilisateurs commencent par des majuscules.
*  - Les constantes (pré-processeurs ou non) et valeurs de types énumérés sont
*    en majuscules. Mots séparés par "_".
*  - Un "#endif" indique par un commentaire la condition concernée.
*  - MAIS : "Avoid using the preprocessor whenever possible. [Stroustrup]"
*    (Perso, j'adhère.)
*  - Commentaire à la Javadoc (compatible avec Doxygen)
*  - Les données membres commencent par un underscore.
*      int _depth;
*  - Encapsulation (systématique).
*  - Un accesseur en lecture a le même nom que la donnée au "_" près.
*      Pas de getDepth() mais depth();
*  - Une accesseur en écriture aussi. (Pas de "set"qqchose) 
*      Pas de setDepth(int ) mais depth(int ); 
*  - Les méthodes inline ne sont pas définies dans le corps de la 
*    définition de classe mais en fin de .h (pas de code au sein 
*    de la définition de classe).
*  - Indentation : variante K&R, cf. indentExample()
*  - Dans la mesure du possible, respecter 80 colonnes max.
*    (Indenter en fonction.)
*  - Ecriture "aérée" : espaces entre les opérateurs et les opérandes, à 
*    l'intérieur des parenthèses, etc.
*    (Plutôt Java que C++, donc sans doute à ne pas adopter.)
*/
  1. ifndef _BYTEINPUT_H_
  2. define _BYTEINPUT_H_
  1. include "ByteInputFD.h"
  1. if defined(_IS_UNIX_) && defined(_HAS_GZIP_)

template< typename Type > class ByteInputGZip : public ByteInputFD {

public:
  
  /** 
   * @param input Tous les paramêtres sont commentés.
   * 
   * @return Ligne 
   */
  ByteInputGZip( ByteInput & input  );
  /** 
   * Le commentaire décrit au présent de l'indicatif ce que fait la fonction
   * ou méthode.
   * 
   * @param buff  Tous les paramêtres sont commentés.
   * @param n     Tous les paramêtres sont commentés.
   * 
   * @return ...
   */
  bool read( char *buff, size_t n );
  inline void indentExample( int & a );
  ~ByteInputGZip();
  inline ByteInput & in();

private:

  ByteInputGZip( const ByteInputGZip & other  );

protected:

  ByteInput & _in;
  int _pidReader;		/**< PID of the Stream input reader */
  int _pidGZip;		/**< PID of the GZip process */

};

/*

*  Definitions of inline methods
*/

ByteInput & in() {

  return _in;

}

/*

* 
*/

void indentExample( int & a ) {

  int i;
  for ( int i = 0; i < 100; ++i ) {
     if ( i % 2 ) {

std::cout << i << " est un nombre congru à 1 modulo 2 ";

     } else {

std::cout << i << " est un nombre pair inférieur à 100 ";

     }
  }

}

  1. endif // defined(_IS_UNIX_) && defined(_HAS_GZIP_)
  1. endif // _BYTEINPUT_H_

</source>

Jacques-Olivier L.

Conventions, structurations et qqs remarques

Un peu en vrac :

  • nommage
    • classes à la JAVA : DiscreteLine
    • méthodes : bool isAligned()
    • données membres : m_point
    • constantes majuscules : NB_MAX_POINTS
    • préprocesseur (évité autant que possible), sinon définitions _MYDEF_
  • structuration
    • tout dans un namespace
    • découpage ensuite par répertoires (base, math, etc)
    • une classe DiscreteLine : DiscreteLine.h DiscreteLine.ih DiscreteLine.cxx. Le fichier .ih contient le code des méthodes inline
    • pas de fonctions ni de variables globales, plutôt des classes <<utils>>, sauf quelques opérateurs (operator<< par exemple).
  • intentions
    • avoir des classes <<utils>> Trace, Debug, Timings pour homogéniser la gestion des erreurs.
    • je n'utilise pas les exceptions en C++ quoique je le fais en JAVA, je ne suis pas contre en avoir.
    • ajouter à chaque méthode sa complexité en pire cas, cas moyen, si cette méthode n'est pas O(1).
    • ajouter un exemple d'utilisation à chaque exécutable.
    • ajouter un exemple d'utilisation à chaque classe.
    • toute classe, méthode, données doit être commentée correctement.
    • la fiabilité doit être importante, mais je n'ai pas trop de soucis car nous travaillons sur des entiers et nous avons pas de probèmes numériques.
    • La généricité est importante, il faut donc veiller à travailler sur des concepts, réalisés ensuite par des classes.
    • mais la performance est fondamentale... sinon personne n'utilisera cette lib. Ainsi, avant de faire ImaGene, j'avais une bibliothèque qui representait des espaces discrets quelconques, 2D, 3D, réguliers ou non. J'aurai peut-être pu faire mieux, mais en tous cas ce qui est en sorti à l'époque est une usine à gaz, peu rapide pour les images 2D. Je n'ai donc gardé la généricité que sur des espaces cartésiens nD, grâce à un codage des cellules.
  • divers
    • il faudrait générer nos classes avec un patron, pour être sûr que chaque fois qu'on rajoute du code, on suit la norme choisie. Je vous joins ci-dessous mes patrons :
    • utiliser Doxygen pour générer la documentation de référence me semble indispensable
    • Doxygen est aussi pas mal pour faire un peu de documentation utilisateur

Patron de XXX.h

<source lang=cpp> /** @file XXX.h */ ////////////////////////////////////////////////////////////////////////////// // // // File name : XXX.h // // Creation : 2000/??/?? // // Version : 2000/??/?? // // Author : JOL // // Summary : Header file for files XXX.ih and XXX.cxx // // History : // 2000/??/?? : ?Name? : ?What? // // Rcs Id : "@(#)class XXX declaration." // // ///////////////////////////////////////////////////////////////////////////////

  1. if defined(XXX_RECURSES)
  2. error Recursive header files inclusion detected in XXX.h
  3. else // defined(XXX_RECURSES)
  4. define XXX_RECURSES
  1. if !defined XXX_h
  2. define XXX_h

//////////////////////////////////////////////////////////////////////////////

  1. include <iostream>

//////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////// // Forces inline if nothing is provided by the compiler.

  1. ifndef INLINE
  2. define INLINE inline
  3. endif

namespace YYY {

 /////////////////////////////////////////////////////////////////////////////
 // class XXX
 /////////////////////////////////////////////////////////////////////////////
 /** 

* Description of class 'XXX'

* Aim: */ class XXX { // ----------------------- Standard services ------------------------------ public: /** * Destructor. */ ~XXX(); // ----------------------- Interface -------------------------------------- public: /** * Writes/Displays the object on an output stream. * @param that_stream the output stream where the object is written. */ void selfDisplay( std::ostream & that_stream ) const; /** * Checks the validity/consistency of the object. * @return 'true' if the object is valid, 'false' otherwise. */ bool OK() const; // ------------------------- Datas ---------------------------------------- private: // ------------------------- Hidden services ------------------------------ protected: /** * Constructor. * Forbidden by default (protected to avoid g++ warnings). */ INLINE XXX(); private: /** * Copy constructor. * @param other the object to clone. * Forbidden by default. */ INLINE XXX( const XXX & other ); /** * Assignment. * @param other the object to copy. * @return a reference on 'this'. * Forbidden by default. */ INLINE XXX & operator=( const XXX & other ); // ------------------------- Internals ------------------------------------ private: }; /** * Overloads 'operator<<' for displaying objects of class 'XXX'. * @param that_stream the output stream where the object is written. * @param that_object_to_display the object of class 'XXX' to write. * @return the output stream after the writing. */ INLINE std::ostream& operator<<( std::ostream & that_stream, const XXX & that_object_to_display ); } // namespace YYY /////////////////////////////////////////////////////////////////////////////// // Includes inline functions/methods if necessary.

  1. if defined(INLINE)
  2. include "YYY/ZZZ/XXX.ih"
  3. endif

// // ///////////////////////////////////////////////////////////////////////////////

  1. endif // !defined XXX_h
  1. undef XXX_RECURSES
  2. endif // else defined(XXX_RECURSES)

</source>

patron de XXX.ih

<source lang=cpp>

////////////////////////////////////////////////////////////////////////////// // // // File name : XXX.ih // // Creation : 2000/??/?? // // Version : 2000/??/?? // // Author : JOL // // Summary : Implementation of inline methods defined in XXX.h // // History : // 2000/??/?? : ?Name? : ?What? // // Rcs Id : "@(#)class XXX declaration." // // ///////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////// // IMPLEMENTATION of inline methods. ///////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////

  1. include <cstdlib>
  2. include <iostream>

//////////////////////////////////////////////////////////////////////////////

  1. if defined(NO_DEBUG)
  2. define ASSERT_XXX(x)
  3. define DEBUGCMD_XXX(x)
  4. else //defined(NO_DEBUG)
  5. define ASSERT_XXX(x) if(!(x)) \
   { std::cerr << "Assertion failed : (" << #x << ')' << std::endl \
   << "In file : " << __FILE__ << " at line #" << __LINE__ << std::endl \
   << "Compiled the " << __DATE__ << " at " << __TIME__ << std::endl; abort();}
  1. define DEBUGCMD_XXX(x) x
  2. endif // else defined(NO_DEBUG)

/////////////////////////////////////////////////////////////////////////////// // Implementation of inline methods //


/////////////////////////////////////////////////////////////////////////////// // Implementation of inline functions and external operators //

/**

* Overloads 'operator<<' for displaying objects of class 'XXX'.
* @param that_stream the output stream where the object is written.
* @param that_object_to_display the object of class 'XXX' to write.
* @return the output stream after the writing.
*/

std::ostream& YYY::operator<<( std::ostream & that_stream, const XXX & that_object_to_display ) {

 that_object_to_display.selfDisplay( that_stream );
 return that_stream;

}

// // /////////////////////////////////////////////////////////////////////////////// </source>

patron de XXX.cxx

<source lang=cpp> /////////////////////////////////////////////////////////////////////////////// // // // File name : XXX.cxx // // Creation : 2000/??/?? // // Version : 2000/??/?? // // Author : Jacques-Olivier Lachaud // // email : lachaud@labri.fr // // Purpose : ?? // // Distribution : // // Use : // ?? // // Todo : // O ?? // // History : // 2000/??/?? : Mr ?Name? : ?What? // // ///////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////// // //


///////////////////////////////////////////////////////////////////////////////

  1. include "YYY/ZZZ/XXX.h"

// Includes inline functions/methods if necessary.

  1. if !defined(INLINE)
  2. include "YYY/ZZZ/XXX.ih"
  3. endif

///////////////////////////////////////////////////////////////////////////////

using namespace std;

const char* const XXX_RCS_ID = "@(#)class XXX definition.";


/////////////////////////////////////////////////////////////////////////////// // class XXX ///////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////// // Standard services - public :

/**

* Destructor. 
*/

YYY::XXX::~XXX() { }


/////////////////////////////////////////////////////////////////////////////// // Interface - public :

/**

* Writes/Displays the object on an output stream.
* @param that_stream the output stream where the object is written.
*/

void YYY::XXX::selfDisplay( ostream& that_stream ) const {

 that_stream << "[XXX]";

}

/**

* Checks the validity/consistency of the object.
* @return 'true' if the object is valid, 'false' otherwise.
*/

bool YYY::XXX::OK() const {

 return true;

}


/////////////////////////////////////////////////////////////////////////////// // Internals - private :

// // /////////////////////////////////////////////////////////////////////////////// </source>

Script de génération

Ces trois fichiers sont parsés par le script suivant, avec des paramètres ainsi :

genere.sh DiscreteLine digital2d ImaGene

<source lang=bash>

  1. !/bin/sh

if test "$#" != "3" ; then

   echo "usage: $0 module_name namespace subdir" ;
   echo "       creates three C++ skeleton files (.h .ih and .cxx) designed"
   echo "       for a class [module_name]."
   exit 1

fi if test -w "$1.h" ; then

   echo "File $1.h exists and is writable. Please remove it before." ;
   exit 2;

fi if test -w "$1.ih" ; then

   echo "File $1.ih exists and is writable. Please remove it before." ;
   exit 2;fi

if test -w "$1.cxx" ;then

   echo "File $1.cxx exists and is writable. Please remove it before." ;    exit 2;

fi cho "Creating modules $1.h, $1.ih and $1.cxx" nspace="s/YYY/$2/g" subdir="s/ZZZ/$3/g" name="s/XXX/$1/g" today='s/2000\/??\/??/'`date '+20%y\/%m\/%d'`'/g'

cat "${HOME}/Modeles/C++/XXX2.h" | sed -e ${nspace} -e ${subdir} -e ${name} -e ${today} > "$1.h" cat "${HOME}/Modeles/C++/XXX2.ih" | sed -e ${nspace} -e ${subdir} -e ${name} -e ${today} > "$1.ih" cat "${HOME}/Modeles/C++/XXX2.cxx" | sed -e ${nspace} -e ${subdir} -e ${name} -e ${today} > "$1.cxx" echo "--> done."

</source>