Bonjour, voilà c'est pour avoir un peu vos avis sur mon style de programmation, ce qu'il y a de bien ou de pas bien. La version 1.0 est terminée, mais je vais améliorer tout ça tout de même.
http://tuxworld.tuxfamily.org
Bonjour, voilà c'est pour avoir un peu vos avis sur mon style de programmation, ce qu'il y a de bien ou de pas bien. La version 1.0 est terminée, mais je vais améliorer tout ça tout de même.
http://tuxworld.tuxfamily.org
Salut,
Bon, tu te douteras bien que je n'ai fait qu'effleurer une partie du code, mais:
En C++, il n'y a pas besoin de passer par le typedef struct, obligatoire en C, comme tu l'as fait pour toutes les structures que j'ai rencontrées.
La définition d'une structure sert en effet de déclaration pour le type en question, et tu peux donc parfaitement te contenter d'un simple
au lieu d'un
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 struct Color4f{ float r, g, b, a; } ;
Je profites d'ailleurs de ce code pour te conseiller de respecter scrupuleusement la règle "une ligne, une variable".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 typedef struct S_Color4f { float r, g, b, a; } Color4f;
Cela ne coute strictement rien d'écrire
mais, cela facilite grandement la relecture
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 struct Color4f{ float r; float g; float b; float a; } ;
Dans le même ordre d'idée, il faut savoir que les noms des variables n'influencent en rien le résultat final une fois le code compilé.
L'idéal est donc d'essayer de choisir en permanence des noms explicites, qui permettront de savoir à la simple lecture à quoi l'on a affaire...
Je sais bien que l'on parle de couleur "rgba", mais l'idéal aurait été d'utiliser les noms complets, à savoir
Cela n'aurait pas couté grand chose, mais aurait facilité encore une fois la lecture
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 struct Color4f{ float red; float green; float blue; float alpha; } ;
Ta classe CGraphic et toutes celles qui en dérivent devrait avoir un destruteur virtuel, car je présume que les différents objets sont gérés par allocation dynamique de la mémoire.
Si tu ne rend pas le destructeur virtuel,tu coures le risque d'une mauvaise destruction des objets de types dérivés, avec d'éventuelles fuites de mémoire très importantes
Je n'ai pas lu énormément de code à part celui des fichiers d'en-tête, mais j'ai remarqué certaines fonctions qui faisaient plus de 600 lignes, voire même près de 900 lignes pour l'une d'elles.
C'est douze à 20 fois trop!!!
l'idéal est de toujours essayer de limiter la taille des fonctions à environ 25 à 50 lignes grand maximum.
Bon, on peut ne pas chipoter pour une ou deux lignes de plus, mais là, nous sommes vraiment très loin de cette limite
Essayes de garder en permanence en tête le principe de la délégation des tâches : toute classe, toute fonction, ne devrait s'occuper que d'une chose, mais devrait le faire correctement
Il en va d'ailleurs de la lisibilité du code, car, lorsque tu dois parcourir 6 à 900 lignes de code, il devient très difficile de garder en tête la logique complete suivie par la fonction, en cas de débugage
De plus, une bonne délégation des responsabilités te permettra sans doute d'éviter de répéter 20 fois le même code, au besoin en passant certains paramètres en argument, et participera donc à la "simplification générale" de ce dernier .
Enfin, fais attention à la cohérence de tes règles de nommage : tu devrais éviter les règles qui font que tu en vienne a devoir utiliser des noms exclusivement en minuscules pour les fonction et à devoir jongler avec des majuscules et des minuscules pour les champs de certaines structures.
Idéalement les champs de structure, les variables membres et les fonctions membres devraient respecter les même conventions, au niveau de la casse à tout le moins
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
//Parenthèses
"Il me semble" qu'en passant par :
il est possible d’accéder à la structure en utilisant simplement
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 typedef struct S_Color4f { float r, g, b, a; } Color4f;
au lieu de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 Color4f.r
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2struct Color4f.r
Ca, c'est vrai en C, mais, en C++ ca ne l'est plus:
Avec un code comme
tu peux parfaitement l'utiliser sous la forme de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 struct Color4f{ float r; float g; float b; float a; } ;
En C++, il n'y a que deux différences, assez maigres d'ailleurs, entre une structure et une classe:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2Color4f myColor; myColor.r = /* une valeur */ ;
A ces deux détails près, l'utilisation de struct est strictement identique à celle de class, et tu pourrait d'ailleurs parfaitement envisager d'y rajouter un constructeur, voire des fonctions membres
- la visibilité par défaut des membres d'une classe est private alors qu'elle est public pour les structures
- La visibilité de l'héritage d'une classe est private alors qu'elle est public pour les structures
A ce sujet, les types de données comme Color4f et autres ont, classiquement, sémantique de valeur!
Cela signifie qu'elles sont copiables, assignables, généralement comparables et... constante.
En effet, tu peux très bien avoir deux objets de type Color représentant des valeurs identique qui utilisent deux adresses mémoire différentes, par contre, si tu modifies une des valeurs dont elles sont composée, tu obtiens... une nouvelle couleur
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Je ne savais pas pour struct, je vais changer ça.
Pour ma structure, elle n'a rien à faire ici, j'ai du l'écrire avant d'inclure OpenGL, car cette structure existe déjà sous OpenGL
Sinon pour le nomage des variables tu as raison à mon avis. J'avais un prof qui me disait de nommer explicitement les variables et les fonctions, et qu'un bon programme n'a pas besoin de commentaires, genre :
float Fonction_qui_multiplie_le_parametre_par_trois(float parametre);
Le débat est ouvert. Perso je pense qu'on se retrouve avec des lignes de code super longues mais explicites. :-)
Sinon tu as raison j'ai deux fichiers .cpp beaucoup trop longs. Je découpe ma grosse fonction principale en sous-fonctions inline qui ne sont appelées qu'une seule fois ?
Merci pour ton intervention et ta patience.
Ben il est possible de trouver un "juste milieu"
multplyByThree, par exemple
Ce qui importe, surtout, c'est de respecter la règle de la responsabilité unique...Sinon tu as raison j'ai deux fichiers .cpp beaucoup trop longs. Je découpe ma grosse fonction principale en sous-fonctions inline qui ne sont appelées qu'une seule fois ?
L'idée est que chaque fonction ne doit faire qu'une chose mais qu'elle doit la faire correctement
En respectant ce principe, il devient d'ailleurs beaucoup plus aisé de s'assurer que chaque fonction fait bien ce qu'elle est sensée faire en mettant des tests unitaires en place
Mais je ne crois pas que l'inlining systématique des fonctions n'apportera quoi que ce soit en terme de performances:
Déjà, l'appel de fonction ne demande que quelques instructions processeur, et s'effectue donc sur seulement quelques cycles d'horloges, ce qui est généralement peu par rapport au temps qu'il faut pour exécuter certaines boucles.
Ensuite, le fait de déclarer une fonction inline ne fait que demander au compilateur de remplacer l'appel de la fonction par le code correspondant, mais le compilateur reste en définitive seul juge pour décider de le faire ou non.
Il y a en effet de nombreux freins à sa capacité d'inlining, comme le fait qu'une fonction soit virtuelle ou qu'elle doive etre traduite en un nombre d'instructions processeurs supérieur à une certaine limite.
Enfin, l'inining peut etre considéré comme une optimisation prématurée, et devrait etre réservé, en gros, aux cas dans lesquels il est prouvé qu'il apporte réellement un gain significatif (mais cela signifie qu'il faut... trouver un moyen de comparer objectivement les performances avec et sans inlining )
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Je ne peux que plussoyer ce prof.J'avais un prof qui me disait de nommer explicitement les variables et les fonctions, et qu'un bon programme n'a pas besoin de commentaires
Par contre l'exemple donné est totalement bidon car la logique même nous dit que cette fonction est inutile. Mais d'un autre côté, c'est la bonne nomenclature de la fonction qui nous signale que cette fonction est inutile, donc encore un bon point pour le nommage explicite
Pour ce qui est de l'inlining c'est pas compliqué : quand ta fonction contient simplement un return et qu'elle n'est pas virtuelle, alors elle devrait être inlinée afin d'éliminer une indirection inutile (sauf si cela devait créer des dépendances cycliques dans le .h auquel cas on s'abstiendra ).
Dans les autres cas, cela relève de l'optimisation.
Cette règle n'a l'air de rien, mais c'est vraiment, AMHA, une 4 ou 5 règles les plus importantes en développement logiciel (pas qu'en c++ donc).
Je préfère l'appeler la "règle de l'opération unique et explicite": une fonction ne doit effectuer qu'une seule opération et son nom doit expliciter ce que fait cette fonction.
Donner une limite au nombre de ligne d'une fonction c'est bien pour donner un ordre d'idée aux grands débutants, mais cela ne ma parait pas très sérieux. On peut avoir par exemple une fonction qui effectue une requête SQL simple mais très longue (par exemple un select sur 200 champs).
« L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
Spinoza — Éthique III, Proposition VII
SQL est si pourrie qu'il faille écrire autant de lignes que de requêtes ???
Si c'est vraiment le cas, il faut exploiter les macros ^^ écrire 200 lignes de copier collé ou presque me révulserait au plus haut point...
edit : ah et 200 lignes c'est pas ce que j'appellerais une fonction trop longue, tout dépend de ce qu'elle fait.
De même que la règle: une ligne = une opération (qui n'est qu'une spécialisation de la règle précédente) est une bonne règle.
Par exemple:Je déteste cette notation. C'est certes compact, mais ça demande un inutile effort de compréhension pour l'analyse.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 inline void CAnimation::pass(const int& loop_type, const int& step) { // we go to the next image up_down ? cursor -= step : cursor += step; // argh
Conseil: utilise des guards un peu plus complexes, ça peu éviter de mauvaises surprises. Par exemple:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 #ifndef ANIMATION #define ANIMATION
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 #ifndef ANIMATION_H__ #define ANIMATION_H__les capitales sont généralement réservées pour les #define (et donc les macros également).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 enum { NO_LOOP, LOOP, UP_DOWN_LOOP };
Sinon, le code est propre et bien documenté, ça fait plaisir
Pas grand chose à dire donc (je ne suis pas plongé en détail non plus). Juste peut-être quelque chose d'étrange (mais il y a peut-être une raison): il n'y a aucune fonction membre constante.
« L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
Spinoza — Éthique III, Proposition VII
« L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
Spinoza — Éthique III, Proposition VII
De toutes manières, personne n'est vraiment d'accord sur le nombre de ligne maximal que l'on peut admettre
Mais une réminiscence de l'époque où l'affichage se faisait sur 25 lignes de 80 colonnes mène régulièrement à considérer que 50 lignes (l'équivalent de deux écrans d'affichages) représentent une limite sensée
Je n'engueulerai jamais quelqu'un qui fournit une fonction qui ne fait effectivement qu'une seule chose mais qui la fait en 60 lignes, mais j'engueulerai surement quelqu'un qui fournit une fonction de 40 lignes et qui prend trois responsabilités
Tout dépend du select que tu fais, mais si tu dois t'amuser avec des jonctions, des requetes qui te permettront de sélectionner une série d'identifiants, ou d'autre trucs du genre, on en arrive assez facilement à des requete imbitables
Ceci dit, l'idéal reste quand meme de "factoriser" le code de cette requete, en ayant, pourquoi pas, plusieurs fonctions qui créent des parties spécifiques
S'il y a une chose à savoir en informatique, c'est que de nombreuses règles doivent etre comprises suffisamment bien pour savoir quand il est bon d'y dérogeredit : ah et 200 lignes c'est pas ce que j'appellerais une fonction trop longue, tout dépend de ce qu'elle fait.
Mais il n'empêche que j'aurai quand meme toujours tendance à considérer a priori une fonction de 200 lignes avec énormément de suspicion, du moins, jusqu'à ce que j'aie la preuve formelle qu'il n'était effectivement pas possible de faire autrement
Même avec une incrémentation correcte, je trouve que la complexité de compréhension d'une fonction s'élève de manière quasi exponentielle par rapport à son nombre de lignes, et je serais vraiment très étonné qu'il n'y ait pas de possibilités élégantes de factoriser quelque chose qui demande 200 lignes de code
[quote:r0d]
De même que la règle: une ligne = une opération (qui n'est qu'une spécialisation de la règle précédente) est une bonne règle.
Par exemple:
[/quote]Tout à fait : ce n'est qu'un sucre syntaxique qui n'apporte rien, en terme de performances à la version "if ... else" classique qui serait (pour reprendre l'exemple) proche de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 inline void CAnimation::pass(const int& loop_type, const int& step) { // we go to the next image up_down ? cursor -= step : cursor += step; // argh
dont la compréhensibilité est malgré tout largement meilleure.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 if(up_down) cursor-=step; else cursor+= step;
Cependant, toute regle ne vaut que par les exceptions qu'on admet à son sujet, et il existe en effet quelques cas, très rares au demeurant, dans lesquels l'utilisation d'un if... else demanderait une gymnastique que l'opérateur ternaire ne demanderait pas, et dans lesquels l'opérateur ternaire se justifie donc pleinement
En outre, l'opérateur ternaire peut être évalué à la compilation, alors que le if... else classique ne peut pas l'être.
Lorsqu'on programme en suivant le paradigme generique, c'est parfois la seule solution dont on dispose pour pouvoir "activer" ou non des capacités contradictoires
Mais bon, ca, c'est des cas réellement particuliers
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Pour le ternaire, j'aurais tendance à écrire celui-ci de cette façon :
Ce qui m'évite toute redondance d'identificateur => refactorisation future optimisée, lecture du code optimisée.
Code : Sélectionner tout - Visualiser dans une fenêtre à part cursor += (up_down ? -1 : +1)*step;
Le problème soulevé par le SRP (Single Responsability Principe), c'est la délimitation de la responsabilité, qui est abstraite, par conséquent floue.
A partir de quand considère-t-on qu'une fonction/classe prend 2 responsabilités ? Je pense qu'un tel débat peut avoir un intérêt énorme, à mes yeux en tout cas.
Je commence déjà à réécrire mon code. :-) en prenant en compte vos remarques. Vous me donnez du boulot
La lecture est meilleure, mais ça rajoute tout de même une super multiplication.cursor += (up_down ? -1 : +1)*step;
J'ai compris un truc en informatique,
factoriser = calcul plus long, mais souvent meilleure lisibilité. (parfois c'est l'effet inverse)
Je sais que les machines sont puissantes de nos jours, mais personnellement je me pose la question ? J'écris pour l'homme ou pour la machine ?
Par exemple quand je divise x par 8 et que x est un entier, hop, décalage de bits, et si le gars qui passe derrière moi ne comprends pas, je me dis qu'il n'avait qu'à savoir lire.
Mais j'ai aussi moi même du mal à me relire parfois
!(y - 1) ? (x ? y << 1: y >> 2) : x << 1
Le compilateur peut très bien optimiser ce que tu ne pensais pas pouvoir être optimiser, bref.
Le problème pour moi est que ton "8" est un magic number. Tu devrais lui donner un vrai nom explicite car pour la machine un nom de variable ou une variable globale avec un nom correct est pareil.
En effet, il faut bien comprendre que les bons compilateurs aujourd'hui optimisent beaucoup de choses. Le décalage de bit c'est la base, mais ça peut aller très loin.
Aujourd'hui, l'optimisation ça ne consiste plus du tout à essayer de gagner 2 cycles sur une opération (ça en général le compilateur le fait mieux que nous), mais utiliser les conteneurs adéquats, éviter les copies inutiles, chercher des heuristiques malines, utiliser au mieux les ressources à disposition (multithreading, grid, etc.), ce genre de choses.
« L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
Spinoza — Éthique III, Proposition VII
Je dirais, de manière générale, dés qu'il te faut plus d'un verbe pour expliquer la logique de ta fonction:
- Si ta fonction commence par trier les données avant de sélectionner celles qui correspondent à un critère donné,
- si elle doit charger des données avant de les afficher,
- si elle doit calculer quelque chose avant d'utiliser le résultat,
- si elle doit demander quelque chose avant de réagir en fonction de l'introduction de l'utilisateur,
c'est chaque foisque ta fonction a d'office au minimum deux responsabilités, et donc une de trop
Lorsque j'essaye d'expliquer comment essayer de déterminer ce qu'il faut mettre en place lors d'une conception, je dis généralement de partir du principe qu'il faut exprimer clairement ce dont on a besoin et partir du principe que les noms représentent des types qu'il faudra implémenter et que les verbes représentent des comportements (fonctions libres ou fonctions membre).
Cette manière de travailler est, certes, perfectible et sans doute un peu à l'emporte pièce, mais c'est, en tous cas, une base saine pour envisager les choses
En nombre de lignes, cela reviendra quasiment au même
Pourquoi un calcul plus longJ'ai compris un truc en informatique,
factoriser = calcul plus long, mais souvent meilleure lisibilité. (parfois c'est l'effet inverse)
Au contraire, le fait de pouvoir séparer les différentes étapes importantes te permettent de ne t'inquiéter que d'un problème à la fois, et donc d'avoir des problèmes plus simples à résoudre, impliquant des solutions plus simples elles aussi
Tu écris d'abord pour l'homme, puis pour la machine.Je sais que les machines sont puissantes de nos jours, mais personnellement je me pose la question ? J'écris pour l'homme ou pour la machine ?
Il faut te dire que ton code sera beaucoup plus souvent lu / modifié qu'il ne sera compilé et que, s'il est trop complexe, tu ne sera pas en mesure de corriger facilement les éventuelles erreurs.
De plus, les jeux d'instructions au niveaux des processeurs sont tels que deux codes ayant un comportement identique dont l'un utilise des sucres syntaxiques seront traduits exactement de la même façon dans l'exécutable final.
Simplement, l'un sera plus "reader friendly" que l'autre
Il ne s'agit pas de "savoir lire" ou non, il s'agit de l'effort mental nécessaire à la compréhension d'un ensemble d'instruction.Par exemple quand je divise x par 8 et que x est un entier, hop, décalage de bits, et si le gars qui passe derrière moi ne comprends pas, je me dis qu'il n'avait qu'à savoir lire.
Tu auras beaucoup plus facile à comprendre i *= 8 que i <<3, parce que, dans le deuxième cas, tu devra avoir une "gymnastique mentale" plus importante (en devant déjà commencer par calculer la valeur de 2^nombre de bits de décalage)
C'est sans doute la meilleure preuve que ton écriture n'est pas bonneMais j'ai aussi moi même du mal à me relire parfois
!(y - 1) ? (x ? y << 1: y >> 2) : x << 1
Si tu as déjà du mal à te relire toi-même alors que tu es sans doute la personne la plus à mène de savoir ce que tu voulais faire, dis toi que quelqu'un qui découvre ton code sans savoir ce que tu pouvais avoir en tête au moment où tu l'as écrit a de grandes chances d'avoir énormément de mal à le comprendre
Ce qu'il faut savoir au niveau des sucres syntaxiques, c'est qu'ils n'ont été mis au point que parce que, à une époque, il y avait de très fortes contraintes techniques en terme d'affichage et de visibilité du code (les écrans, par exemples, n'étaient capables que d'afficher 25 lignes de 80 colonnes).
Il fallait donc, effectivement, trouver le moyen de faire tenir "un maximum d'information" sur "un minimum d'espace".
Ces contraintes techniques ont été levées, en gros, depuis l'époque de windows 3 / 3.1 et l'arrivée d'éditeur de texte pouvant sans problème afficher, sur un écran, largement plus de 25 lignes et 80 colonnes.
Le besoin de sucre syntaxique a donc simplement diminué en même temps que les contraintes techniques, et, comme il n'y a pas de différence au final en terme de code binaire généré, il est largement préférable de privilégier la relecture aisée du code
Personnellement, je rève du jour où C et C++ se décideront à supprimer l'opérateur , pour la déclaration de variables, par exemple
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Pas mal comme définition
Cependant, j'ai peur que ce ne soit pas aussi simple
Prenons un exemple concret: on a un gros objet plein de variables et on veut le sérialiser. Le sauvegarder dans un fichier xml disons. On veut écrire une fonction exportToXmlFile( ofstream & file ), par exemple (il y a mille façons de serialiser un objet). Et bien cette fonction peut faire 500 lignes juste en faisant desPourtant la fonction ne fera qu'une seule chose: sauvegarder notre objet au format xml.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 file << "<root>" << endl; file << "<variables>" << endl; file << "<variable>" << ma_variable << "</variable>" << endl; // etc.
Mai peut-être devrions-nous ouvrir un autre fil?
« L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
Spinoza — Éthique III, Proposition VII
J'ai bien dit que la méthode est perfectible, et qu'elle se contente de donner une base de départ pour la réflexion.
Cependant, tu remarquera que j'ai parlé de décrire la logique qui est implémentée dans la fonction
Et donc, si l'on reprend ton exemple, nous pourrions déjà décrire la logique sous la forme de
Mon dieu! cela fait quatre verbes... donc trois de trop
- écrire l'en-tete du fichier
- "ouvrir" la racine
- écrire les données
- "fermer la racine"
Cela nécessite donc trois fonctions
createXmlHeader : qui écrit les fameuses lignes qui indiquent l'encodage
openRootNode qui contientwriteData, qui mérite peut etre d'être également factorisée
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 file << "<root>" << endl; file << "<variables>" << endl;
closeRootNode qui contientet donc, une fonction exportToXmlFile( ofstream & file) qui prend la forme de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 file << "</variables>" << endl file << "</root>" << endl;;
mon conseil est donc parfaitement respecté et respectable :d
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 exportToXmlFile( ofstream & file) { createXmlHeader(file); openRootNode(file); writeData(file); closeRootNode(file); }
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Définition intéressante, mais qui amène quand même un problème Si on la suit jusqu'au bout, on ne fera qu'écrire des fonctions contenant des appels à des fonctions... On finit par perdre un temps énorme en sous-découpage.
J'ai l'impression que c'est un peu pousser l'idée à l’extrémisme...
A mon avis il faut trouver un juste milieu, et pour moi tant qu'on n'écris un code qu'une seule fois, qu'il fasse 4 trucs différents je m'en fous, tant que le nommage de la fonction est explicite ça regarde pas l'utilisateur.
Dès qu'on doit réutiliser un bout du code, hop on l'encapsule.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager