|
SEB
|
Posté le 06 Août 2011 à 15:14
|
|

Messages : 554
GCPoints : 103313
|
Ahhh les fameuses, tellement personnelles souvent... et tellement discutables en général avec des points valables dans tous les cas.
Bon il y a pourtant énormément de choses a dire sur les conventions de codages donc je vais commencer et essayer de ne rien oublier. Et ce n'est pas encore imposé c'est sujet a débat !
Conventions Préprocesseur
Les directives préprocesseur commençant par un # donc doivent-elles intégrer de l'indentation?
par exemple :
#ifndef XXXX
#define XXXX
# include "monmachin.h"
#endif
ou alors rester
#ifndef XXXX
#define XXXX
#include "monmachin.h"
#endif
Sauf exception explicitée et convenue en groupe au cas par cas, les noms et mots dans les preprocesseurs doivent êtres en MAJUSCULE avec un underscore séparant chaque mot.
Pour les encadrant de fichier.h (#ifndef XXX) ils doivent ajouter un underscore avant et un après tout en intégrant le 'H'
Exemple :
#ifndef _MA_CLASSE_H_
#define _MA_CLASSE_H_
#endif // _MA_CLASSE_H_
Il faut ajouter un commentaire au #endif pour spécifier quel #if il termine
Il faut absolument éviter les directives préprocesseur dans les corps de fonction, si c'est le cas il faut trouver une alternative.
Code : C++
void mafonc() {
....
#ifdef _WIN32
montrucwindows
#else
montrucposix
#endif
...
}
Ce genre de choses devrait plutôt être traité en faisant quelque chose comme
Code : C++
void montruc();
void mafonc() {
...
montruc()
...
}
et (dans un autre fichier peut-etre)
Code : C++
#ifdef _WIN32
void montruc() {
version windows
}
#else
void montruc() {
version posix
}
#endif
Conventions Codage
Je pourrais tenter de tout formuler mais parfois un petit exemple vaut mieux qu'un grand discours donc voila le style que je propose pour le codage en général.
Code : C++
int main(int argc, const char** argv) {
int a = 0;
// ici je fais le commentaire de la condition
if( macondi1 && macondi2 && macondi3
&& macondi4 && macondi5 ) {
// ici je fais le commentaire de la boucle for
for( int i = 0; i < 12; ++i ) {
faire des blabla
}
} else if( monautrecondi ) {
// ici je fais le commentaire de la boucle while
while( trucmachin ) {
faire des blublu
}
}
}
Bon la je suis très rigoureux sur les commentaires, il faudra l'etre mais je sais que en pratique dans les implementation c'est assez dur de le faire tout le temps.
A noter ici que les indentations sont composés de tabulations.
Pour les classes :
Code : C++
/**
* Class MyClass
* \brief descriptionBreve
* \author nom ou mail de l'auteur
*/
class MyClass {
public :
/**
* Constructeur par default
*/
MyClass() ;
/**
* Destructeur
*/
~MyClass() ;
/**
* Fonction qui fait des bulles
*/
void doBubbles() ;
/**
* Recupere le nombre de bulles
*/
int nbBubbles() const ;
/**
* Une fonction virtuelle pour la route
*/
virtual void myVirtual() = 0 ;
/**
* Ensuite une fonction statique
*/
static float ExplodeAllBuubles() ;
protected :
/**
* Fonction a acces protege
*/
void protectedFunc(int paramA, int paramB) ;
private :
// attribut 1
int _attribA;
OtherClass* _myFriend;
};
#include "MyClass_inl.h"
Pour faire un rapide bilan des regles : On présente dans l'ordre les fonctions publiques, protected, private puis les attributs. Les fonctions statiques en fonction de leur droits d'accès se trouvent à la fin de la partie correspondante. Les noms de classes sont avec Majuscule au premier mot puis à chaque Mot, les methodes sont avec minuscules au premier mot puis majuscules, les fonctions statiques sont avec Majuscule au premier mot et a chaque mot. On essaye au maximum de respecter un espace avant le point virgule de chaque methode. Pour l'indentation ce sont toujours des tabulations sauf pour alligner les noms d'attributs ou il faut utiliser absolument des espaces (basé sur un ide ou les caracteres sont de taille egale). Les attributs commencent par un _. Il ne faut absolument aucune implémentation dans les fichier .h même en cas de inline, ou de template il faut faire un autre fichier nommé 'MyClass_inl.h' qui contiendra tout ca.
Pour le cas des accesseurs/mutateurs, je préconise que les accesseur aient le nom de l'attribut sans le _ et les mutateurs qu'ils commencent par set...
Ce qui donne par exemple :
Code : C++
int monAttribut() const ;
void setMonAttribut(int v) ;
int _monAttribut;
Pour les commentaires il faudrait en principe ajouter les paramètres et le retour pour faire de la doc propre... perso je ne sais pas si c'est vraiment nécessaire a partir du moment ou les nommages sont explicites.
ps... dommage que les tabulations ne marchent pas dans les messages :/
Bon voila je continuerais plus tard XD
NextGine : 3D games engine
Nombre de lignes actuel : 77683
|
|
freemaul
|
Posté le 06 Août 2011 à 15:57
|
|

Messages : 174
GCPoints : 50213
|
Il faut voir aussi quels logiciel va être utiliser pour la génération de la doc, car ceci impose certaines règles sur les commentaires.
Je pense notamment à Doxygen (seul logiciel de génération de doc que je connaisse) qui impose un certain formalisme sur les commentaires en haut des déclarations de fonctions.
Il faut aussi définir si cette documentation doit être fait au moment de la déclaration (.h) ou de l’implémentation (.c) ?
Exemple doxygen :
Code : C++
/**
* \enum Str_err_e
* \brief Constantes d'erreurs.
*
* Str_err_e est une série de constantes prédéfinie pour diverses futures
* fonctions de l'objet Str_t.
*/
typedef enum
{
STR_NO_ERR, /*!< Pas d'erreur. */
STR_EMPTY_ERR, /*!< Erreur: Objet vide ou non initialisé. */
NB_STR_ERR /*!< Nombre total de constantes d'erreur. */
}
Str_err_e;
"La vie n'a pas de prix, mais elle coûte chère"
|
|
MonchauxantZ
|
Posté le 06 Août 2011 à 18:02
|
|

Messages : 117
GCPoints : 26910
|
Bien que je ne programme pas en C++, voilà ma façon de programmer (bien que certainement différente d'une programmation en C++) :
Code : Basic
Liste des variables
Liste des structures
Liste des procédures
Code(s) d'initialisation du programme (Importation, Chargement)
Code principal (Kernel)
Code(s) de fin de programme (Sauvegarde en général)
Coupure du programme.
Et tout ça avec plein de commentaires partout ;)
|
|
Huntil
|
Posté le 06 Août 2011 à 18:50
|
|

Messages : 1012
GCPoints : 289843
|
C'est plutôt pour la structure générale que pour la convention de nommage il me semble.
Dernière édition le 06 Août 2011 à 18:52
Copyright © 2007 - 2010 Huntil
"Il faut toujours un drame"
|
|
MonchauxantZ
|
Posté le 06 Août 2011 à 19:40
|
|

Messages : 117
GCPoints : 26910
|
C'est vrai oui, mais autant que si on développe à plusieurs, autant développer universellement ;)
Ça évite les confusions.
|
|
Darktib
|
Posté le 06 Août 2011 à 20:44
|
|

Messages : 4017
GCPoints : 347288
|
Pour le préprocesseur, je préfère sans indentation. Pour le reste, je suis d'accord.
Pour le reste du code... je suis déjà contre le style 'java' des accolades. Perso, je vois plus un truc style:
Code : C++
int main(int argc, const char** argv)
{
int a = 0;
// ici je fais le commentaire de la condition
if(macondi1 && macondi2 && macondi3
&& macondi4 && macondi5)
{
// ici je fais le commentaire de la boucle for
for(int i = 0; i < 12; ++i)
{
faire des blabla
}
}
else if(monautrecondi)
{
// ici je fais le commentaire de la boucle while
while( trucmachin )
{
faire des blublu
}
}
}
Noter le:
Code : C++
if(condition1 && condition2
<indent>&& condition3)
{
// ...
}
Idem pour tout endroit ou on trouve des accolades.
Pour la doc Doxygen je suis pour. Par contre je ne comprend pas l'espace entre la fin de la déclaration d'une fonction et le point-virgule...
Pour les membres je suis contre l'underscore avant le reste du nom (ou même un 'm_'), par contre je pense que les nommer comme des variables 'normales' suffit (ex maVariableQuiFaitDesBulles). Sans indentation entre le type et le nom (juste un espace).
Enfin, pour les inlines, je suis pour la définition des inlines dans le header qui les déclare, mais après la déclaration de la classe lorsque c'est le cas.
Dernière édition le 06 Août 2011 à 20:50
|
|
Huntil
|
Posté le 06 Août 2011 à 23:05
|
|

Messages : 1012
GCPoints : 289843
|
Perso je suis comme Darktib, je m'y retrouve plus facilement quand les blocs ont les accolades alignées, d'ailleurs eclipse m'énerve avec ça.
Copyright © 2007 - 2010 Huntil
"Il faut toujours un drame"
|
|
SEB
|
Posté le 07 Août 2011 à 10:41
|
|

Messages : 554
GCPoints : 103313
|
Preproc sans indentation ça me vas aussi je n'ai pas de préférence.
Pour les accolades sur la même colonne je suis moyen chaud mais bon... vu que c'est une question de gout et de perception, si la majorité est de cet avis pourquoi pas, mais d'un autre côté si c'est juste parceque ca fait 'java' c'est pas un très bon argument pour rejeter cette méthode.
L'espace du point virgule est simplement la pour aérer et un tout petit peu je trouve que ca fait moins touffu... comme l'indentation que tu appelle à la 'java'.
J'aimerais que tu explique pourquoi tu es contre l'underscore parceque ca par contre je suis pret à le défendre pendant longtemps. Je trouve que c'est indispensable lorsque l'on implémente les contenu des méthode de toujours être conscient de ce avec quoi on travaille. Et donc de savoir si c'est un attribut ou non, c'est juste une question de clarté m_ c'est trop lourd parcequ'il faut avoir le méchanisme de dire dans sa tête 'm(embre' les premiere fois qu'on le fait alors que l'underscore c pas envahissant et sufisemment distinctif. De plus cela permet de faire des accesseur qui ne porte pas le mot 'get' ce qui est plutôt sympa je trouve.
Et l'indentation entre le type et le nom... j'y tiens aussi beaucoup.
Je suis désolé mais moi mon objectif quand je veux utiliser une classe qui a été faite par moi ou quelqu'un d'autre c'est de pouvoir comprendre le plus rapidement possible ce qui s'y passe et ce qu'elle fait. Et l'indentation (allignement des attributs), espacement, nommage et organisation attributs à la fin sont à mon avis la manière la plus claire de pouvoir appréhender une classe le plus vite possible.
Les inlines dans le header ca c'est une question de ne pas avoir des fichier header trop énormes, c'est pour ca que pour ma part je procède avec un fichier supplémentaire lorsque c'est nécessaire mais je n'ai rien contre le fait de les mettre dans le .h du moment qu'ils sont à la fin.
NextGine : 3D games engine
Nombre de lignes actuel : 77683
|
|
Darktib
|
Posté le 07 Août 2011 à 20:44
|
|

Messages : 4017
GCPoints : 347288
|
En fait, c'est pas parce que c'est 'à la java' que ça ne me convient pas, c'est parce que c'est pas très lisible (pour les accolades).
SEB a écrit :J'aimerais que tu explique pourquoi tu es contre l'underscore parceque ca par contre je suis pret à le défendre pendant longtemps. Je trouve que c'est indispensable lorsque l'on implémente les contenu des méthode de toujours être conscient de ce avec quoi on travaille. Et donc de savoir si c'est un attribut ou non, c'est juste une question de clarté m_ c'est trop lourd parcequ'il faut avoir le méchanisme de dire dans sa tête 'm(embre' les premiere fois qu'on le fait alors que l'underscore c pas envahissant et sufisemment distinctif. De plus cela permet de faire des accesseur qui ne porte pas le mot 'get' ce qui est plutôt sympa je trouve.
Soit, je me range à ton avis. Mon argument aurait plutôt été tourné vers l'esthétique du code ;) (et aussi sur le fait que perso, pour savoir ce que fait une classe, je ne regarde en général que les fonctions...)
Pour ce qui est de l'indentation... mêmes arguments. Avec un en plus: chaque attribut devrait respecter cette déclaration:
Code : C++
// Documentation (très) succinte de l'attribut
type _monAttribut;
<un saut de ligne>
// Doc attr2
int _size;
// doc attr3
// ... Dans ce cas précis, les indenter ne sert à rien.
Dernière édition le 07 Août 2011 à 20:44
|
|
SEB
|
Posté le 07 Août 2011 à 21:05
|
|

Messages : 554
GCPoints : 103313
|
En fait l'underscore est aussi utile dans l'implémentation des méthodes, 1 pour savoir qu'on est en train de manipuler pas nimporte quel variable mais un attribut, 2 pour de petits soucis estetiques autres comme par exemple :
Code : C++
void MaClasse::init(int id, float distance) {
_id = id;
_distance = distance;
}
cela évite d'avoir à écrire this-> que je trouve absolument horrible et inutile comme notation tout en permettant d'avoir des arguments aux noms plus qu'explicites. En fait je trouve que les attributs sont nécessaire pour appréhender au dela de ce que fait la classe le 'comment' elle le fait, et ca peut donner pas mal d'indice sur la façon d'utiliser cette classe au mieux (d'un point de vue performance).
Pour les commentaires il faut effectivement les mettres mais un peu moins pour sautter des lignes entre mais bon ca c pas tres grave. Donc si on reprend les conventions après discussions cela donnerai quelquechose comme :
Code : C++
/**
* Class MyClass
* \brief descriptionBreve
* \author nom ou mail de l'auteur
*/
class MyClass
{
public :
/**
* Constructeur par default
*/
MyClass() ;
/**
* Destructeur
*/
~MyClass() ;
/**
* Fonction qui fait des bulles
*/
void doBubbles() ;
/**
* Recupere le nombre de bulles
*/
int nbBubbles() const ;
/**
* Une fonction virtuelle pour la route
*/
virtual void myVirtual() = 0 ;
/**
* Ensuite une fonction statique
*/
static float ExplodeAllBuubles() ;
protected :
/**
* Fonction a acces protege
*/
void protectedFunc(int paramA, int paramB) ;
private :
// attribut 1
int _attribA;
// attribut 2
OtherClass* _myFriend;
// attribut 3
float _truc;
};
inline int MaClass::monInline() const
{
return 0;
}
NextGine : 3D games engine
Nombre de lignes actuel : 77683
|
|
Darktib
|
Posté le 08 Août 2011 à 22:30
|
|

Messages : 4017
GCPoints : 347288
|
J'ai regardé le fichier texte des conventions dans le dépot, il y a quelques tabulations qui déconnent je pense, genre:
Code : txt
while(condition)
{
}
(la première accolade est après une tabulation et 2 espaces, la seconde après 4 espaces si je me souviens bien).
D'ailleurs en parlant de ça, je propose qu'on règlent nos IDE pour qu'ils remplacent les tabulations par 4 espaces, sinon la mise en forme se fait toujours la malle lorsque les sources se baladent entre les ordis...
|
|
SEB
|
Posté le 08 Août 2011 à 23:09
|
|

Messages : 554
GCPoints : 103313
|
Oui effectivement c'était du grand n'importe quoi ce fichier je pense que c'est a cause du fait que j'ai copié collé le block que j'avai fait sur game corp. C'est fixé merci ^^. Par contre pourquoi les tabulations ne seraient pas des 'tabulations' ??? comme ca les sources ne se font pas la malle.... et elles sont présenté comme chacun aime non ?
NextGine : 3D games engine
Nombre de lignes actuel : 77683
|
|
nepser
|
Posté le 09 Août 2011 à 08:55
|
|

Messages : 116
GCPoints : 23144
|
Le problème de laisser des tabulations, que si par exemple la tienne vaut 4 espaces et moi 6; on va avoir des gros décallages en particulier lors de l'alignement des noms de variable par exemple. (décallage entre la longueur du type)
|
|
SEB
|
Posté le 09 Août 2011 à 09:55
|
|

Messages : 554
GCPoints : 103313
|
Non justement... je ne sais pas si je l'ai dit dans mon premier message, je vais vérifier
mais l'idée c'est d'utiliser des tabulation pour 'indenter' et des espaces pour alligner. (en utilisant la touche espace)
Et je vous promet que en faisant comme ca si on utilise bien une police à taille de caractère fixé on a aucun souci.
Je re exemplifie :
Code : C++
class Truc
{
_>public-:
_>_>Truc()-;
_>_>void method()-;
_>private-;
_>_>int---_mavalint;
_>_>float-_mavalfloat;
};
Ou les _> sont des 'vrais tab' et les - sont des espaces.
Ps: oui désolé je ne l'avais pas précisé. autant pour moi ^^
Dernière édition le 09 Août 2011 à 09:58
NextGine : 3D games engine
Nombre de lignes actuel : 77683
|
|
nepser
|
Posté le 09 Août 2011 à 10:28
|
|

Messages : 116
GCPoints : 23144
|
Niveau mutateur, ça vous plait cette forme?
Code : C++
int monAttribut() const ;
void monAttribut(int v) ;
|
|
SEB
|
Posté le 09 Août 2011 à 11:26
|
|

Messages : 554
GCPoints : 103313
|
pour l'accèsseur oui c'est en parti pour cela que j'aime mettre un underscore aux attributs pour pouvoir écrire :
Code : C++
int monAttribut() const ;
Pour le muttateur... ca m'est franchement égal. set... ou pas set....
NextGine : 3D games engine
Nombre de lignes actuel : 77683
|
|
nepser
|
Posté le 09 Août 2011 à 11:48
|
|

Messages : 116
GCPoints : 23144
|
Des limitations sur le templating? Le nombre de "return" par fonction? L'utilisation de "goto"? L'utilisation switch/case,if/else?
Exception vs code d'erreur? Test de pointeur null dédié à l'appelant ou l'appelé? Nommage des "enum" (@freemaul: inutile de typedef comme en C les enums)?
Pointeur ou référence?
Quid du contrôle de la mémoire allouée?
|
|
SEB
|
Posté le 09 Août 2011 à 13:56
|
|

Messages : 554
GCPoints : 103313
|
Effectivement ces questions sont importantes aussi et le titre du sujet devrait permettre de les intégrer ici.
J'aurais tendance à répondre :
Des limitations sur le templating?
Heuu la je vois pas ce que tu cherche a définir XD
Le nombre de "return" par fonction?
Pourquoi le limiter ? ^o) si c'est bien codé il n'y a pas de raison de le limiter.
L'utilisation de "goto"?
J'avoue que je serais tenté de dire 'non' aux goto sauf cas exceptionnel.
L'utilisation switch/case,if/else?
Idem que devrais-t-on limiter ?
Exception vs code d'erreur?
J'aurais tendance a dire pas d'exception c'est une saleté ralentisseuse de code et qui est un des meilleur moyen de diminuer son attention aux problèmes éventuels. Les code d'erreurs.... pourquoi pas. Mais pour moi un bon système de log c'est suffisant.
Test de pointeur null dédié à l'appelant ou l'appelé?
A l’appelant définitivement plus assertion dans l'appelé pour le mode debug.
Nommage des "enum"
Le nom de l'enum formé comme pour les classe NomDeEnum. Sans typedef effectivement. et valeurs d'énum selon le même format que les macros Majuscules et underscore.
Pointeur ou référence?
Ca pour moi il ne devrais pas y avoir de règle c'est au cas par cas.
Si j'y réfléchis bien je devrais pouvoir trouver ce que je me demande pour faire le choix mais la j'ai pas le temps XD
Quid du contrôle de la mémoire allouée?
Qu'entend tu ici? tu parle de tester le retour de 'new/malloc' ? ou plutot d'un memory manager vérifiant le bon relachement de la mémoire etc... ?
NextGine : 3D games engine
Nombre de lignes actuel : 77683
|
|
nepser
|
Posté le 09 Août 2011 à 22:11
|
|

Messages : 116
GCPoints : 23144
|
Des limitations sur le templating?
C'est un problème de vue sur la façon d'aborder la conception des classes. Est-ce qu'on va faire des choses énormément templaté pour pouvoir facilement prendre en compte des modifications de lib extérieures entre autres. Par exemple, dans ton schéma uml, templater LevelEntity sur les ISceneNode de Irrlicht?
Le nombre de "return" par fonction?
Certains préfèrent n'avoir qu'un seul return par fonction pour avoir un meilleur contrôle du flot d'exécution. Ok donc.
L'utilisation de "goto"?
Comme pour le return, on va utiliser la technique du bon sens.
L'utilisation switch/case,if/else?
Est-ce que ça te dérange pas d'avoir un switch/case sur 50 enums?
Exception vs code d'erreur?
Le système de log ne répond pas à la problématique. Le problème est le suivant: si un problème d'exécution est rencontré, comment le signaler à l'utilisateur de la méthode. Par exemple, "malloc" utilise un retour vers "NULL" tandis que "new" lance un "throw" en cas de mémoire manquante. Même si les 2 n'ont pas le même effet, c'est une spécificité de conception générale d'une appli.
Test de pointeur null dédié à l'appelant ou l'appelé?
Ok
Nommage des "enum"
Ok
Pointeur ou référence?
Ce que j'utilise en règle générale c'est que si l'objet à été alloué ailleurs, alors je le passe en référence.
Quid du contrôle de la mémoire allouée?
Pointeurs intelligents? L'objet qui alloue dés-alloue? L'allocation est déterminé par un processus documenté?
|
|
Darktib
|
Posté le 09 Août 2011 à 22:40
|
|

Messages : 4017
GCPoints : 347288
|
Je suis d'accord avec SEB sur ces questions.
Pour ce qui est des enums, par contre comment nommer les valeurs? Un truc comme Irrlicht:
Code : C++
enum E_VIDEO_DRIVER
{
EVD_DIRECTX,
EVD_OPENGL,
EVD_SOFTWARE
}
Pour les tabulations, si on respecte la règle que tu as énoncé, cela m'ira.
Pour ce qui est de la désallocation, l'objet qui alloue désalloue, cela me parait le plus sûr.
Dernière édition le 09 Août 2011 à 22:41
|