IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Bomberman et explosion des bombes dont la portée est plus grande que le plateau


Sujet :

C++

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Février 2018
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lycéen
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2018
    Messages : 2
    Points : 1
    Points
    1
    Par défaut Bomberman et explosion des bombes dont la portée est plus grande que le plateau
    Bonjour,

    Je suis en BTS informatique et je dois vous avouez que je suis en galère pour un projet d'informatique considéré comme difficile par notre prof.
    En effet, le but est de créer un programme, à l'aide d'un tableau 2D, qui est capable de faire exploser des bombes d'une certaine puissance (ex: une bombe de valeur 2 explosera 2 cases dans les 4 directions). Pour faire cette récursivité entre toutes les bombes, il n'y a aucun problème, les bombes s’enchaînent, le programme est capable de dire si notre personnage est toujours en vie ou non. Seulement maintenant, si une bombe a une puissance de 10 par exemple, alors que le tableau ne fais que 5x5, hop, crash du programme.
    Alors maintenant je j'ai codé tout ça je me doute que résoudre ce problème ne doit pas être aussi compliquer, cependant je me perd complètement.


    Je vous met tout mon code en pièce jointe, et j'espère que vous pourrez m'aider.



    Merci d'avance

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    #include <iostream> // bibliothèque de gestion des E/S 
    #include <conio.h> // gestion de la console (ici _getch()) 
    #include <Windows.h> 
    #define MIN(X,Y) ((X)<=(Y)?(X):(Y)) 
    #define MAX(X,Y) ((X)>=(Y)?(X):(Y)) 
    using namespace std;
     
     
    const int H = 5, L = 5;
    int iPersonnage = 0, jPersonnage = 0; // exemple 
     
     
     
     
    int jeu[L][H] = { { 0, 0, 0, 0, 1 },
    				  { 0, 0, 0, 3, 0 },
    				  { 0, 0, 1, 1, 0 },
    				  { 0, 0, 0, 0, 0 },
    				  { 0, 0, 0, 0, 0 } };
     
     
     
    /***************************
    Affichage du plateau de jeu
    ***************************/
    void affichageJeu()
    {
    	int i, j;
     
    	for (i = 0; i < L; i++)
    	{
    		for (j = 0; j < H; j++)
    		{
    			cout << jeu[i][j] << "\t";
    		}
    		cout << endl;
    	}
    }
     
    /***************************
    Explosion d'une bombe à la ligne i et colonne j
    Le plus simple est de créer une fonction récursive
    pour tenir compte des réactions en chaines
    Personnellement, quand une zone est atteinte par une bombe,
    je remplace le contenu de la case par -1
    ***************************/
    void explosion(int iBombe, int jBombe)
    {
    	int i = jeu[iBombe][jBombe]; //Permet de savoir la puissance de la bombe activée en premier 
    	jeu[iPersonnage][jPersonnage] = -2; // Permet de localiser visuellement le personnage
    	int Explosion; // Utile pour la boucle for
    	int imin = H-1, jmin = L-1, imax = H, jmax = L;
     
     
     
     
    	if (jeu[iBombe][jBombe] == i)  //Permet de répendre l'impacte de la bombe, même si celle ci est égale à 1000000000
    	{
    		// Explosion des cases
    		for (Explosion = 0; Explosion <= i; Explosion++)
    		{
     
     
    			//Il manque ici la gestion de définition des nouveaux coordonés d'une éventuelle bombe impacté par la première
    			// Appelle de cette fonction avec les coordonnés de la nouvelle bombe déclancher par la précedente
     
    			jeu[iBombe][jBombe] = -1; //Bombe elle même.
     
    			//iBombe H
    			//jBombe L
     
     
    			/*if (i + iBombe > H) break;*/
     
    				if (jeu[iBombe - (Explosion)][jBombe] > 0)
    				{
    					explosion(iBombe - Explosion, jBombe); // haut
    				}
     
     
    				if (jeu[iBombe][jBombe + (Explosion)] > 0)
    				{
    					explosion(iBombe, jBombe + Explosion); //Droite
    				}
     
    				if (jeu[iBombe + (Explosion)][jBombe] > 0)
    				{
    					explosion(iBombe + Explosion, jBombe); //Bas
    				}
     
     
     
    				if (jeu[iBombe][jBombe - (Explosion)] > 0)
    				{
    					explosion(iBombe, jBombe - Explosion); //Gauche
    				}
     
     
     
     
     
     
     
     
     
     
    			if (iBombe - Explosion >= 0)
    				break;
    			else jeu[iBombe - Explosion][jBombe] = -1; //Haut
     
    			if (jBombe + Explosion >= jmax)
    				break;
    			else jeu[iBombe][jBombe + Explosion] = -1;//Droite
     
     
    			if (iBombe + Explosion >= imax)
    				break;
    			else jeu[iBombe + Explosion][jBombe] = -1; //Bas
     
     
    			if (jBombe - Explosion >= jmin)
    				break;
    			else jeu[iBombe][jBombe - Explosion] = -1;//Gauche
     
     
     
     
    				/**********************************************************/
    				/*
     
    				int imin = 0, imax = H, jmin = 0, jmax = L;
     
     
     
    				// on applique une correction éventuelle pour les bords.
    				if (imin <0) imin = 0;
    				if (jmin <0) jmin = 0;
    				if (imax >= H) imax = H - 1;
    				if (jmax >=L) jmax = L - 1;
     
     
     
    				/***********************************************************/
     
     
     
     
    		}
     
    	}
     
     
    }
     
     
     
     
     
     
     
     
     
    /*****************************
    Fonction principale
    *****************************/
    int main() // Fonction principale 
    {
    	// La commande ci-dessous permet d'obtenir les accents 
    	// dans la console. Mais il faut choisir la police de 
    	// caractères Consolas ou Lucida 
    	SetConsoleOutputCP(1252);
    	explosion(2, 2);
    	cout << "PLATEAU DE JEU APRES EXPLOSION DE LA BOMBE " << endl;
    	cout << "LES -1 INDIQUENT LES POSITIONS DETRUITES" << endl;
    	cout << "Et pour finir, le -2 représente votre personnage, du moins si il est toujours vivant" << endl;
    	affichageJeu();
    	// Indiquer si le personnage est encore vivant après l'explosion 
     
     
     
     
    	if (jeu[iPersonnage][jPersonnage] == -1)
    		cout << "Le personnage est mort";
    	else cout << "Le personnage est vivant";
     
     
     
    	_getch();
    	return 0; // fin du programme. Le code 0 est envoyé 
    }
    Fichiers attachés Fichiers attachés

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Tu connais le problème (tu accèdes en dehors de ta zone de jeu), tu connais la solution (empêcher d'accéder à une telle zone) !

    Pour cela, calcule la position, et si elle est trop grande (ou trop petite), alors réduit la (ou augmente la) ou ignore la

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Il y a quand même quelques soucis avec ton code, que j'ai parcouru en vitesse, je te les marques "tels qu'il viennent":
    1. vire conio.h, ce n'est pas un fichier d'en-tête C++, et ce n'est même pas un fichier standard du C... reportes-toi à cette entrée de la FAQ pour savoir comment faire un pose qui sera portable
    2. vire windows.h, tu n'en as pas besoin (en plus, c'est un fichier spécifique à windows... quid si on veut compiler sous linux ou sous Mac OS on est bloqué tu trouves pas ca idiot pour un truc en mode console )
    3. vire la lignes using namespace std;, je t'expliquerai pourquoi si tu le demandes, mais prend l'habitude d'utiliser les noms pleinement qualifié des fonctionnalités issues de la bibliothèque standard (comme std::cout, std::cin, ou std::endl)
    4. min et max existent déjà dans la bibliothèque standard, dans le fichier d'en-tête <algorithm>, utilise les au lieu de ces horribles macro issues du C. Là aussi, je justifierai mon conseil à la demande
    5. essayes de respecter la règle "une instruction (déclaration) = une ligne" : on n'est vraiment plus quelque caractères près dans un code source, mais ca facilite la lecture
    6. dans le même ordre d'idée, essaye de choisir des noms de variables (et de constantes) explicites : pourquoi utiliser H au lieu de "hauteur" et L au lieu de "largeur" tu sais ce qu'elles représentent maintenant, mais... dans six mois ou un an
    7. Les variables globales, C'EST MAL... Je ne parle pas de H et de L (sauf en ce qui concerne leur nom), mais de toutes les autres...
    8. Tu as de la chance que ton tableau ne fasse que 5*5, car tu te places dans une position dans laquelle le débordement de pile est patent, si tu décide d'augmenter les dimensions
    9. au lieu d'utiliser des "valeurs magiques" comme 0, 1, 3 ou -1, tu devrais envisager l'utilisation d'une énumération
    10. ne déclare pas te variables en début de fonction: déclare-les plutôt au plus près de leur première utilisation (par exemple, directement après la parenthèse ouvrante de ta boucle for(...; ...; ...)
    11. les accents, on s'en fout pas mal dans un affichage console... d'autant plus que tu risque de toutes manière d'avoir un problème du seul fait de l'encodage (avec ou sans BOM, et d'autres joyeusetés du style) de ton fichier source . L'idéal, pour ne pas se prendre la tête (surtout sous windows) c'est d'envisager l'anglais comme langue d'affichage: ainsi, plus de problème d'accents, vu qu'il n'y en a simplement pas
    12. si un code n'a pas sa place, supprime le au lieu de le commenter: ainsi, il disparait, et les gens ne commenceront pas à se demander s'il doivent le décommenter ou non
    13. Regroupe tes lignes de code: cela ne sert à rien de rajouter cinq lignes vides à gauche et à droite . Seulement, quand, après avoir viré les lignes vides et les lignes de commentaires seuls, on se retrouve avec une fonction de près de 60 lignes, on peut tout doucement commencer à penser qu'elle en fait trop
    14. Je suis l'un des rares à être dans le cas, mais j'ai personnellement horreur d'utiliser break pour sortir d'une boucle, alors que j'aurais pu, "tout simplement" adapter ma condition de sortie
    15. de manière générale, la meilleure approche pour gérer correctement la récursivité (je ne suis d'ailleurs pas sur qu'elle soit absolument nécessaire ici), c'est de gérer et "d'évacuer" le (ou les) "cas de base" (la situation dans laquelle la fonction ne sera pas appelée une fois de plus). Une fois que ces "cas particuliers" sont hors de tes pattes, la logique devient beaucoup plus simple à mettre en oeuvre, car tu sais que, quoi qu'il arrive, tu sera dans une situation dans laquelle il faut faire l'appel récursif

    Je sais, ca fait beaucoup, et peu d'explications... Mais, que veux tu, tu es occupé à faire ce que l'on pourrait appeler un "kata", et nous, nous sommes les "sensei" qui veillent à ce que tu fasses tes mouvements correctement... Il est donc logique que l'on te tape sur les bras si la position n'est pas bonne, n'est-ce pas

    Mais, rassure toi: on est tous passés par là, et nous t'expliquerons tout ce que tu pourras demander sur le sujet
    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

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Dans un tel projet, je m'attendrais à avoir les fonctions void exploseCase(position); void exploseBombe(position); void exploseBombe(position, direction, puissance); afin d'avoir une pseudo-implémentation du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    void exploseCase(position)
    {
      s'il y a une bombe sur la case : exploseBombe(position)
    }
    void exploseBombe(position)
    {
      exploseBombe(position, vers le haut, puissance de la bombe);
      exploseBombe(position, vers la droite, puissance de la bombe);
      exploseBombe(position, vers le bas, puissance de la bombe);
      exploseBombe(position, vers la gauche, puissance de la bombe);
    }
    void exploseBombe(position, direction, puissance)
    {
      pour i allant de 1 à puissance, sans dépasser le plateau
        exploseCase(position + i)
    }
    Sinon, es-tu vraiment en C++ ? En dehors de cout tout ceci est du bon vieux gros C.
    Pourrais-tu mettre au propre un minimum ton code avant de le poster ? Voir des sauts de ligne et tabulations totalement au hasard ne donne pas du tout envie de lire.
    Pense à utiliser les balises code pour ton code, il est suffisament petit pour être posté directement.

    Et où se passe la gestion des inputs ? Tout ce que je vois là c'est un plateau fixe, une explosion en (2,2) et l'affichage du plateau. Une seule et unique fois.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Au passage, la propagation des explosions peut aussi être faite en itératif, si ta grille de jeu permet un "flag" indiquant qu'elle est en train d'exploser:
    • Marquer la case de la première bombe comme "explosant".
    • FAIRE
      • flag on_a_trouvé_une_bombe = FAUX
      • Parcourir toutes les cases de la grille:
        • si la case est "explosant" et contient une bombe:
          • marquer toutes les cases à sa portée comme "explosant"
          • flag on_a_trouvé_une_bombe = VRAI
          • Supprimer la bombe
        • si la case est "explosant" et contient un perso:
          • tuer le perso
    • TANT QUE flag on_a_trouvé_une_bombe est VRAI
    • Supprimer le marquage "explosant" de toutes les cases.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Nouveau Candidat au Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Février 2018
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lycéen
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2018
    Messages : 2
    Points : 1
    Points
    1
    Par défaut
    Bonjour à tous,

    déjà merci beaucoup pour vos réponses !

    Ensuite j'ai du oublier de le préciser, mais tout les #includes, les variables globales et tout ce que vous m'avez fait remarquer sont donné par le prof et non modifiable, il veut que nous faisions en fonction de son squelette. Je n'ai le droit de modifier que la fonction explosion() et à la limite le main().

    En tout cas merci à tous, je vais prendre le temps d'analyser vos réponses et essayer de réussir !!

    à bientôt !

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Ah, ces profs, qui nous emmerdent à nous forcer d'utiliser du code qui n'a aucun sens, et qui est dangereux!!!!

    Si tu as l'impression que ton prof est "correct" et "honnête" au lieu d'être un "vieux con borné", corrige les erreurs que l'on t'as signalé, d'autant plus que nous avons bien évité, jusqu'à présent (et que l'on peut continuer), de te donner le code réel, et donne lui le lien vers cette discussion...

    Quand il remarquera que tu fais en dix ou en vingt lignes ce que lui fait en cent (ou peu s'en faut), et que tu évites toute une série de problème auxquels lui a été confronté, il sera bien obligé de constater que cette méthode n'a décidément que des avantages, et ne pourra faire autrement que d'accepter ta manière (correcte !!! ) de travailler
    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

  8. #8
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Les variables globales, C'EST MAL...
    Ouais enfin faire une classe static avec des variables static dedans, en théorie c'est plus propre mais en vrai ça revient un peu au même; De plus, si les variables globales sont bien nommées et dans un namespace bien spécifique je vois pas trop le problème. Même si je suis d'accord qu'il faut quand même les éviter au maximum mais quand on a pas d'interface graphique et que l'on débute, avoir une liste de variables globales dans un fichier appart et les utiliser pour paramétrer son application avant de la compiler, c'est pas si mal que ça. (Et je précise bien, quand on débute)


    Citation Envoyé par koala01 Voir le message
    vire la lignes using namespace std;, je t'expliquerai pourquoi si tu le demandes, mais prend l'habitude d'utiliser les noms pleinement qualifié des fonctionnalités issues de la bibliothèque standard (comme std::cout, std::cin, ou std::endl)
    POURQUOI ?


    Citation Envoyé par koala01 Voir le message
    min et max existent déjà dans la bibliothèque standard, dans le fichier d'en-tête <algorithm>, utilise les au lieu de ces horribles macro issues du C. Là aussi, je justifierai mon conseil à la demande
    Je dirais même plus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #define MIN(X,Y) ((X)<=(Y)?(X):(Y)) 
    #define MAX(X,Y) ((X)>=(Y)?(X):(Y))
    Pourquoi ne pas faire une fonction ? Sinon à ce niveau là autant refaire tout tes fonctions en #define, ça n'a auncun sens. Fait des fonctions, généralement, plus ton code en contient, plus il devient lisible.

    Pour le reste je suis d'accord avec vous

  9. #9
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Matthieu76 Voir le message
    Ouais enfin faire une classe static avec des variables static dedans, en théorie c'est plus propre mais en vrai ça revient un peu au même;
    Primo, je n'ai jamais parlé de variables statiques dans une classe

    Secundo, pour moi, c'est exactement du pareil au même, si ce n'est que les données statiques d'une classes sont des globales cachée.
    De plus, si les variables globales sont bien nommées et dans un namespace bien spécifique je vois pas trop le problème.
    Le gros problème vient des deux termes utilisés:
    • Variable: que l'on peut manipuler à son aise, dont on peut changer l'état "comme on veut"
    • globale : auquel on peut accéder depuis n'importe où dans le code.

    Quand tu mets ces deux termes ensemble, tu obtiens donc "dont on peut changer l'état comme on veut depuis n'importe où dans le code"; ce qui implique que tu ne peux faire aucune présomption quant à l'état actuel de cette variable, car il dépent de l'ensemble des processus par lesquels on a pu passer depuis le lancement de l'application.

    Or, le développeur qui manipule une variable (qu'elle soit globale ou non) est, par définition même, un utilisateur de cette variable, et, donc, il est soumis aux mêmes restrictions que n'importe quel utilisateur : c'est un imbécile distrait qui profitera de la moindre opportunité que nous pourrons lui laisser pour faire une connerie.

    Ne perds pas de temps à te demander SI il va faire une connerie, car la réponse sera forcément oui. Ne perds pas d'avantage de temps à te demander si, avec une doc suffisante, tu pourras l'empêcher, car la réponse sera forcément non.

    La seule question qui vaille la peine de se poser c'est "quand va-t-il faire une connerie énorme", et là encore, la réponse est connue : ce sera forcément au pire moment qui soit.

    Alors, je suis tout à fait d'accord sur le fait que l'on n'a parfois pas vraiment d'autre choix. Des variables comme std::cin ou std::cout n'auraient pas pu être autre chose que des globales, même si on peut regretter le fait qu'elles fussent "exposées au public" : on "aurait pu" ne pas les exposer, mais fournir des fonctions comme printnl que l'on trouve dans certains langages

    Mais, il faut se rendre compte que, l'un dans l'autre, std::cin et std::cout agissent exactement comme des types totalement opaques: l'utilisateur de ces données n'a aucun besoin de savoir de quoi elles sont effectivement composées, et doit se contenter de sa connaissance des moyens de les manipuler. L'un dans l'autre, cela empêche l'utilisateur de faire pas mal des conneries qui pourraient lui couter un bras

    Alors, si tu es un développeur suffisamment habitué et suffisamment doué que pour pouvoir concevoir une variable globales avec laquelle l'utilisateur ne pourra faire aucune connerie, et que tu as réellement besoin d'une variable globale, vas-y, utilises la; ce sera sans doute la "moins mauvaise solution".

    Mais gardes en mémoire deux faits importants:
    1. dans le cas présent, je m'adresse à un débutant; mon but est donc de lui donner des conseils simples et faciles à mettre en oeuvre (en évitant toutes les considérations qui ne manquent pas de rendre le problème bien plus complexe
    2. dans le cas présent, les variables globales sont tout sauf d'une utilisation "sécurisante à l'emploi", et, comme il y a facilement moyen de s'en passer, le premier point devait primer

    Même si je suis d'accord qu'il faut quand même les éviter au maximum mais quand on a pas d'interface graphique et que l'on débute, avoir une liste de variables globales dans un fichier appart et les utiliser pour paramétrer son application avant de la compiler, c'est pas si mal que ça. (Et je précise bien, quand on débute)
    Que l'on débute ou que l'on soit chevronné, que l'on utilise une bibliothèque graphique ou non, l'utilisation même de variables globales est une solution qui ne doit être envisagée qu'en dernier recours.

    Quand au paramétrage de l'application, c'est typiquement un domaine encore très particulier, car, a priori, aucun réglage n'a réellement besoin d'être réellement global: le réglage pour le volume sonore n'a, par exemple, aucune raison d'être accessible au module qui s'occupe de l'affichage, et le réglage qui défini la résolution d'écran n'a a priori aucun besoin d'être accessible au module qui s'occupe du son.

    Et l'on pourrait suivre exactement le même raisonnement pour la très grosse majorité des réglages
    POURQUOI ?
    Pour comprendre la raison pour laquelle la directive using namespace std; est une pratique à éviter, il faut comprendre un peu l'histoire de C++:

    Comme beaucoup de langages, C++ a d'abord été la propriété de la société (de télécoms) dans laquelle Strutroup travaillait quand il l'a développé. Cette société a, très vite, pris la décision ("bénie des dieux") de permettre l'utilisation de ce langage "par d'autres".

    Seulement, la bibliothèque standard (développée à l'origine par Stepanov) prenait place dans l'espace de noms global, un peu à l'instar de la bibliothèque standard du C.

    Pendant des années, des développeurs ont donc écrit du code C++ en utilisant la bibliothèque standard qui se trouvait ... dans l'espace de noms global.

    Or, en 1998, la "nouvelle" norme (à l'époque) a décidé que la bibliothèque standard prendrait désormais place dans l'espace de noms std (ce qui est toujours le cas à l'heure actuelle). C'était très bien, parce que l'utilisation d'espaces de noms permet de ranger les différentes fonctionnalités "dans des boîtes", et donc d'éviter pas mal de problèmes (entre autres, lorsque plusieurs bibliothèques utilisent des noms identiques).

    Mais cela posait un problème majeur: il y avait déjà des millions de lignes de code écrites en C++ et pour lesquelles les fonctionnalités de la bibliothèque standard se trouvait dans... l'espace de noms global. Il était donc hors de question d'obliger les développeurs à passer toutes ces lignes de code en revue afin d'y ajouter un std:: partout où c'était nécessaire!

    La meilleure solution que le comité de standardisation a trouvé est de rajouter la fameuse directive using namespace <nom de l'espace de noms>; pour permettre au code existant de continuer à compiler.

    De cette manière, les développeurs pouvaient l'ajouter dans n'importe quel fichier d'en-tête d'usage courant, et profiter de la "viralité" des inclusions en cascade pour que leur "ancien" code compile avec "un minimum d'adaptations".

    Mais cette directive n'a -- a priori -- été créée que pour permettre, en 1998 et dans les quelques années qui ont suivi, à du code plus ancien (datant d'avant 1998) de continuer à compiler. Elle n'a pas du tout été prévue pour permettre aux développeurx de "nouveaux" projets (de projets dont le développement a commencé après 1998) de faire preuve de fainéantise

    Nous sommes, aujourd'hui, en 2018, soit vingt ans après que la bibliothèque standard ait "migré" vers l'espace de noms std. On ne peut décemment pas dire que n'importe quel projet dont le développement commencerait aujourd'hui puisse entré dans la catégorie des "anciens" projets, qui ont été initiés... avant 1998

    En plus, il faut bien te dire que l'utilisation de la directive using namespace ne va pas sans poser un certains nombre de problèmes, entre autres, à cause des inévitables conflits de noms qu'elle peut occasionner.

    Et comme, au final, il ne faut qu'une demi seconde pour ajouter le fameux std:: au code que l'on écrit aujourd'hui, et que cela ne risque absolument pas d'user prématurément le clavier, il est bien plus intéressant de prendre l'habitude de le faire plutôt que de prendre une habitude -- honnie par la profession -- d'utiliser cette directive qui, à mon sens du moins, pourrait tout à fait être rendue obsolète avant d'être purement et simplement supprimée
    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

  10. #10
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Pour compléter un peu la pratique consistant à éviter les "using namespace", je vais raconter une anecdote.

    Un jour, notre projet a eu besoin d'un équivalent de std::array mais utilisait C++03. Pas de problème, on a codé une classe array qu'on a mis dans un namespace à nous (appelons le toto). On était débutants en C++, alors on a mis des using namespace toto;" dans plusieurs fichiers d'en-tête. C'était cool. Un jour, on a utilisé notre code avec Visual Studio, qui définit une classe array non compatible avec toto::array (ni avec std::array d'ailleurs) dans le namespace global. J'ai dû viré tous les using namespace des headers, le projet était petit mais ça a été pénible.

    Ici, c'était toto::array qui posait problème mais ça aurait été pareil avec std::array. Il aurait été le même avec n'importe quel foo::bar qui pourrait rentrer en conflit avec zorg::bar. Ne jamais mettre de using namespace dans un fichier d'en-tête, jamais. Tu ne sais jamais quand ça te pétera à la figure !

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Personne ici n'a jamais objecté à "jamais de using namespace dans un header". Là où selon Matthieu76 et moi ça frise le fanatisme, c'est de chercher à les interdire aussi dans les sources...

    D'ailleurs, le problème du array de Visual Studio n'est pas qu'il est en global: À ma connaissance, il ne l'est pas, mais ses headers contiennent a using namespace cli;...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Avec les différentes solutions de fastbuild, unity builds etc, avoir une telle déclaration dans un cpp est tout autant problématique.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  13. #13
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Personne ici n'a jamais objecté à "jamais de using namespace dans un header". Là où selon Matthieu76 et moi ça frise le fanatisme, c'est de chercher à les interdire aussi dans les sources...
    Ah j'avais compris ça de manière globale !

    Dans les sources, c'est un peu différent, c'est moins contaminant. En même temps, faire des using namespace dans un source, c'est s'exposer à ce qu'un mauvais header vient un jour foutre le bazar... Par soucis d'expliciter, je mets en général le nom complet. Quand ça me fatigue un peu, je préfère faire des choses plus précises comme using std::cout; using toto::array;. Mais c'est peut-être aussi de l'intégrisme

    Citation Envoyé par Médinoc Voir le message
    D'ailleurs, le problème du array de Visual Studio n'est pas qu'il est en global: À ma connaissance, il ne l'est pas, mais ses headers contiennent a using namespace cli;...
    Ah merci ! J'étais jamais allé au bout de la recherche de la cause !

  14. #14
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    A vrai dire, Médinoc, je comprends ton point de vue, et, qui sait, je souffre peut-être d'une certaine forme d'intégrisme sur ce point particulier. Mais, si c'est le cas, je peux te rassurer: je suis prêt à le revendiquer

    Et je suis bien d'accord sur un point : c'est "moins mauvais" d'utiliser la directive using namespace ... ; (quel que soit l'espace de noms envisagé) dans un fichier d'implémentation. Mais...

    Tu le sais aussi bien que moi, C++ compte parmi les langages les plus complexes que l'on puisse trouver. Si bien que, même lorsque l'on essaye de se limiter à des "lignes de conduites" compréhensibles par un débutant, on en vient régulièrement à parler de la règle, d'une exception à la règle, et parfois même encore d'une exception à l'exception de la règle.

    Alors, "pour une fois(*)" que l'on peut gentiment ignorer l'exception à la règle afin de gagner en concision -- et donc, en simplicité -- sans provoquer d'erreur majeure, je crois sincèrement que ca vaut la peine de le faire

    (*) oui, je sais: le terme est volontairement excessif

    Sans oublier le fait que, finalement, que tu le fasse dans un fichier d'en-tête ou dans tes 300 fichiers d'implémentation, tu en reviendra toujours au même point : il suffit d'un en-tête mal foutu (et l'histoire de Bktero, confirmée par tes propres dires est là pour prouver que cela peut aller) pour foutre le bordel dans ... tous tes fichiers d'implémentation.

    Alors, au final, sachant que je ne suis qu'un "malheureux pisseur de code" et que je ne suis pas (par chances pour mon équipe, car elle souffrirait) responsable technique et que, une fois que j'ai exposé mon point de vue, je n'ai encore gagné que le droit de me taire, posons nous sincèrement la question: est-il réellement intéressant d'introduire l'exception, que ce soit au niveau du débutant ou du cheveronné, afin de permettre l'usage de cette directive dans les fichiers d'implémentation

    A titre personnel, j'aurais tendance à dire que non. Mais tu peux bien sur être d'un avis contraire
    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

  15. #15
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut Exception à la règle
    Ouais mais si par exemple (et en par exemple j'entends dans l'un de mes projets perso) j'ai un namespace database avec une classe static Database qui contient une fonction write, je trouve ça "un poil lourd" d'écrire :
    database::Database.write("SELECT * FROM user");

    Surtout que je compte déplacer ce code dans ma bibliothèque tools ce qui donnerait :
    tools::database::Database.write("SELECT * FROM user");Avec une écriture comme ça le code devient rapidement imbitable.

  16. #16
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    using tools::database::Database;
    ?

  17. #17
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut
    Oui, c'est ce que je dis, il faut parfois utiliser les using.



    Ps : On ne pas pas faire de using d'une classe ?

  18. #18
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Mince, j'avais fait une version plus détaillée de mon message mais j'ai raté la publication...

    Je voulais dire que ça te simplifie la vie. Néanmoins, tu t'exposes au même risque que précédemment. Tu réduis la voilure sur les conflits en étant plus précis. C'est comme en Java ou en Python où on te déconseille d'importer tout un package avec * mais uniquement les morceaux qui t'intéressent.

  19. #19
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut
    Ouais dans mon code en gros j'ai 3 namespaces principaux, model, vu et controller et avec les using je vérifie que ma vue n'appelle jamais directement mon model mais qu'elle passe bien par mon controller. Comme ça je suis à peu près garanti de respecter le principe MVC. Le but étant que chaque namespace ne soit appeler qu'une seul fois par un autre namespace ainsi j'ai un seul et unique using namespace database; qui est dans mon fichier databaseManager.cpp qui lui est dans mon namespace controller. Sur mon diagramme UML, je n'ai qu'une seule liaison entre 2 namespaces et c'est beaucoup plus propre et lisible.

  20. #20
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Déjà, un truc qui s'appelle xxxMANAGER, c'est pas l'idéal. Car le terme Manager, c'est particulièrement vague, et que tu en viendra surement à te dire "tiens, je dois faire ceci ou cela avec mon xxx, qui va s'en occuper", et la réponse sera toute trouvée: "ben, mon manager, pardi".

    Sauf que tu vas te poser dix ou vingt fois ce genre de question sur un projet conséquent. Et, au final, tu te retrouvera avec une classe manager, qui s'occupe de dix ou de ving choses différentes, particulièrement monolithique, et à laquelle tu n'oses plus toucher, de peur de "tout casser".

    L'idéal, c'est d'utiliser des termes plus spécifiques à l'usage qui en est fait, comme par exemple:
    • factory, pour tout ce qui a trait à la construction des objets
    • holder, pour tout ce qui a trait au maintien en mémoire et à l'accès aux objets
    • visitor, pour tout ce qui a trait à l'interrogation et à la manipulation polymorphe,
    • importer/exporter/translator, pour tout ce qui permet la transmission / récupération depuis "une autre source"
    • j'en passe, et sans doute de meilleures.

    De cette manière, tu obtiendras des éléments qui ne s'occupent que d'une seule chose, au besoin, en faisant appel à d'autres éléments pour certains aspects spécifiques de leur besoins, et tu pourras faire évoluer les choses "à ta guise" à peu près dans toutes les directions.

    Ensuite, on ne dit pas de ne pas utiliser la directive using, d'autant plus que, depuis C++11, c'est le moyen privilégié de créer des alias de types. On dit de ne pas utiliser la directive using namespace, qui a pour effet d'exposer l'ensemble de l'espace de noms.

    Si, pour une raison ou une autre, tu te retrouve à vouloir exposer quelque chose de ton espace de noms, veille au moins à n'exposer que... ce dont tu as besoin, et non l'espace de noms dans son entièreté!

    Tu veux introduire une partie de ton espace de noms database dans ton espace de noms tools Grand bien de fasse. Mais veille au moins à n'y introduire que ce qui aura du sens! Ainsi, je ne serais pas outré si tu avais un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    namespace tools{
        using database::Database;
    }
    qui permettra à l'utilisateur de ta bibliothèque tools d'écrire un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int main(){
        tools::Database db;
    }
    Et puis, rien ne t'empêche de fournir, dans ton espace de noms tools, des fonctions qui utilisent des fonctionnalités issues de tes espaces de noms "internes", mais qui seront -- à peu de chose près, les seuls "points d'accès" à ces espaces de noms et qui permettront même à l'utilisateur de n'avoir purement et simplement pas conscience de l'existence de ces espaces de noms internes
    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

Discussions similaires

  1. aide projet Mastermind
    Par 0coco0 dans le forum Langage
    Réponses: 14
    Dernier message: 14/01/2008, 09h48
  2. Aide projet Firefox
    Par KKshi666 dans le forum C++
    Réponses: 10
    Dernier message: 20/11/2006, 14h25
  3. Demande d'aide - Projet professionnel ambigu
    Par makechange dans le forum Emploi
    Réponses: 5
    Dernier message: 08/09/2006, 13h34
  4. Besoin d'aide projet d'info : la bonne paye sur C++ Builder.
    Par timsupra dans le forum C++Builder
    Réponses: 18
    Dernier message: 25/04/2006, 10h24
  5. aide projet dev
    Par Nickname dans le forum Langage
    Réponses: 16
    Dernier message: 06/02/2006, 13h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo