Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

C++ : Un langage de programmation puissant, Study Guides, Projects, Research of Computer science

Le livre est divisé en deux parties. La première partie couvre les concepts fondamentaux de la programmation en C++, tels que les variables, les expressions, les instructions de contrôle et les fonctions. La deuxième partie couvre des sujets plus avancés, tels que la programmation orientée objet, la programmation générique et la programmation parallèle.

Typology: Study Guides, Projects, Research

Pre 2010

Uploaded on 09/19/2023

hamza-belkadi
hamza-belkadi 🇲🇦

1 document

Partial preview of the text

Download C++ : Un langage de programmation puissant and more Study Guides, Projects, Research Computer science in PDF only on Docsity! informaticie... mehdidou99 La programmation en C++ moderne 6 mars 2021 0 Table des matières II.6.7. Convention de nommage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 II.6.8. Contrôler plus finement l’exécution de la boucle . . . . . . . . . . . . . . . . 92 II.6.8.1. break—Je m’arrête là . . . . . . . . . . . . . . . . . . . . . . . . . . 92 II.6.8.2. continue—Saute ton tour! . . . . . . . . . . . . . . . . . . . . . . . 94 II.6.8.3. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 II.7. Au tableau ! 101 II.7.1. Un tableau c’est quoi? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 II.7.2. std::vector—Mais quel dynamisme! . . . . . . . . . . . . . . . . . . . . . . . 101 II.7.2.1. Déclarer un std::vector . . . . . . . . . . . . . . . . . . . . . . . . 101 II.7.2.2. Manipuler les éléments d’un std::vector . . . . . . . . . . . . . . . 103 II.8. Accès aux éléments 104 II.8.1. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 II.8.1.1. Calcul de moyenne . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 II.8.1.2. Minimum et maximum . . . . . . . . . . . . . . . . . . . . . . . . . . 112 II.8.1.3. Séparer les pairs des impairs . . . . . . . . . . . . . . . . . . . . . . . 113 II.8.1.4. Compter les occurrences d’une valeur . . . . . . . . . . . . . . . . . . 113 II.8.2. std::array—Le tableau statique . . . . . . . . . . . . . . . . . . . . . . . . . 113 II.8.2.1. Déclarer un std::array . . . . . . . . . . . . . . . . . . . . . . . . . 113 II.8.2.2. Remplir un tableau . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 II.8.2.3. Accéder aux éléments . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 II.8.2.4. Connaître la taille . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 II.8.2.5. Vérifier si le tableau est vide . . . . . . . . . . . . . . . . . . . . . . . 116 II.8.3. std::string—Un type qui cache bien son jeu . . . . . . . . . . . . . . . . . . . 117 II.8.3.1. Connaître la taille d’une chaîne . . . . . . . . . . . . . . . . . . . . . 117 II.8.3.2. Accéder à un caractère . . . . . . . . . . . . . . . . . . . . . . . . . . 118 II.8.3.3. Premier et dernier caractère . . . . . . . . . . . . . . . . . . . . . . . 118 II.8.3.4. Vérifier qu’une chaîne est vide . . . . . . . . . . . . . . . . . . . . . . 119 II.8.3.5. Ajouter ou supprimer un caractère à la fin . . . . . . . . . . . . . . . 119 II.8.3.6. Supprimer tous les caractères . . . . . . . . . . . . . . . . . . . . . . 120 II.8.3.7. Boucler sur une chaîne . . . . . . . . . . . . . . . . . . . . . . . . . . 120 II.8.3.8. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 II.9. Déployons la toute puissance des conteneurs 126 II.9.1. Le socle de base: les itérateurs . . . . . . . . . . . . . . . . . . . . . . . . . . 126 II.9.1.1. Déclaration d’un itérateur . . . . . . . . . . . . . . . . . . . . . . . . 126 II.9.1.2. Début et fin d’un conteneur . . . . . . . . . . . . . . . . . . . . . . . 127 II.9.1.3. Accéder à l’élément pointé . . . . . . . . . . . . . . . . . . . . . . . . 127 II.9.1.4. Se déplacer dans une collection . . . . . . . . . . . . . . . . . . . . . 128 II.10. Déplacement vers l’élément suivant 129 II.10.0.1. const et les itérateurs . . . . . . . . . . . . . . . . . . . . . . . . . . 131 II.10.0.2. Itérer depuis la fin . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 II.10.0.3. Utilisation conjointe avec les conteneurs . . . . . . . . . . . . . . . . 134 II.10.1. Des algorithmes à gogo! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 II.10.1.1. std::count—Compter les occurrences d’une valeur . . . . . . . . . . 135 3 Table des matières II.10.1.2. std::find—Trouver un certain élément . . . . . . . . . . . . . . . . 136 II.10.1.3. std::sort—Trier une collection . . . . . . . . . . . . . . . . . . . . 138 II.10.1.4. std::reverse—Inverser l’ordre des éléments d’une collection . . . . 139 II.10.1.5. std::remove—Suppression d’éléments . . . . . . . . . . . . . . . . . 140 II.10.1.6. std::search—Rechercher un sous-ensemble dans un ensemble . . . 140 II.10.1.7. std::equal—Vérifier l’égalité de deux ensembles . . . . . . . . . . . 141 II.10.1.8. Et tant d’autres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 II.10.2. Personnalisation à la demande . . . . . . . . . . . . . . . . . . . . . . . . . . 142 II.10.2.1. Le prédicat, à la base de la personnalisation des algorithmes . . . . . 142 II.10.2.2. Trier une liste dans l’ordre décroissant . . . . . . . . . . . . . . . . . 142 II.10.2.3. Somme et produit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 II.10.2.4. Prédicats pour caractères . . . . . . . . . . . . . . . . . . . . . . . . . 144 II.10.3. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 II.10.3.1. Palindrome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 II.10.3.2. string_trim—Suppression des espaces . . . . . . . . . . . . . . . . 146 II.10.3.3. Couper une chaîne . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 II.10.3.4. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 II.11. Des flux dans tous les sens 152 II.11.1. Avant-propos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 II.11.1.1. Prendrez-vous une extension? . . . . . . . . . . . . . . . . . . . . . . 152 II.11.1.2. Vois sur ton chemin… . . . . . . . . . . . . . . . . . . . . . . . . . . 153 II.11.1.3. Un mot sur Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 II.11.1.4. Pas d’interprétation, on est des brutes . . . . . . . . . . . . . . . . . 154 II.11.2. std::ofstream—Écrire dans un fichier . . . . . . . . . . . . . . . . . . . . . . 154 II.11.2.1. Ouvrir le fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 II.11.2.2. Écriture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 II.11.2.3. Ouvrir sans effacer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 II.11.3. std::ifstream—Lire dans un fichier . . . . . . . . . . . . . . . . . . . . . . . . 159 II.11.3.1. Ouvrir le fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 II.11.3.2. Lecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 II.11.3.3. Tout lire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 II.11.4. Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 II.11.4.1. Statistiques sur des fichiers . . . . . . . . . . . . . . . . . . . . . . . . 163 II.11.5. Encore plus de flux! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 II.11.5.1. Un flux c’est quoi? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 II.11.5.2. Un buffer dites-vous? . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 II.11.5.3. Les modificateurs de flux . . . . . . . . . . . . . . . . . . . . . . . . . 165 II.11.5.4. Même les chaînes y passent! . . . . . . . . . . . . . . . . . . . . . . . 166 II.11.5.5. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 4 Table des matières III. On passe la deuxième ! 171 III.1. Découpons du code — Les fonctions 173 III.1.1. Les éléments de base d’une fonction . . . . . . . . . . . . . . . . . . . . . . . 173 III.1.1.1. Une fonction, c’est quoi? . . . . . . . . . . . . . . . . . . . . . . . . . 173 III.1.1.2. Une fonction bien connue . . . . . . . . . . . . . . . . . . . . . . . . . 175 III.1.1.3. Les composants d’une fonction . . . . . . . . . . . . . . . . . . . . . . 175 III.2. Schéma d’une fonction 176 III.2.1. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 III.2.1.1. Afficher un rectangle . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 III.2.1.2. Distributeur d’argent . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 III.2.1.3. Parenthésage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 III.2.2. Quelles sont vos références? . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 III.2.2.1. La problématique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 III.2.2.2. Les références . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 III.2.2.3. Paramètres de fonctions . . . . . . . . . . . . . . . . . . . . . . . . . 184 III.2.2.4. Valeur de retour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 III.2.2.5. Un mot sur la déduction de type . . . . . . . . . . . . . . . . . . . . 188 III.2.3. Nos fonctions sont surchargées! . . . . . . . . . . . . . . . . . . . . . . . . . 190 III.2.4. [T.P] Gérer les erreurs d’entrée—Partie III . . . . . . . . . . . . . . . . . . . 191 III.2.5. Dessine-moi une fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 III.2.5.1. Le problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 III.2.5.2. La solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 III.2.5.3. Utilisons les prototypes . . . . . . . . . . . . . . . . . . . . . . . . . . 194 III.2.5.4. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 III.3. Erreur, erreur, erreur… 201 III.3.1. L’utilisateur est un idiot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 III.3.2. À une condition… ou plusieurs . . . . . . . . . . . . . . . . . . . . . . . . . . 202 III.3.2.1. Contrats assurés par le compilateur . . . . . . . . . . . . . . . . . . . 202 III.4. Le typage 203 III.4.0.1. Vérifier nous-mêmes . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 III.4.1. Le développeur est un idiot . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 III.4.1.1. Préconditions et assertions . . . . . . . . . . . . . . . . . . . . . . . . 206 III.4.2. Les tests unitaires à notre aide . . . . . . . . . . . . . . . . . . . . . . . . . . 207 III.4.2.1. Pourquoi tester? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 III.4.2.2. Un test unitaire, qu’est-ce que c’est? . . . . . . . . . . . . . . . . . . 207 III.4.2.3. Écrire des tests unitaires . . . . . . . . . . . . . . . . . . . . . . . . . 208 III.4.2.4. Les tests unitaires et les postconditions . . . . . . . . . . . . . . . . . 209 III.4.3. [T.P] Gérer les erreurs d’entrée—Partie IV . . . . . . . . . . . . . . . . . . . 209 III.4.4. L’exception à la règle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 III.4.4.1. La problématique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 III.4.4.2. C’est quoi une exception? . . . . . . . . . . . . . . . . . . . . . . . . 212 III.4.4.3. Lancement des exceptions dans 3, 2, 1… . . . . . . . . . . . . . . . . . 212 III.4.4.4. Attends que je t’attrape! . . . . . . . . . . . . . . . . . . . . . . . . . 214 III.4.4.5. Attrapez-les tous! . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 5 Table des matières III.11.4. Les avantages du découpage en fichiers . . . . . . . . . . . . . . . . . . . . . 358 III.11.4.1. Une structure de projet plus visible . . . . . . . . . . . . . . . . . . . 358 III.11.4.2. Une meilleure abstraction . . . . . . . . . . . . . . . . . . . . . . . . 358 III.11.4.3. Une meilleure modularité . . . . . . . . . . . . . . . . . . . . . . . . . 359 III.11.5. Le cas des templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 III.11.5.1. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 IV. Interlude - Être un développeur 386 IV.1. Avant-propos 388 IV.1.1. Ce que nous avons appris . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 IV.1.2. Différents paradigmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 IV.1.2.1. Le paradigme impératif . . . . . . . . . . . . . . . . . . . . . . . . . . 389 IV.1.2.2. Le paradigme fonctionnel . . . . . . . . . . . . . . . . . . . . . . . . . 390 IV.1.2.3. Le paradigme générique . . . . . . . . . . . . . . . . . . . . . . . . . 391 IV.1.2.4. La programmation par contrat . . . . . . . . . . . . . . . . . . . . . . 392 IV.1.3. Brancher le cerveau avant tout . . . . . . . . . . . . . . . . . . . . . . . . . . 393 IV.1.4. Savoir se débrouiller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 IV.1.4.1. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 IV.2. Mais où est la doc ? 396 IV.2.1. Lire une page de doc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 IV.2.1.1. À l’arrivée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 IV.2.1.2. vector − Retour sur le plus célèbre des conteneurs . . . . . . . . . . 397 IV.3. Présentation 398 IV.3.0.1. Les algorithmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 IV.3.0.2. Les chaînes de caractère au grand complet . . . . . . . . . . . . . . . 401 IV.3.1. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 IV.3.1.1. Remplacer une chaîne de caractère par une autre . . . . . . . . . . . 402 IV.3.1.2. Norme d’un vecteur . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 IV.3.1.3. Nombres complexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 IV.3.1.4. Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 IV.3.2. Documenter son code avec Doxygen . . . . . . . . . . . . . . . . . . . . . . . 404 IV.3.2.1. Installation des outils . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 IV.3.2.2. Écrire la documentation . . . . . . . . . . . . . . . . . . . . . . . . . 408 IV.3.3. Quelques bonnes pratiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 IV.3.3.1. Ce qu’il faut documenter . . . . . . . . . . . . . . . . . . . . . . . . . 415 IV.3.3.2. Les fichiers d’en-tête ou source? . . . . . . . . . . . . . . . . . . . . . 415 IV.3.3.3. Commentaire vs documentation . . . . . . . . . . . . . . . . . . . . . 416 IV.3.3.4. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419 IV.4. Compilation en cours… 423 IV.4.1. Le préprocesseur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423 IV.4.1.1. Inclure des fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423 IV.4.1.2. Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423 8 Table des matières IV.4.1.3. Debug ou release? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424 IV.4.2. La compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426 IV.4.2.1. Les templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426 IV.4.2.2. constexpr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 IV.4.2.3. La compilation à proprement parler . . . . . . . . . . . . . . . . . . . 429 IV.4.2.4. Une étape intermédiaire cachée . . . . . . . . . . . . . . . . . . . . . 430 IV.4.2.5. Influer sur la compilation . . . . . . . . . . . . . . . . . . . . . . . . . 431 IV.4.3. Le linker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436 IV.4.3.1. Une question de symboles . . . . . . . . . . . . . . . . . . . . . . . . 437 IV.4.4. Schéma récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440 IV.4.4.1. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 IV.5. Chasse aux bugs ! 443 IV.5.1. Le principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 IV.5.2. Un code d’exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 IV.5.3. Visual Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 IV.5.3.1. Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 IV.5.3.2. Pas-à-pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447 IV.5.3.3. Point d’arrêt conditionnel . . . . . . . . . . . . . . . . . . . . . . . . 448 IV.5.4. Qt Creator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 IV.5.4.1. Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 IV.5.4.2. Pas-à-pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 IV.5.4.3. Point d’arrêt conditionnel . . . . . . . . . . . . . . . . . . . . . . . . 452 IV.5.4.4. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 IV.5.5. En ligne de commande avec gdb . . . . . . . . . . . . . . . . . . . . . . . . . 454 IV.5.5.1. Poser un point d’arrêt . . . . . . . . . . . . . . . . . . . . . . . . . . 454 IV.5.5.2. Supprimer des points d’arrêt . . . . . . . . . . . . . . . . . . . . . . . 455 IV.5.5.3. Désactiver des points d’arrêt . . . . . . . . . . . . . . . . . . . . . . . 455 IV.5.5.4. Afficher l’état d’une variable . . . . . . . . . . . . . . . . . . . . . . . 456 IV.5.5.5. Pas-à-pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456 IV.5.5.6. Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 IV.5.5.7. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 IV.5.5.8. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 IV.6. Une foule de bibliothèques 459 IV.6.1. Quelles bibliothèques choisir? . . . . . . . . . . . . . . . . . . . . . . . . . . 459 IV.6.1.1. Boost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 IV.6.1.2. SFML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 IV.6.2. Généralités . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 IV.6.2.1. Statique ou dynamique? . . . . . . . . . . . . . . . . . . . . . . . . . 460 IV.6.2.2. Debug ou release? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 IV.6.3. Installer Boost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 IV.6.3.1. GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 IV.6.3.2. Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 IV.6.3.3. Tester l’installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464 IV.6.4. Installer SFML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 IV.6.4.1. GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 IV.6.4.2. Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467 9 Table des matières IV.6.4.3. Tester l’installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470 IV.6.4.4. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 IV.7. Améliorer ses projets 473 IV.7.1. git—Sauvegarder et versionner son code . . . . . . . . . . . . . . . . . . . . 473 IV.7.1.1. La problématique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 IV.7.1.2. Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 IV.7.1.3. Initialiser git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 IV.7.1.4. Créer un dépôt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 IV.7.1.5. Connaître l’état de ses fichiers . . . . . . . . . . . . . . . . . . . . . . 475 IV.7.1.6. Ajouter un fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476 IV.7.1.7. Valider les modifications . . . . . . . . . . . . . . . . . . . . . . . . . 477 IV.7.1.8. Voir l’historique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478 IV.7.1.9. Bloquer certains fichiers . . . . . . . . . . . . . . . . . . . . . . . . . 478 IV.7.1.10. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480 IV.7.1.11. Visual Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480 IV.7.2. GitHub—Partager son code . . . . . . . . . . . . . . . . . . . . . . . . . . . 481 IV.7.2.1. La problématique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481 IV.7.2.2. Création d’un projet . . . . . . . . . . . . . . . . . . . . . . . . . . . 482 IV.7.2.3. Récupérer localement les modifications . . . . . . . . . . . . . . . . . 484 IV.7.2.4. Pousser nos modifications . . . . . . . . . . . . . . . . . . . . . . . . 485 IV.7.2.5. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486 IV.7.3. CMake—Automatiser la compilation de nos programmes . . . . . . . . . . . 486 IV.7.3.1. La problématique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486 IV.7.3.2. Un exemple simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487 IV.7.3.3. Lier des bibliothèques externes . . . . . . . . . . . . . . . . . . . . . . 491 IV.7.3.4. Définir des variables au lancement . . . . . . . . . . . . . . . . . . . . 504 IV.7.3.5. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 IV.7.4. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 IV.7.4.1. TravisCI—De l’intégration continue . . . . . . . . . . . . . . . . . . . 504 IV.7.4.2. CppCheck—Vérification du code . . . . . . . . . . . . . . . . . . . . . 505 IV.7.4.3. StackOverflow—La réponses à quasiment toutes les questions . . . . . 506 IV.7.4.4. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507 V. La Programmation Orientée Objet 515 V.1. Premiers pas avec la POO 517 V.1.1. Le principe: des objets bien serviables . . . . . . . . . . . . . . . . . . . . . . 517 V.1.1.1. Le principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 V.2. Penser en terme de données… 518 V.2.0.1. Exemple concret . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 V.2.1. Un peu de vocabulaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 V.2.2. En C++, ça donne quoi? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 V.2.2.1. Penser services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 V.2.2.2. Penser tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 V.2.2.3. Définition de la classe . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 10 Table des matières sera mis sur la rigueur, la qualité et les bonnes pratiques. Le rythme sera progressif, chaque concept étant introduit en temps voulu et en lien avec ce que nous aurons déjà vu. i Prérequis Prérequis Lire cette introduction à la programmation afin d’avoir des bases pour aborder l’ap- prentissage du C++. Objectifs Vous former à la programmation en vous donnant des bases solides sur lesquelles continuer. Vous former au C++ moderne. 13 Première partie Remerciements 14 I. Remerciements Car ce cours n’aurait jamais pu voir le jour sans l’aide et le soutien de plusieurs personnes. — Un merci particulier à @gbdivers pour son cours Débuter en C++ moderne qui aura été une source d’inspiration pour l’écriture du présent cours, à qui nous avons emprunté plusieurs passages très bien écrits et qui n’aura cessé de nous aider à améliorer ce cours par ses nombreuses remarques et suggestions. — Tous les membres qui ont participé à la bêta et qui ont grandement aidé à améliorer la qualité de ce tutoriel, par leurs nombreuses remarques, suggestions et corrections. Toutes vos participations, petites et grandes, nous ont été extrêmement précieuses et utiles pour produire un cours meilleur. — Toute l’équipe de Zeste de Savoir; en particulier, un grand merci à @Taurre et @Glordim qui se sont chargés de la validation. — Et l’ensemble des lecteurs, pour avoir choisi ce cours. ! À venir La partie POO est toujours en rédaction. Les mises à jour viendront au fil de l’eau. 15 II.1. Le C++, qu’est-ce que c’est ? Voilà, vous êtes décidés, vous voulez apprendre à programmer à l’aide du langage C++. Mais vous devez toujours avoir quelques questions qui trottent dans votre esprit. — Concrètement, C++, c’est quoi? — Et puis pourquoi commencer par C++? — Que vais-je savoir faire en sortant de ce tutoriel? — Il y a-t-il des conditions, des prérequis, pour pouvoir suivre ce cours? II.1.1. Petite mise au point J’ai indiqué en introduction que le seul prérequis était de lire l’introduction à la programmation et c’est vrai. Mais si peu de connaissances sont nécessaires pour comprendre tout ce qui sera dit, cela ne veut pas dire pour autant que ce sera du tout cuit, prémâché, directement dans la bouche. C’est pour cela que je veux prendre quelques minutes pour clarifier ceci. II.1.1.1. Développer, unmétier à part entière Eh oui! Créer des logiciels, c’est un métier. D’ailleurs, il y a mêmes des écoles et des études spécialisées pour ça. C’est que développer, ce n’est pas simplement écrire du code. Il y a aussi des phases de réflexion, de conceptions, d’écriture, de validation, de tests, de réécriture d’anciennes portions, etc. Par ailleurs, même si cela n’est pas directement lié à la programmation, peut également s’ajouter à cela: la gestion de base de données, l’usage du réseau, le management, la gestion de projet, etc. En bref, être développeur c’est beaucoup de compétences différentes dans des domaines variés. La cruelle vérité qui se cache derrière tout ça, c’est que ce cours ne fera pas de vous des experts, ni des développeurs professionnels. Par contre, une fois fini, vous aurez des bases solides pour continuer votre apprentissage. La route du savoir est infinie. II.1.1.2. Votre part du travail Le cours est écrit de façon à être le plus clair possible, sans vous noyer sous un flot de détails et d’explications, mais il arrivera parfois que vous ne compreniez pas un morceau de code ou une explication. C’est tout à fait normal, ça fait partie de l’apprentissage. Reprenez le cours à tête reposée, aidez-vous de schémas ou de dessins, demandez de l’aide sur les forums , et vous ne resterez jamais bloqués longtemps. 18 II. Le début du voyage Par contre, il faut être prêt à fournir des efforts de votre côté. Cela signifie ne pas se ruer sur les forums au bout de quelques minutes, sans même avoir essayé de trouver une solution. II.1.1.3. Les mathématiques, indispensables ? Une des grandes appréhensions, qui revient régulièrement dans la bouche des débutants, est de savoir si les mathématiques sont un prérequis à l’apprentissage de la programmation. La réponse est non. Il est tout à fait possible d’apprendre à programmer tout en ayant un faible niveau en mathématique. Ce cours ne demande aucune connaissance en mathématiques plus poussées que les opérations de base et, quelques fois, l’utilisation de sinus et cosinus, en guise d’exemples. Bien sûr, certains aspects de la programmation, comme la sécurité, la cryptographie ou les applications scientifiques vont demander un bagage mathématique solide. Mais cela ne rentre pas dans le cadre de ce cours. II.1.1.4. L’anglais, indispensable ? À strictement parler, dans le cadre de ce cours, pas besoin de savoir parler anglais. Même si nous examinerons régulièrement de la documentation écrite dans la langue de Shakespeare, je serai là pour donner des explications et éclaircissements. Et quand bien même il y aurait quelque chose sur lequel vous butez, vous pouvez vous servir d’un traducteur automatique. D’un point de vue plus général, si vous souhaitez continuer dans l’informatique et la pro- grammation, il sera très difficile d’échapper à l’anglais. Beaucoup de cours, de documents, de forums sont en anglais, ou en font un usage massif. L’anglais est tout simplement la langue de l’informatique. Après, sachez que l’anglais informatique est simple à comprendre, car souvent écris par des gens dont l’anglais n’est pas la langue maternelle. Ainsi, inutile d’être bilingue, un bon dictionnaire ou un traducteur vous aideront. II.1.2. Tour d’horizon du C++ II.1.2.1. L’histoire du C++ Faisons un plongeon dans l’histoire et revenons dans les années 1970. À cette époque, Dennis Ritchie , programmeur aux laboratoires AT&T aux États-Unis, invente le langage C , conçu pour programmer le système d’exploitation UNIX. Ce langage devint très populaire à tel point qu’il est encore beaucoup utilisé aujourd’hui, dans l’écriture de Linux par exemple. Puis un peu plus tard, au début des années 1980, Bjarne Stroustrup , lui aussi développeur aux laboratoires AT&T, décida de prendre le langage C comme base et de lui ajouter des fonctionalités issues d’un autre langage appelé Simula. Ce langage devint alors le C with classes. Finalement, en 1983, son créateur, estimant que le nom de son langage était trop réducteur aux vues de tous les ajouts faits par rapport au C, décida de le renommer C++. Mais l’histoire ne s’arrête pas là. Au contraire, le C++ continue d’évoluer à tel point qu’on décide au début des années 1990 de le normaliser, c’est-à-dire d’en établir les règles officielles. Ce travail de longue 19 II. Le début du voyage haleine s’acheva en 1998; cette version est ainsi souvent nommée C++98. Ensuite, en 2003, des corrections ont été apportées et l’on obtint C++03. Puis de nouveau un chantier titanesque est mis en place pour améliorer encore plus le C++, ce qui aboutit 8 ans plus tard, en 2011, à la sortie de C++11, jugée par beaucoup de développeurs comme étant la renaissance du C++. Ensuite, de nouvelles corrections et quelques ajustements ont été apportés pour donner C++14. Enfin, à l’heure actuelle, la norme C++17, nouvelle version majeure et apportant tout un lot de choses intéressantes, est sortie en fin d’année et C++20 est déjà en chantier. i Point vocabulaire Beaucoup de programmeurs utilisent le terme «C++ historique» pour désigner les normes C++98 et C++03 et le terme «C++ moderne» pour parler de C++11 et au-delà. II.1.2.2. Pourquoi apprendre le C++ ? — Sa popularité: le C++ est un langage qui est utilisé dans de nombreux projets important (citons Libre Office , 7-zip ou encore KDE ). Il est au programme de beaucoup de formations informatiques. Il possède une communauté très importante, beaucoup de documentation et d’aide, surtout sur l’internet anglophone. — Sa rapidité: C++ offre un grand contrôle sur la rapidité des programmes. C’est cette caractéristique qui fait de lui un des langages de choix pour les programmes scientifiques, par exemple. — Sa facilité d’apprentissage: depuis sa version de 2011, C++ est beaucoup plus facile à apprendre que par le passé. Et ça tombe bien, c’est sur cette version et les suivantes que va se baser ce cours. — Son ancienneté: C++ est un langage ancien d’un point de vue informatique (30 ans, c’est énorme), ce qui donne une certaine garantie de maturité, de stabilité et de pérennité (il ne disparaîtra pas dans quelques années). — Son évolution: C++11 est un véritable renouveau de C++, qui le rend plus facile à utiliser et plus puissant dans les fonctionnalités qu’il offre aux développeurs. C++14 et C++17 améliorent encore la chose. — Il est multi-paradigme: il n’impose pas une façon unique de concevoir et découper ses programmes mais laisse le développeur libre de ses choix, contrairement à d’autres langages comme Java ou Haskell . Bien entendu, tout n’est pas parfait et C++ a aussi ses défauts. — Son héritage du C: C++ est un descendant du langage C, inventé dans les années 1970. Certains choix de conception, adaptés pour l’époque, sont plus problématiques aujourd’hui, et C++ les traine avec lui. — Sa complexité: il ne faut pas se le cacher, avoir une certaine maîtrise du C++ est très long et demandera des années d’expérience, notamment parce que certaines des fonctionnalités les plus puissantes du C++ requièrent de bien connaître les bases. — Sa bibliothèque standard: bien qu’elle permette de faire beaucoup de choses (et d’ailleurs, nous n’aurons même pas le temps d’en faire un tour complet dans ce cours), elle n’offre pas de mécanisme natif pour manipuler des bases de données, faire des 20 II. Le début du voyage II.2.1.0.1. Survol de Wandbox Figure II.2.1. – L’interface de Wandbox. 1. En haut à gauche, dans un encart vert, c’est le langage de programmation utilisé. Si un autre nom que C++ est écrit, pas de soucis, il suffit de cliquer sur la liste déroulante en dessous, puis sur «C++» et choisir «GCC HEAD» ou «Clang HEAD» (qui sont les toutes dernières versions de ces compilateurs). 2. Un peu plus bas, la liste déroulante commençant par C++ permet de choisir la version du langage. Dans ce tutoriel, nous utiliserons la version «C++17», qui correspond à la version 2017 du langage. Que vous choisissiez «C++17» ou «C++17 (GNU)», cela n’a aucune importance à notre niveau. 3. La grande zone de texte blanche est là où nous écrirons le code. 4. Enfin, le bouton Run (or Ctrl + Enter) servira à lancer le compilateur et lui faire compiler le code écrit dans l’encadré précédent. 5. Quand la compilation est terminée, le résultat apparait ici. II.2.2. Des outils plus poussés Les outils en ligne sont très bien pour des petits codes rapides ou pour faire quelques tests, mais ils sont quand même limités. Sachez qu’il existe cependant des outils très complets tant pour Windows que pour GNU/Linux. Comme mentionné dans le cours d’introduction à la programmation , on peut utiliser un ensemble d’outils et de logiciels différents ou bien utiliser un IDE. 23 II. Le début du voyage II.2.2.1. Visual Studio Community L’IDE par excellence de Microsoft, qui permet de programmer non seulement en C++, mais aussi en Python, en JavaScript, en C#, etc. Configurable, extensible, léger par défaut dans sa version 2019, il est en plus 100% gratuit dans le cadre de l’apprentissage, de la recherche ou des projets open source. Vous n’aurez donc pas besoin de débourser quoi que ce soit pour l’utiliser. Inconvénient? Il n’est disponible que pour Windows (dans sa version 7 au minimum). Pour le télécharger et l’installer, je vous invite à suivre la documentation fournie par Microsoft . L’installation demande une connexion Internet. Figure II.2.2. – Vérifiez que la case C++ est bien cochée. Une fois que Visual Studio est installé pour la première fois et configuré, on arrive sur l’écran d’accueil. Figure II.2.3. – L’écran d’accueil de Visual Studio 2019. On peut directement créer un nouveau projet, ou bien aller directement à la page principale, vide. 24 II. Le début du voyage Figure II.2.4. – La page principale de Visual Studio 2019 est bien vide. Que l’on choisisse de créer directement un nouveau projet, ou bien que, depuis la page d’accueil, on clique sur Fichier -> Nouveau -> Projet… , on se retrouve sur le même écran. Figure II.2.5. – On a le choix de créer tout un tas de projets différents. 25 II. Le début du voyage II.2.2.2. Qt Creator ! Non supporté Nous vous proposons ci-dessous Qt Creator car c’est un autre poids-lourd des IDE, mais aucun de nous deux ne l’utilise ni ne saurait vous aider en cas de problème avec. Les explications qui suivent seront peut-être périmées ou inexactes. Nous en sommes désolé, mais cela demande beaucoup de travail que de les maintenir constamment à jour. Vous pourrez néanmoins trouver un tutoriel français ici , sur le site de @gbdivers, un spécialiste de Qt. Un autre grand IDE pour programmer en C++ se nomme Qt Creator , disponible sous Windows, MacOS et GNU/Linux. Il est fourni par une compagnie du nom de Qt, qui édite également une bibliothèque C++ très populaire et répandue, que vous aurez peut-être l’occasion de croiser ou d’apprendre une fois ce cours terminé. Téléchargez la version Open Source, puis installez-la. Sélectionnez la dernière version de Qt disponible et, dans Tools, prenez la version la plus à jour de MinGW. L’installation peut être plus ou moins longue, en fonction de la qualité de votre connexion Internet notamment. Figure II.2.10. – Voici l’écran d’accueil, au lancement de Qt Creator. Pour créer un nouveau projet, cliquez sur Fichier -> Nouveau fichier ou projet… , puis dans Projets -> Non-Qt Project -> Plain C + Application . 28 II. Le début du voyage Figure II.2.11. – Écran de choix du projet. Cliquez ensuite sur Choose . L’écran d’après vous demande le nom du projet et où il sera localisé. 29 II. Le début du voyage Figure II.2.12. – Choix du nom et de la localisation du projet. Sur les écrans d’après, laissez les choix par défaut et cliquez à la fin sur Terminer . Ouvrez enfin le fichier se terminant par .pro et ajouter la première ligne pour une version de Qt inférieur à 5.12, la deuxième à partir de Qt 5.12. Avant Qt 5.12 1 CONFIG += c++1z À partir de Qt 5.12 1 CONFIG += c++17 II.2.2.3. Pour les autres outils Si vous souhaitez utiliser un autre outil que ceux cités plus haut, vous pouvez, bien entendu. Par contre, vous devrez vous débrouiller pour le configurer, car on ne peut malheureusement 30 II.3. Rencontre avec le C++ Que diriez-vous de rentrer directement dans le vif du sujet en écrivant votre premier code C++? Nous allons commencer par l’un des exemples les plus connus et les plus utilisés: afficher un message. Et, vous verrez, il y a déjà de quoi dire. II.3.1. Compilons notre premier programme Allez donc sur Wandbox , ou bien ouvrez votre projet C++, et copiez-collez ce code dans la zone de texte. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Hello World !" << std::endl; // affiche Hello World ! 6 return 0; 7 } Cliquez ensuite sur Run (pour WandBox), faites Ctrl + F5 (Visual Studio Community), Ctrl + R (Qt Creator), ou compilez et exécutez en ligne de commande, et sous vos yeux émerveillés s’affiche le résultat suivant. 1 Hello World ! Félicitations, vous venez de compiler votre tout premier programme C++! Mais je devine que vous voulez comprendre ce qui s’est passé et avoir des explications sur ce que signifie ce code. 33 II. Le début du voyage II.3.2. Démystification du code II.3.2.1. Inclure des fonctionnalités déjà codées 1 #include <iostream> Le but de notre programme est d’afficher un message. Des développeurs experts ont déjà créé un outil qui permet de le faire facilement. Il se trouve dans un fichier nommé «iostream», acronyme de «Input Output Stream», soit «Flux d’Entrées Sorties» dans la langue de Molière. Ce fichier fait partie de la bibliothèque standard C++, un ensemble de fonctionnalité déjà pré-codées et incluses partout avec chaque compilateur C++. Pour utiliser les fonctionnalités offertes par ce fichier, notamment écrire un message, on doit l’importer dans notre programme. On dit qu’on l’inclut, d’où l’anglais «include». Nous utiliserons beaucoup cette fonctionnalité tout au long du cours. Enfin, dernière remarque, avez-vous noté que la ligne commence par le symbole #? C’est ce qu’on appelle une directive de préprocesseur. Le préprocesseur est un programme qui se lance automatiquement au début de la compilation, notamment pour importer les fichiers qu’on lui demande. Nous le détaillerons plus loin dans ce cours. Retenez que #include nous permet d’importer des fichiers que des programmeurs experts ont déjà écrits avant nous. II.3.2.2. Le point d’entrée 1 int main() 2 { 3 4 } Quant l’ordinateur exécute un programme, il lui faut bien un endroit où commencer, un début, un point d’entrée. À partir de ce point d’entrée, il exécutera des instructions, des ordres, que nous aurons au préalable écrits. Cet endroit s’appelle main (prononcé «mèïne») et est la fonction principale de tout programme C++. Qu’est-ce qu’une fonction? C’est un un regroupement d’instructions. En C++, vous trou- verez ainsi des fonctions pour calculer une racine carrée, pour comparer des durées, trier une liste d’objets, afficher des messages, etc. Nous en utiliserons beaucoup déjà existantes et, plus tard, apprendrons à créer nos propres fonctions. Dans notre cas, la fonction main regroupe deux instructions différentes. 34 II. Le début du voyage II.3.2.3. Voici mes instructions… 1 std::cout << "Hello World !" << std::endl; // Affiche le message Hello World ! La première instruction est justement celle qui nous permet d’afficher un message. Elle débute avec std::cout (à prononcer «ci-aoûte»), qui représente la sortie standard en C++, c’est-à-dire la communication du programme vers l’utilisateur, par l’écran dans notre cas. Le préfixe std:: indique que vous utilisez une fonctionnalité déjà programmée et fournie dans la bibliothèque standard C++. On note ensuite la présence de deux chevrons < qui permettent d’injecter, d’envoyer, du contenu dans la sortie standard, dans std::cout. Dans notre code d’introduction, nous injectons deux choses. — D’abord, "Hello World !", qui est le message que l’on voit s’afficher à l’écran. — Puis std::endl, qui permet d’aller à la ligne, comme son nom l’indique («end line» que l’on traduit par «retour à la ligne»). De même que pour std::cout, std::endl est fourni par la bibliothèque standard. Enfin, elle se termine par un point-virgule ; qui est obligatoire. Chaque instruction doit être terminée par un point-virgule. Ce sont les règles du C++ qui veulent ça. i Chevrons On peut combiner les chevrons < autant que l’on souhaite. Essayez donc d’afficher la phrase «Bonjour, j’écris du C++» suivi d’un retour à la ligne, suivi de «Et j’aime beaucoup.» Contenu masqué n°1 ! Un mot sur Windows Si vous êtes sous Windows et que vous tentez d’afficher du texte avec des accents, vous allez obtenir des caractères bizarres. Pour afficher du code avec des accents, vous allez devoir ajouter les lignes 2, 3 et 8 dans votre code. Nous en reparlerons plus tard. 35 II. Le début du voyage — Les commentaires sont ignorés par le compilateur mais nous sont très utiles à nous, humains. Contenumasqué Contenumasqué n°1 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Bonjour, j'écris du C++" << std::endl << "Et j'aime beaucoup."; 6 7 return 0; 8 } Retourner au texte. 38 II.4. Une super mémoire Vous savez désormais afficher des messages à l’écran. C’est un bon début, mais on est quand même assez limités, n’est-ce pas? Rassurez-vous, C++ nous permet de faire bien plus que ça. Grâce à ce langage, nous allons nous amuser avec cette super calculatrice qu’est notre ordinateur et nous découvrirons qu’il possède aussi une super mémoire! Ce chapitre va nous faire découvrir les littéraux et les variables. II.4.1. Les littéraux Que sont les littéraux? Une valeur écrite littéralement dans le code, d’où son nom. Nous avons rencontré un littéral dans le chapitre précédent: "Hello World !". Ce littéral est ce qu’on appelle une chaîne de caractères. Mais ce n’est pas le seule littéral possible en C++. Examinons tout ça. II.4.1.1. Les caractères Nous avons fait connaissance avec les chaînes de caractères lors du chapitre précédent. Les chaînes de caractères ne sont rien d’autre que du texte. On les reconnait parce qu’elles commencent et finissent par des doubles guillemets ". Entraînez-vous donc à afficher des chaînes de caractères, par exemple un littéral souhaitant une bonne journée. Contenu masqué n°2 Tous comme les mots de la langue française sont des regroupements de lettres, les chaînes de caractères sont une suite de caractères simples. En C++, un caractère est encadré par des guillemets simples '. 1 #include <iostream> 2 3 int main() 4 { 5 // Un caractère peut être une lettre. 6 std::cout << 'A' << std::endl; 7 // Ou bien un chiffre. 39 II. Le début du voyage 8 std::cout << '7' << std::endl; 9 // Ou même de la ponctuation. 10 std::cout << '!' << std::endl; 11 12 return 0; 13 } Les chaînes de caractères permettent de regrouper des caractères et nous facilitent ainsi la vie pour écrire du texte. 1 #include <iostream> 2 3 int main() 4 { 5 // Que c'est fastidieux d'écrire ça ! 6 std::cout << 'S' << 'a' << 'l' << 'u' << 't' << ' ' << 't' << 'o' << 'i' << ' ' << '!' << std::endl; 7 // C'est tellement mieux comme ça. 8 std::cout << "Salut toi !" << std::endl; 9 10 return 0; 11 } ? J’ai mis plusieurs caractères entre guillemets simples, comme ceci 'abc' et mon code compile. Ça veut dire que ça marche? Si vous avez essayé de compiler, vous avez remarqué un message en rouge dans la fenêtre de résultat disant warning: multi-character character constant, ainsi qu’un nombre au lieu de nos caractères. Le warning est un message d’avertissement que le compilateur vous envoie, car il ne sait pas si ce que vous avez fait est une erreur d’inattention ou bien une manœuvre volontaire de votre part. Dans notre cas, la norme C++ n’interdit pas de faire ça, mais ce n’est pas considéré comme une bonne pratique, comme étant du bon code. ! N’ignorez pas les warnings! Les warnings sont des messages importants signalant d’éventuels problèmes. Il ne faut surtout pas les ignorer sous prétexte que le code compile! II.4.1.1.1. Des caractères spéciaux Il existe quelques caractères qui sont un peu particuliers et, pour les introduire, je vais vous demander d’afficher un message contenant un chemin de dossier Windows (C:\Program Files 40 II. Le début du voyage 6 std::cout << "1 - 4 = " << 1 - 4 << std::endl; 7 std::cout << "7.5 * 2 = " << 7.5 * 2 << std::endl; 8 9 std::cout << "9 / 2 = " << 9 / 2 << std::endl; 10 std::cout << "9. / 2 = " << 9. / 2 << std::endl; 11 std::cout << "9 % 2 = " << 9 % 2 << std::endl; 12 13 return 0; 14 } ? Attends, qu’est-ce que c’est que ça? 9 / 2 et 9. / 2 ne donne pas la même chose? Et c’est quoi %? En fait, la raison est très simple: pour C++, si on fait une opération sur deux nombres entiers, le résultat est un nombre entier. Si l’on veut que le résultat soit un nombre à virgule, il faut qu’au moins un des deux nombres soit un flottant. Dans le cas de la division, si les deux nombres sont des entiers, on obtient le quotient de la division euclidienne, le reste s’obtenant avec l’opérateur %, appelé modulo (c’est de l’arithmétique ). Si l’un des deux nombres est un flottant, alors on obtient le résultat de la division réelle, donc un nombre réel. Également, comme en maths, les calculs respectent la distributivité , l’associativité , la commutativité et la priorité des opérateurs . L’exemple suivant est tiré du cours de @gbdivers. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Commutativité :" << std::endl; 6 std::cout << "2 + 3 = " << 2 + 3 << std::endl; 7 std::cout << "3 + 2 = " << 3 + 2 << std::endl; 8 9 std::cout << "Associativité :" << std::endl; 10 std::cout << "2 + (3 + 4) = " << 2 + (3 + 4) << std::endl; 11 std::cout << "(2 + 3) + 4 = " << (2 + 3) + 4 << std::endl; 12 13 std::cout << "Distributivité :" << std::endl; 14 std::cout << "2 * (4 + 3) = " << 2 * (4 + 3) << std::endl; 15 std::cout << "2 * 4 + 2 * 3 = " << 2 * 4 + 2 * 3 << std::endl; 16 17 std::cout << "Priorité des opérateurs :" << std::endl; 18 std::cout << "2 * 6 + 3 = " << 2 * 6 + 3 << std::endl; 19 std::cout << "2 * (6 + 3) = " << 2 * (6 + 3) << std::endl; 20 std::cout << "2 * 4 - 6 / 2 = " << 2 * 4 - 6 / 2 << std::endl; 43 II. Le début du voyage 21 22 return 0; 23 } Nous nous sommes amusés avec les littéraux, mais on est quand même rapidement limité. Imaginons que nous voulions multiplier le résultat précédent par 2 et ce, trois fois. Nous sommes obligés d’écrire un code comme ceci. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "1 * 2 = " << 1 * 2 << std::endl; 6 std::cout << "1 * 2 * 2 = " << 1 * 2 * 2 << std::endl; 7 std::cout << "1 * 2 * 2 * 2 = " << 1 * 2 * 2 * 2 << std::endl; 8 9 return 0; 10 } Maintenant, imaginons qu’on ne multiplie plus par 2 mais par 4, et non plus trois fois mais cinq. Vous visualisez bien tous les changements à faire? C’est pénible, n’est-ce pas? N’y a-t-il pas un moyen de se souvenir de valeurs et de calculs? II.4.2. Les variables La réponse à la question soulevée dans la section précédente se trouve dans le titre. Il s’agit des variables. C’est un concept commun à beaucoup de langages de programmation qui permet de stocker une valeur et de lui associer un nom, afin de faciliter tant l’écriture que la lecture du code. On peut les voir comme des enveloppes, des tiroirs, des conteneurs, bref, une zone où est stockée une valeur, à laquelle on associe un nom. ? Elle est où, cette «zone de stockage»? Toutes les variables sont stockées dans la mémoire vive de l’ordinateur, la RAM . Son fonctionnement est un peu complexe et ne nous intéresse pas (dans le cadre de ce cours tout du moins). Les curieux trouveront beaucoup de ressources sur Internet pour combler leur soif de savoir, allant de la vulgarisation simple à des explications complètes . II.4.2.1. Comment créer des variables en C++ ? Pour déclarer une variable en C++, il faut trois éléments obligatoires. 44 II. Le début du voyage — D’abord, un type, qui indique ce que la variable va stocker (un entier, une chaîne de caractères, etc). — Ensuite, un identificateur, c’est-à-dire le nom associé à la variable. — Enfin, il faut bien donner une valeur à stocker à notre variable. Ceci se fait en mettant cette valeur entre accolades { }. Examinons un cas réel que nous détaillerons. 1 #include <iostream> 2 #include <string> 3 4 int main() 5 { 6 int reponse { 42 }; 7 std::cout << "La réponse à la Grande Question est " << reponse << std::endl; 8 9 double pi { 3.1415926 }; 10 std::cout << "Voici la valeur du célèbre nombre pi : " << pi << std::endl; 11 12 char lettre { 'A' }; 13 std::cout << "La première lettre de l'alphabet français est " << lettre << std::endl; 14 15 std::string phrase { "Bonjour tout le monde !" }; 16 std::cout << "En entrant dans la salle, il s'écria : " << phrase << std::endl; 17 18 return 0; 19 } 1 La réponse à la Grande Question est 42 2 Voici la valeur du célèbre nombre pi : 3.14159 3 La première lettre de l'alphabet français est A 4 En entrant dans la salle, il s'écria : Bonjour tout le monde ! i Syntaxe héritée Il existe une syntaxe alternative, de la forme type identificateur = valeur;. Essayez, vous verrez que ça marche. 45 II. Le début du voyage imposées par C++, cela ne veut pas dire que la variable est bien nommée. — variable: ne veut rien dire. Que stocke-t-elle? Quel est son but? Pourquoi existe-t-elle? — variable_contenant_la_multiplication_de_pi_par_e_au_cube: beaucoup trop long. — cIrCoNfErEnCe_CeRcLe: le nom définit bien le pourquoi de l’existence de notre variable, mais le mélange majuscule / minuscule le rend illisible. — Brzęczyszczykiewicz: aucun sens, sauf si vous aimez l’humour polonais . Avec le temps, en progressant, vous arriverez à trouver plus rapidement et plus facilement des identificateurs qui soient clairs et simples. Dans le cours, je m’efforcerai de le faire afin de vous donner des exemples concrets. II.4.2.1.4. Sinon, par défaut… Abordons un dernier point. Je vous ai dit qu’on donne une valeur entre accolades pour initialiser notre variable. Mais que se passe-t-il si on écrit simplement les accolades, sans aucune valeur dedans? Le code va-t-il toujours compiler? 1 #include <iostream> 2 #include <string> 3 4 int main() 5 { 6 int entier {}; 7 std::cout << "Mon entier vaut " << entier << std::endl; 8 9 double reel {}; 10 std::cout << "Mon réel vaut " << reel << std::endl; 11 12 char lettre {}; 13 std::cout << "Mon caractère vaut " << lettre << std::endl; 14 15 std::string phrase {}; 16 std::cout << "Ma chaîne vaut " << phrase << std::endl; 17 18 return 0; 19 } 1 Mon entier vaut 0 2 Mon réel vaut 0 3 Mon caractère vaut 4 Ma chaîne vaut Non, le programme n’a pas de bugs, il fonctionne très bien. En fait, si aucune valeur n’est spécifiée, nos variables sont initialisées à une valeur par défaut. Pour les entiers et les réels, 48 II. Le début du voyage il s’agit de zéro. Pour les caractères, c’est une valeur spéciale signifiant «pas de caractère», de même que pour les chaînes de caractères, initialisées avec du vide. i À vous de choisir C++ vous laisse libre de vos choix. Dans ce cours, pour commencer, nous écrirons toujours les valeurs explicitement. Au fur et à mesure que vous progresserez, nous utiliserons de plus en plus souvent l’initialisation par défaut. II.4.2.2. Un peu de constance, voyons ! Terminons cette partie en présentant un mot-clé important qui a pour nom const. Il permet d’empêcher toute modification de la variable sur laquelle ce mot-clé s’applique. On dit qu’on crée une constante. Et si l’on essaye de modifier une constante, le compilateur refuse clair et net. 1 int main() 2 { 3 double const pi { 3.141592 }; 4 pi = 4; // Ouch, badaboum ça ne compile pas. 5 6 return 0; 7 } 1 [Visual Studio] 2 C3892 'pi' : vous ne pouvez pas assigner une variable const. 3 4 ------------------------------------------------------------ 5 6 [GCC] 7 prog.cc: In function 'int main()': 8 prog.cc:4:8: error: assignment of read-only variable 'pi' 9 4 | pi = 4; // Ouch, badaboum ça ne compile pas. 10 | ~~~^~~ 11 12 ------------------------------------------------------------ 13 14 [Clang] 15 prog.cc:4:8: error: cannot assign to variable 'pi' with const-qualified type 'const double' 16 pi = 4; // Ouch, badaboum ça ne compile pas. 17 ~~ ^ 18 prog.cc:3:18: note: variable 'pi' declared const here 19 double const pi { 3.141592 }; 49 II. Le début du voyage 20 ~~~~~~~~~~~~~^~~~~~~~~~~~~~~ 21 1 error generated. Certains choisissent de les écrire entièrement en majuscule pour bien les différencier des autres variables. Ce n’est absolument pas une obligation et nous n’imposons sur ce point aucune règle. Quelle en est l’utilité? Il sert pour la qualité du code. Tout ce qui n’est pas destiné à être modifié est ainsi protégé. Cela nous permet également de donner des garanties fortes à notre code. C’est pour ça que nous allons l’utiliser dans tous les exemples. Vous verrez plus tard dans le cours d’autres cas utiles. i Ordre du const Vous verrez souvent des codes qui inversent l’ordre de const et écrivent const int constante {};. Cela est légal et possible en C++, car const respecte une règle simple: il s’applique à ce qui est à sa gauche immédiate, sauf s’il n’y a rien, auquel cas il s’applique à ce qu’il y a à droite. Ici, cela ne change rien, mais plus tard cela aura des conséquences. Nous verrons cela en temps voulu. II.4.2.3. Manipulation de variables Nous ne sommes absolument pas obligés de nous contenter d’afficher nos variables. Au contraire, nous pouvons faire beaucoup d’opérations dessus, notamment combiner les variables entre elles et modifier leur valeur. 1 #include <iostream> 2 3 int main() 4 { 5 int entier { 4 }; 6 std::cout << "Mon entier vaut : " << entier << std::endl; 7 8 // Je peux tout à fait changer la valeur de ma variable. 9 entier = 4 * (8 + 9) - 1; 10 std::cout << "Finalement non, il vaut : " << entier << std::endl; 11 12 // Je peux même utiliser la valeur de ma variable et la réaffecter à la même variable. 13 entier = entier + 7; 14 std::cout << "Et si j'additionne 7 ? " << entier << std::endl; 15 16 int autre_entier { entier * 2 }; 17 // Je peux utiliser d'autres variables également. 50 II. Le début du voyage 1 int main() 2 { 3 // Comme 0 est déjà un littéral entier, pourquoi donc préciser 'int' ? 4 int entier { 0 }; 5 6 // Comme 3.1415 est déjà un littéral flottant, pourquoi donc préciser 'double' ? 7 double reel { 3.1415 }; 8 9 return 0; 10 } Le compilateur peut en effet déduire tout seul le type d’une variable et cela grâce à un nouveau mot-clef: auto. Celui-ci s’utilise en lieu et place du type de la variable. Notre code précédent peut ainsi être réécrit de la manière qui suit. 1 int main() 2 { 3 // Hop, le compilateur déduit que 'entier' est de type 'int'. 4 auto entier { 0 }; 5 6 // Hop, le compilateur déduit que 'reel' est de type 'double'. 7 auto reel { 3.1415 }; 8 9 return 0; 10 } II.4.3.1. Avec const Tout comme dans le cas d’une variable dont le type est explicitement écrit, si vous voulez déclarer une constante, il suffit de rajouter const. 1 int main() 2 { 3 auto const constante { 40 }; 4 return 0; 5 } 53 II. Le début du voyage II.4.3.2. Le cas de std::string Dans le cas des chaînes de caractères, c’est un peu particulier. Déjà, il faut rajouter un s après les guillemets fermants ", et ce pour chaque chaîne de caractères que vous voulez écrire. Ensuite, il faut rajouter une ligne spéciale. Nous expliquerons pourquoi plus loin dans ce cours. L’exemple suivant va vous aider à comprendre. 1 #include <string> 2 3 int main() 4 { 5 // Écrivez cette ligne une seule fois. 6 using namespace std::literals; 7 8 // Puis vous pouvez déclarer autant de chaînes de caractères que vous voulez. 9 auto chaine { "Du texte."s }; 10 auto autre_chaine { "Texte alternatif."s }; 11 auto encore_une_chaine { "Allez, un dernier pour la route."s }; 12 13 return 0; 14 } i Histoire et héritage Si nous sommes obligés de rajouter le s en fin de littéral, c’est parce que nous avons affaire ici à un héritage du C. Sans celui-ci, le compilateur déduit que notre littéral est une chaîne de caractères comme en C et non comme étant une std::string. Nous en reparlerons au moment voulu, mais retenez que ce s est très important dès que vous utilisez auto. II.4.3.3. Les avantages Utiliser auto présente deux avantages majeurs. — D’abord, utiliser auto permet de raccourcir le code. Là, remplacer double par auto n’est pas un gain de place énorme, mais, plus tard dans ce cours, nous verrons des types longs à écrire et lourds à lire, qu’il sera bien plus agréable de remplacer par un concis auto. — Ensuite, cela permet un code plus évolutif. Imaginez des calculs complexes avec des types écrits explicitement. Si vous voulez changer l’un des types, il faut en changer chaque occurrence. Avec auto, vous laissez au compilateur le soin de s’occuper de cette tâche. ? Je suis perdu. Qu’est-ce que je dois choisir entre auto ou le type explicite? 54 II. Le début du voyage C++ vous autorise à faire les deux, donc le choix est vôtre. Certains programmeurs ne jurent que par auto et l’utilisent partout. D’autres préfèrent le réserver aux types longs ou complexes et écrire explicitement les types simples et courts. Dans le cadre de ce cours, j’utiliserai les deux façons de faire. II.4.4. Les entrées Dès le premier code C++ que vous avez étudié, il y avait la notion de sortie standard. Il est temps de voir le concept inverse en manipulant l’entrée standard. Maintenant que nous connaissons le concept des variables, demander des informations à l’utilisateur est à notre portée. Il faut en effet pouvoir stocker quelque part la valeur qu’a tapée l’utilisateur, ce que permettent justement les variables. Manipuler les entrées est un peu particulier avec Wandbox. Il faut cliquer sur l’encadré stdin et taper la valeur que vous souhaitez rentrer. C’est moins pratique qu’avec un IDE. Peu importe ce que vous préférez, l’essentiel est que vous puissiez manipuler pour comprendre la suite du chapitre. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Entre ton age : " << std::endl; 6 int age { 0 }; 7 std::cin >> age; 8 std::cout << "Tu as " << age << " ans.\n"; 9 10 return 0; 11 } Avez-vous remarqué à quel point cin est semblable à cout? Déjà, pour l’utiliser, il faut le préfixer par std::, car cin est un objet appartement à la bibliothèque standard. Et on utilise les chevrons dans le sens inverse de cout. II.4.4.1. Gestion des erreurs Et si vous rentrez une valeur qui n’a rien à voir? Que se passe-t-il si je décide de taper Maurice au lieu de 5? Essayez donc. 1 Entre ton age : 2 Maurice 3 Tu as 0 ans. 4 Appuyez sur une touche pour continuer... 55 II. Le début du voyage Contenumasqué n°3 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Dossier principal : C:\Program Files (x86)" << std::endl; 6 7 return 0; 8 } Retourner au texte. Contenumasqué n°4 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Voici un exemple sans échappement : " << "'" << " est bien affiché." << std::endl; 6 std::cout << "Maintenant, je vais l'échapper : " << '\'' << " est bien affiché grâce à l'échappement." << std::endl; 7 8 std::cout << "La suite, après la tabulation : \tJe suis loin." << std::endl; 9 std::cout << "Ces mots sont sur une ligne.\nEt ceux là sur la suivante.\n"; 10 11 return 0; 12 } Retourner au texte. Contenumasqué n°5 1 #include <iostream> 2 3 int main() 4 { 58 II. Le début du voyage 5 int nombre { 1 }; 6 int const multiplicateur { 2 }; 7 8 nombre = nombre * multiplicateur; 9 std::cout << "Maintenant, mon nombre vaut " << nombre << std::endl; 10 11 nombre = nombre * multiplicateur; 12 std::cout << "Maintenant, mon nombre vaut " << nombre << std::endl; 13 14 nombre = nombre * multiplicateur; 15 std::cout << "Maintenant, mon nombre vaut " << nombre << std::endl; 16 17 return 0; 18 } i Vous remarquerez qu’on répète quand même plusieurs fois les mêmes instructions. Ce n’est pas grave. Nous verrons très bientôt comment remédier à ce problème. L’essentiel est que vous ayez pu voir l’avantage d’utiliser des variables. Retourner au texte. 59 II.5. Le conditionnel conjugué en C++ «Le conditionnel est un mode employé pour exprimer un état soumis à une condition.» Telle est la définition qu’en donne Wikipédia . Cela vous rappelle-t-il vos cours de français? Mais quel peut bien être le rapport avec la programmation? C’est que C++ permet aussi d’exprimer des conditions et donc de modifier le comportement de notre programme. Ce chapitre va donc introduire les conditions à notre palette d’outils et permettra de résoudre la problématique soulevée en conclusion du chapitre précédent. II.5.1. Les booléens Les conditions en C++ sont régies par un principe simple, qui est qu’une condition est soit vraie, soit fausse. Finalement, c’est un peu comme dans la réalité. Si je vous pose la question «Êtes-vous majeurs?», la réponse est soit oui, soit non. De même, «Faîtes-vous 1m80 ou plus?» entraînera soit une réponse positive, soit négative. C++ nous offre un type conçu exprès pour ça, bool. Ce type peut prendre deux valeurs: soit true, signifiant vrai, soit false qui veut dire faux. Voyez par vous-mêmes l’exemple on ne peut plus bête ci-dessous. 1 int main() 2 { 3 bool const vrai { true }; 4 bool const faux { false }; 5 6 return 0; 7 } ? D’accord, mais ça sert à quoi ça? Je vois l’intérêt de manipuler des entiers ou du texte, mais stocker juste vrai ou faux, ça sert quand? L’intérêt semble en effet très faible si l’on se contente du code précédent. Sachez que les booléens sont partout, utilisables grâce à ce que l’on appelle les opérateurs de comparaisons. En voici la liste juste ci-dessous. Opérateur Signification Exemple == Égalité, compare si deux variables sont égales entre elles. a == b 60 II. Le début du voyage Prenons un exemple. Affichons la note à un examen, rentrée par l’utilisateur. Si celle-ci est supérieure ou égale à 16, nous afficherons un message de félicitations. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Indique-moi ta note : "; 6 7 int note { 0 }; 8 std::cin >> note; 9 10 std::cout << "Tu as obtenu " << note << std::endl; 11 12 if (note >= 16) 13 { 14 std::cout << "Félicitations, c'est une très bonne note !" << std::endl; 15 } 16 17 return 0; 18 } Faites-le tourner. Vous verrez, le message de félicitations ne s’affiche que si vous rentrez un nombre supérieur ou égal à 16. Essayez avec 15, vous ne verrez plus le message. II.5.2.1. À portée Nous pouvons également déclarer des variables au sein du bloc d’accolades. Cependant, celles-ci ne sont utilisables que jusqu’à l’accolade fermante correspondante. Ainsi, le code ci-dessous n’est pas correct. 1 #include <iostream> 2 3 int main() 4 { 5 if (true) 6 { 7 int const age { 42 }; 8 // D'autres instructions. 9 10 // Aucun problème. 11 if (age == 42) 12 { 13 // Ici non plus. 14 } 63 II. Le début du voyage 15 } 16 17 // NON ! Le compilateur ne connait pas la variable age. 18 std::cout << age << std::endl; 19 20 return 0; 21 } Ce sont les règles de C++ qui veulent ça. Quand on écrit un nouveau bloc à base d’accolades, on dit qu’on crée une nouvelle portée. Et une variable n’est utilisable que dans la portée, ou le bloc d’accolade, où elle a été déclarée. C’est une bonne pratique de déclarer ses variables dans la plus petite portée possible. Il y a plusieurs raisons à ça. — Dans le cas d’un code long et complexe, déclarer une variable au plus près possible de son utilisation permet de ne pas avoir à parcourir de longues lignes pour en obtenir des détails (quel est son type, sa valeur de base, etc). Cela aide à la lecture et la compréhension du code. — Lorsqu’on atteint la fin du bloc correspondant, le programme libère dans la mémoire les emplacements qu’il avait réservés pour les variables qui s’y trouvaient. Dans le cas d’un int comme ici, ça ne change rien. Mais dans le cas de variables plus complexes que nous verrons plus tard, cela peut avoir une grande incidence sur les performances du programme. Ainsi, je vous encourage fortement à déclarer vos variables à l’intérieur de vos blocs de condition si elles ne sont pas destinées à être utilisées ailleurs. II.5.3. else — Sinon… Maintenant que nous avons vu comment changer le code si une condition est vérifiée, voyons comment faire l’opposé, c’est-à-dire comment agir si celle-ci est fausse. Imaginons un programme demandant si l’utilisateur est majeur ou mineur. On peut imaginer quelque chose comme ce qui suit. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Donne-moi ton âge: "; 6 int age { 0 }; 7 std::cin >> age; 8 9 if (age >= 18) 10 { 11 std::cout << "Tu es majeur." << std::endl; 64 II. Le début du voyage 12 } 13 14 if (age < 18) 15 { 16 std::cout << "Tu es mineur." << std::endl; 17 } 18 19 return 0; 20 } Ce programme est fonctionnel mais un peu lourd, puisqu’on répète deux fois une condition quasiment identique. Heureusement, C++ nous offre un autre mot-clef, else, qui exécute des instructions si la condition du if est fausse. Voyez-vous mêmes le code ci-dessous. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Donne-moi ton âge: "; 6 int age { 0 }; 7 std::cin >> age; 8 9 if (age >= 18) 10 { 11 std::cout << "Tu es majeur." << std::endl; 12 } 13 else 14 { 15 std::cout << "Tu es mineur." << std::endl; 16 } 17 18 return 0; 19 } Le code se lit ainsi en français: «Si l’âge rentré par l’utilisateur est supérieur ou égal à 18 ans, alors afficher “Tu es majeur”, sinon afficher “Tu es mineur”.» Le mot-clef else est en effet un mot d’anglais qui existe et qui signifie, comme vous l’avez compris, «sinon». 65 informaticie... mehdidou99 La programmation en C++ moderne 6 mars 2021 0 Table des matières II.6.7. Convention de nommage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 II.6.8. Contrôler plus finement l’exécution de la boucle . . . . . . . . . . . . . . . . 92 II.6.8.1. break—Je m’arrête là . . . . . . . . . . . . . . . . . . . . . . . . . . 92 II.6.8.2. continue—Saute ton tour! . . . . . . . . . . . . . . . . . . . . . . . 94 II.6.8.3. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 II.7. Au tableau ! 101 II.7.1. Un tableau c’est quoi? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 II.7.2. std::vector—Mais quel dynamisme! . . . . . . . . . . . . . . . . . . . . . . . 101 II.7.2.1. Déclarer un std::vector . . . . . . . . . . . . . . . . . . . . . . . . 101 II.7.2.2. Manipuler les éléments d’un std::vector . . . . . . . . . . . . . . . 103 II.8. Accès aux éléments 104 II.8.1. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 II.8.1.1. Calcul de moyenne . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 II.8.1.2. Minimum et maximum . . . . . . . . . . . . . . . . . . . . . . . . . . 112 II.8.1.3. Séparer les pairs des impairs . . . . . . . . . . . . . . . . . . . . . . . 113 II.8.1.4. Compter les occurrences d’une valeur . . . . . . . . . . . . . . . . . . 113 II.8.2. std::array—Le tableau statique . . . . . . . . . . . . . . . . . . . . . . . . . 113 II.8.2.1. Déclarer un std::array . . . . . . . . . . . . . . . . . . . . . . . . . 113 II.8.2.2. Remplir un tableau . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 II.8.2.3. Accéder aux éléments . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 II.8.2.4. Connaître la taille . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 II.8.2.5. Vérifier si le tableau est vide . . . . . . . . . . . . . . . . . . . . . . . 116 II.8.3. std::string—Un type qui cache bien son jeu . . . . . . . . . . . . . . . . . . . 117 II.8.3.1. Connaître la taille d’une chaîne . . . . . . . . . . . . . . . . . . . . . 117 II.8.3.2. Accéder à un caractère . . . . . . . . . . . . . . . . . . . . . . . . . . 118 II.8.3.3. Premier et dernier caractère . . . . . . . . . . . . . . . . . . . . . . . 118 II.8.3.4. Vérifier qu’une chaîne est vide . . . . . . . . . . . . . . . . . . . . . . 119 II.8.3.5. Ajouter ou supprimer un caractère à la fin . . . . . . . . . . . . . . . 119 II.8.3.6. Supprimer tous les caractères . . . . . . . . . . . . . . . . . . . . . . 120 II.8.3.7. Boucler sur une chaîne . . . . . . . . . . . . . . . . . . . . . . . . . . 120 II.8.3.8. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 II.9. Déployons la toute puissance des conteneurs 126 II.9.1. Le socle de base: les itérateurs . . . . . . . . . . . . . . . . . . . . . . . . . . 126 II.9.1.1. Déclaration d’un itérateur . . . . . . . . . . . . . . . . . . . . . . . . 126 II.9.1.2. Début et fin d’un conteneur . . . . . . . . . . . . . . . . . . . . . . . 127 II.9.1.3. Accéder à l’élément pointé . . . . . . . . . . . . . . . . . . . . . . . . 127 II.9.1.4. Se déplacer dans une collection . . . . . . . . . . . . . . . . . . . . . 128 II.10. Déplacement vers l’élément suivant 129 II.10.0.1. const et les itérateurs . . . . . . . . . . . . . . . . . . . . . . . . . . 131 II.10.0.2. Itérer depuis la fin . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 II.10.0.3. Utilisation conjointe avec les conteneurs . . . . . . . . . . . . . . . . 134 II.10.1. Des algorithmes à gogo! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 II.10.1.1. std::count—Compter les occurrences d’une valeur . . . . . . . . . . 135 3 Table des matières II.10.1.2. std::find—Trouver un certain élément . . . . . . . . . . . . . . . . 136 II.10.1.3. std::sort—Trier une collection . . . . . . . . . . . . . . . . . . . . 138 II.10.1.4. std::reverse—Inverser l’ordre des éléments d’une collection . . . . 139 II.10.1.5. std::remove—Suppression d’éléments . . . . . . . . . . . . . . . . . 140 II.10.1.6. std::search—Rechercher un sous-ensemble dans un ensemble . . . 140 II.10.1.7. std::equal—Vérifier l’égalité de deux ensembles . . . . . . . . . . . 141 II.10.1.8. Et tant d’autres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 II.10.2. Personnalisation à la demande . . . . . . . . . . . . . . . . . . . . . . . . . . 142 II.10.2.1. Le prédicat, à la base de la personnalisation des algorithmes . . . . . 142 II.10.2.2. Trier une liste dans l’ordre décroissant . . . . . . . . . . . . . . . . . 142 II.10.2.3. Somme et produit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 II.10.2.4. Prédicats pour caractères . . . . . . . . . . . . . . . . . . . . . . . . . 144 II.10.3. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 II.10.3.1. Palindrome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 II.10.3.2. string_trim—Suppression des espaces . . . . . . . . . . . . . . . . 146 II.10.3.3. Couper une chaîne . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 II.10.3.4. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 II.11. Des flux dans tous les sens 152 II.11.1. Avant-propos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 II.11.1.1. Prendrez-vous une extension? . . . . . . . . . . . . . . . . . . . . . . 152 II.11.1.2. Vois sur ton chemin… . . . . . . . . . . . . . . . . . . . . . . . . . . 153 II.11.1.3. Un mot sur Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 II.11.1.4. Pas d’interprétation, on est des brutes . . . . . . . . . . . . . . . . . 154 II.11.2. std::ofstream—Écrire dans un fichier . . . . . . . . . . . . . . . . . . . . . . 154 II.11.2.1. Ouvrir le fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 II.11.2.2. Écriture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 II.11.2.3. Ouvrir sans effacer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 II.11.3. std::ifstream—Lire dans un fichier . . . . . . . . . . . . . . . . . . . . . . . . 159 II.11.3.1. Ouvrir le fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 II.11.3.2. Lecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 II.11.3.3. Tout lire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 II.11.4. Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 II.11.4.1. Statistiques sur des fichiers . . . . . . . . . . . . . . . . . . . . . . . . 163 II.11.5. Encore plus de flux! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 II.11.5.1. Un flux c’est quoi? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 II.11.5.2. Un buffer dites-vous? . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 II.11.5.3. Les modificateurs de flux . . . . . . . . . . . . . . . . . . . . . . . . . 165 II.11.5.4. Même les chaînes y passent! . . . . . . . . . . . . . . . . . . . . . . . 166 II.11.5.5. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 4 Table des matières III. On passe la deuxième ! 171 III.1. Découpons du code — Les fonctions 173 III.1.1. Les éléments de base d’une fonction . . . . . . . . . . . . . . . . . . . . . . . 173 III.1.1.1. Une fonction, c’est quoi? . . . . . . . . . . . . . . . . . . . . . . . . . 173 III.1.1.2. Une fonction bien connue . . . . . . . . . . . . . . . . . . . . . . . . . 175 III.1.1.3. Les composants d’une fonction . . . . . . . . . . . . . . . . . . . . . . 175 III.2. Schéma d’une fonction 176 III.2.1. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 III.2.1.1. Afficher un rectangle . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 III.2.1.2. Distributeur d’argent . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 III.2.1.3. Parenthésage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 III.2.2. Quelles sont vos références? . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 III.2.2.1. La problématique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 III.2.2.2. Les références . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 III.2.2.3. Paramètres de fonctions . . . . . . . . . . . . . . . . . . . . . . . . . 184 III.2.2.4. Valeur de retour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 III.2.2.5. Un mot sur la déduction de type . . . . . . . . . . . . . . . . . . . . 188 III.2.3. Nos fonctions sont surchargées! . . . . . . . . . . . . . . . . . . . . . . . . . 190 III.2.4. [T.P] Gérer les erreurs d’entrée—Partie III . . . . . . . . . . . . . . . . . . . 191 III.2.5. Dessine-moi une fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 III.2.5.1. Le problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 III.2.5.2. La solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 III.2.5.3. Utilisons les prototypes . . . . . . . . . . . . . . . . . . . . . . . . . . 194 III.2.5.4. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 III.3. Erreur, erreur, erreur… 201 III.3.1. L’utilisateur est un idiot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 III.3.2. À une condition… ou plusieurs . . . . . . . . . . . . . . . . . . . . . . . . . . 202 III.3.2.1. Contrats assurés par le compilateur . . . . . . . . . . . . . . . . . . . 202 III.4. Le typage 203 III.4.0.1. Vérifier nous-mêmes . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 III.4.1. Le développeur est un idiot . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 III.4.1.1. Préconditions et assertions . . . . . . . . . . . . . . . . . . . . . . . . 206 III.4.2. Les tests unitaires à notre aide . . . . . . . . . . . . . . . . . . . . . . . . . . 207 III.4.2.1. Pourquoi tester? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 III.4.2.2. Un test unitaire, qu’est-ce que c’est? . . . . . . . . . . . . . . . . . . 207 III.4.2.3. Écrire des tests unitaires . . . . . . . . . . . . . . . . . . . . . . . . . 208 III.4.2.4. Les tests unitaires et les postconditions . . . . . . . . . . . . . . . . . 209 III.4.3. [T.P] Gérer les erreurs d’entrée—Partie IV . . . . . . . . . . . . . . . . . . . 209 III.4.4. L’exception à la règle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 III.4.4.1. La problématique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 III.4.4.2. C’est quoi une exception? . . . . . . . . . . . . . . . . . . . . . . . . 212 III.4.4.3. Lancement des exceptions dans 3, 2, 1… . . . . . . . . . . . . . . . . . 212 III.4.4.4. Attends que je t’attrape! . . . . . . . . . . . . . . . . . . . . . . . . . 214 III.4.4.5. Attrapez-les tous! . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 5 Table des matières III.11.4. Les avantages du découpage en fichiers . . . . . . . . . . . . . . . . . . . . . 358 III.11.4.1. Une structure de projet plus visible . . . . . . . . . . . . . . . . . . . 358 III.11.4.2. Une meilleure abstraction . . . . . . . . . . . . . . . . . . . . . . . . 358 III.11.4.3. Une meilleure modularité . . . . . . . . . . . . . . . . . . . . . . . . . 359 III.11.5. Le cas des templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 III.11.5.1. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 IV. Interlude - Être un développeur 386 IV.1. Avant-propos 388 IV.1.1. Ce que nous avons appris . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388 IV.1.2. Différents paradigmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 IV.1.2.1. Le paradigme impératif . . . . . . . . . . . . . . . . . . . . . . . . . . 389 IV.1.2.2. Le paradigme fonctionnel . . . . . . . . . . . . . . . . . . . . . . . . . 390 IV.1.2.3. Le paradigme générique . . . . . . . . . . . . . . . . . . . . . . . . . 391 IV.1.2.4. La programmation par contrat . . . . . . . . . . . . . . . . . . . . . . 392 IV.1.3. Brancher le cerveau avant tout . . . . . . . . . . . . . . . . . . . . . . . . . . 393 IV.1.4. Savoir se débrouiller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 IV.1.4.1. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 IV.2. Mais où est la doc ? 396 IV.2.1. Lire une page de doc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 IV.2.1.1. À l’arrivée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 IV.2.1.2. vector − Retour sur le plus célèbre des conteneurs . . . . . . . . . . 397 IV.3. Présentation 398 IV.3.0.1. Les algorithmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 IV.3.0.2. Les chaînes de caractère au grand complet . . . . . . . . . . . . . . . 401 IV.3.1. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 IV.3.1.1. Remplacer une chaîne de caractère par une autre . . . . . . . . . . . 402 IV.3.1.2. Norme d’un vecteur . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 IV.3.1.3. Nombres complexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 IV.3.1.4. Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 IV.3.2. Documenter son code avec Doxygen . . . . . . . . . . . . . . . . . . . . . . . 404 IV.3.2.1. Installation des outils . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 IV.3.2.2. Écrire la documentation . . . . . . . . . . . . . . . . . . . . . . . . . 408 IV.3.3. Quelques bonnes pratiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 IV.3.3.1. Ce qu’il faut documenter . . . . . . . . . . . . . . . . . . . . . . . . . 415 IV.3.3.2. Les fichiers d’en-tête ou source? . . . . . . . . . . . . . . . . . . . . . 415 IV.3.3.3. Commentaire vs documentation . . . . . . . . . . . . . . . . . . . . . 416 IV.3.3.4. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419 IV.4. Compilation en cours… 423 IV.4.1. Le préprocesseur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423 IV.4.1.1. Inclure des fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423 IV.4.1.2. Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423 8 Table des matières IV.4.1.3. Debug ou release? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424 IV.4.2. La compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426 IV.4.2.1. Les templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426 IV.4.2.2. constexpr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 IV.4.2.3. La compilation à proprement parler . . . . . . . . . . . . . . . . . . . 429 IV.4.2.4. Une étape intermédiaire cachée . . . . . . . . . . . . . . . . . . . . . 430 IV.4.2.5. Influer sur la compilation . . . . . . . . . . . . . . . . . . . . . . . . . 431 IV.4.3. Le linker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436 IV.4.3.1. Une question de symboles . . . . . . . . . . . . . . . . . . . . . . . . 437 IV.4.4. Schéma récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440 IV.4.4.1. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 IV.5. Chasse aux bugs ! 443 IV.5.1. Le principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 IV.5.2. Un code d’exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 IV.5.3. Visual Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 IV.5.3.1. Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 IV.5.3.2. Pas-à-pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447 IV.5.3.3. Point d’arrêt conditionnel . . . . . . . . . . . . . . . . . . . . . . . . 448 IV.5.4. Qt Creator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 IV.5.4.1. Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 IV.5.4.2. Pas-à-pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 IV.5.4.3. Point d’arrêt conditionnel . . . . . . . . . . . . . . . . . . . . . . . . 452 IV.5.4.4. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 IV.5.5. En ligne de commande avec gdb . . . . . . . . . . . . . . . . . . . . . . . . . 454 IV.5.5.1. Poser un point d’arrêt . . . . . . . . . . . . . . . . . . . . . . . . . . 454 IV.5.5.2. Supprimer des points d’arrêt . . . . . . . . . . . . . . . . . . . . . . . 455 IV.5.5.3. Désactiver des points d’arrêt . . . . . . . . . . . . . . . . . . . . . . . 455 IV.5.5.4. Afficher l’état d’une variable . . . . . . . . . . . . . . . . . . . . . . . 456 IV.5.5.5. Pas-à-pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456 IV.5.5.6. Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 IV.5.5.7. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 IV.5.5.8. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 IV.6. Une foule de bibliothèques 459 IV.6.1. Quelles bibliothèques choisir? . . . . . . . . . . . . . . . . . . . . . . . . . . 459 IV.6.1.1. Boost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 IV.6.1.2. SFML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 IV.6.2. Généralités . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 IV.6.2.1. Statique ou dynamique? . . . . . . . . . . . . . . . . . . . . . . . . . 460 IV.6.2.2. Debug ou release? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 IV.6.3. Installer Boost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 IV.6.3.1. GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 IV.6.3.2. Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 IV.6.3.3. Tester l’installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464 IV.6.4. Installer SFML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 IV.6.4.1. GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 IV.6.4.2. Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467 9 Table des matières IV.6.4.3. Tester l’installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470 IV.6.4.4. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 IV.7. Améliorer ses projets 473 IV.7.1. git—Sauvegarder et versionner son code . . . . . . . . . . . . . . . . . . . . 473 IV.7.1.1. La problématique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 IV.7.1.2. Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 IV.7.1.3. Initialiser git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 IV.7.1.4. Créer un dépôt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 IV.7.1.5. Connaître l’état de ses fichiers . . . . . . . . . . . . . . . . . . . . . . 475 IV.7.1.6. Ajouter un fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476 IV.7.1.7. Valider les modifications . . . . . . . . . . . . . . . . . . . . . . . . . 477 IV.7.1.8. Voir l’historique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478 IV.7.1.9. Bloquer certains fichiers . . . . . . . . . . . . . . . . . . . . . . . . . 478 IV.7.1.10. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480 IV.7.1.11. Visual Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480 IV.7.2. GitHub—Partager son code . . . . . . . . . . . . . . . . . . . . . . . . . . . 481 IV.7.2.1. La problématique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481 IV.7.2.2. Création d’un projet . . . . . . . . . . . . . . . . . . . . . . . . . . . 482 IV.7.2.3. Récupérer localement les modifications . . . . . . . . . . . . . . . . . 484 IV.7.2.4. Pousser nos modifications . . . . . . . . . . . . . . . . . . . . . . . . 485 IV.7.2.5. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486 IV.7.3. CMake—Automatiser la compilation de nos programmes . . . . . . . . . . . 486 IV.7.3.1. La problématique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486 IV.7.3.2. Un exemple simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487 IV.7.3.3. Lier des bibliothèques externes . . . . . . . . . . . . . . . . . . . . . . 491 IV.7.3.4. Définir des variables au lancement . . . . . . . . . . . . . . . . . . . . 504 IV.7.3.5. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 IV.7.4. Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 IV.7.4.1. TravisCI—De l’intégration continue . . . . . . . . . . . . . . . . . . . 504 IV.7.4.2. CppCheck—Vérification du code . . . . . . . . . . . . . . . . . . . . . 505 IV.7.4.3. StackOverflow—La réponses à quasiment toutes les questions . . . . . 506 IV.7.4.4. En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 Contenu masqué . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507 V. La Programmation Orientée Objet 515 V.1. Premiers pas avec la POO 517 V.1.1. Le principe: des objets bien serviables . . . . . . . . . . . . . . . . . . . . . . 517 V.1.1.1. Le principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 V.2. Penser en terme de données… 518 V.2.0.1. Exemple concret . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 V.2.1. Un peu de vocabulaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 V.2.2. En C++, ça donne quoi? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 V.2.2.1. Penser services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 V.2.2.2. Penser tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 V.2.2.3. Définition de la classe . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 10 Table des matières sera mis sur la rigueur, la qualité et les bonnes pratiques. Le rythme sera progressif, chaque concept étant introduit en temps voulu et en lien avec ce que nous aurons déjà vu. i Prérequis Prérequis Lire cette introduction à la programmation afin d’avoir des bases pour aborder l’ap- prentissage du C++. Objectifs Vous former à la programmation en vous donnant des bases solides sur lesquelles continuer. Vous former au C++ moderne. 13 Première partie Remerciements 14 I. Remerciements Car ce cours n’aurait jamais pu voir le jour sans l’aide et le soutien de plusieurs personnes. — Un merci particulier à @gbdivers pour son cours Débuter en C++ moderne qui aura été une source d’inspiration pour l’écriture du présent cours, à qui nous avons emprunté plusieurs passages très bien écrits et qui n’aura cessé de nous aider à améliorer ce cours par ses nombreuses remarques et suggestions. — Tous les membres qui ont participé à la bêta et qui ont grandement aidé à améliorer la qualité de ce tutoriel, par leurs nombreuses remarques, suggestions et corrections. Toutes vos participations, petites et grandes, nous ont été extrêmement précieuses et utiles pour produire un cours meilleur. — Toute l’équipe de Zeste de Savoir; en particulier, un grand merci à @Taurre et @Glordim qui se sont chargés de la validation. — Et l’ensemble des lecteurs, pour avoir choisi ce cours. ! À venir La partie POO est toujours en rédaction. Les mises à jour viendront au fil de l’eau. 15 II.1. Le C++, qu’est-ce que c’est ? Voilà, vous êtes décidés, vous voulez apprendre à programmer à l’aide du langage C++. Mais vous devez toujours avoir quelques questions qui trottent dans votre esprit. — Concrètement, C++, c’est quoi? — Et puis pourquoi commencer par C++? — Que vais-je savoir faire en sortant de ce tutoriel? — Il y a-t-il des conditions, des prérequis, pour pouvoir suivre ce cours? II.1.1. Petite mise au point J’ai indiqué en introduction que le seul prérequis était de lire l’introduction à la programmation et c’est vrai. Mais si peu de connaissances sont nécessaires pour comprendre tout ce qui sera dit, cela ne veut pas dire pour autant que ce sera du tout cuit, prémâché, directement dans la bouche. C’est pour cela que je veux prendre quelques minutes pour clarifier ceci. II.1.1.1. Développer, unmétier à part entière Eh oui! Créer des logiciels, c’est un métier. D’ailleurs, il y a mêmes des écoles et des études spécialisées pour ça. C’est que développer, ce n’est pas simplement écrire du code. Il y a aussi des phases de réflexion, de conceptions, d’écriture, de validation, de tests, de réécriture d’anciennes portions, etc. Par ailleurs, même si cela n’est pas directement lié à la programmation, peut également s’ajouter à cela: la gestion de base de données, l’usage du réseau, le management, la gestion de projet, etc. En bref, être développeur c’est beaucoup de compétences différentes dans des domaines variés. La cruelle vérité qui se cache derrière tout ça, c’est que ce cours ne fera pas de vous des experts, ni des développeurs professionnels. Par contre, une fois fini, vous aurez des bases solides pour continuer votre apprentissage. La route du savoir est infinie. II.1.1.2. Votre part du travail Le cours est écrit de façon à être le plus clair possible, sans vous noyer sous un flot de détails et d’explications, mais il arrivera parfois que vous ne compreniez pas un morceau de code ou une explication. C’est tout à fait normal, ça fait partie de l’apprentissage. Reprenez le cours à tête reposée, aidez-vous de schémas ou de dessins, demandez de l’aide sur les forums , et vous ne resterez jamais bloqués longtemps. 18 II. Le début du voyage Par contre, il faut être prêt à fournir des efforts de votre côté. Cela signifie ne pas se ruer sur les forums au bout de quelques minutes, sans même avoir essayé de trouver une solution. II.1.1.3. Les mathématiques, indispensables ? Une des grandes appréhensions, qui revient régulièrement dans la bouche des débutants, est de savoir si les mathématiques sont un prérequis à l’apprentissage de la programmation. La réponse est non. Il est tout à fait possible d’apprendre à programmer tout en ayant un faible niveau en mathématique. Ce cours ne demande aucune connaissance en mathématiques plus poussées que les opérations de base et, quelques fois, l’utilisation de sinus et cosinus, en guise d’exemples. Bien sûr, certains aspects de la programmation, comme la sécurité, la cryptographie ou les applications scientifiques vont demander un bagage mathématique solide. Mais cela ne rentre pas dans le cadre de ce cours. II.1.1.4. L’anglais, indispensable ? À strictement parler, dans le cadre de ce cours, pas besoin de savoir parler anglais. Même si nous examinerons régulièrement de la documentation écrite dans la langue de Shakespeare, je serai là pour donner des explications et éclaircissements. Et quand bien même il y aurait quelque chose sur lequel vous butez, vous pouvez vous servir d’un traducteur automatique. D’un point de vue plus général, si vous souhaitez continuer dans l’informatique et la pro- grammation, il sera très difficile d’échapper à l’anglais. Beaucoup de cours, de documents, de forums sont en anglais, ou en font un usage massif. L’anglais est tout simplement la langue de l’informatique. Après, sachez que l’anglais informatique est simple à comprendre, car souvent écris par des gens dont l’anglais n’est pas la langue maternelle. Ainsi, inutile d’être bilingue, un bon dictionnaire ou un traducteur vous aideront. II.1.2. Tour d’horizon du C++ II.1.2.1. L’histoire du C++ Faisons un plongeon dans l’histoire et revenons dans les années 1970. À cette époque, Dennis Ritchie , programmeur aux laboratoires AT&T aux États-Unis, invente le langage C , conçu pour programmer le système d’exploitation UNIX. Ce langage devint très populaire à tel point qu’il est encore beaucoup utilisé aujourd’hui, dans l’écriture de Linux par exemple. Puis un peu plus tard, au début des années 1980, Bjarne Stroustrup , lui aussi développeur aux laboratoires AT&T, décida de prendre le langage C comme base et de lui ajouter des fonctionalités issues d’un autre langage appelé Simula. Ce langage devint alors le C with classes. Finalement, en 1983, son créateur, estimant que le nom de son langage était trop réducteur aux vues de tous les ajouts faits par rapport au C, décida de le renommer C++. Mais l’histoire ne s’arrête pas là. Au contraire, le C++ continue d’évoluer à tel point qu’on décide au début des années 1990 de le normaliser, c’est-à-dire d’en établir les règles officielles. Ce travail de longue 19 II. Le début du voyage haleine s’acheva en 1998; cette version est ainsi souvent nommée C++98. Ensuite, en 2003, des corrections ont été apportées et l’on obtint C++03. Puis de nouveau un chantier titanesque est mis en place pour améliorer encore plus le C++, ce qui aboutit 8 ans plus tard, en 2011, à la sortie de C++11, jugée par beaucoup de développeurs comme étant la renaissance du C++. Ensuite, de nouvelles corrections et quelques ajustements ont été apportés pour donner C++14. Enfin, à l’heure actuelle, la norme C++17, nouvelle version majeure et apportant tout un lot de choses intéressantes, est sortie en fin d’année et C++20 est déjà en chantier. i Point vocabulaire Beaucoup de programmeurs utilisent le terme «C++ historique» pour désigner les normes C++98 et C++03 et le terme «C++ moderne» pour parler de C++11 et au-delà. II.1.2.2. Pourquoi apprendre le C++ ? — Sa popularité: le C++ est un langage qui est utilisé dans de nombreux projets important (citons Libre Office , 7-zip ou encore KDE ). Il est au programme de beaucoup de formations informatiques. Il possède une communauté très importante, beaucoup de documentation et d’aide, surtout sur l’internet anglophone. — Sa rapidité: C++ offre un grand contrôle sur la rapidité des programmes. C’est cette caractéristique qui fait de lui un des langages de choix pour les programmes scientifiques, par exemple. — Sa facilité d’apprentissage: depuis sa version de 2011, C++ est beaucoup plus facile à apprendre que par le passé. Et ça tombe bien, c’est sur cette version et les suivantes que va se baser ce cours. — Son ancienneté: C++ est un langage ancien d’un point de vue informatique (30 ans, c’est énorme), ce qui donne une certaine garantie de maturité, de stabilité et de pérennité (il ne disparaîtra pas dans quelques années). — Son évolution: C++11 est un véritable renouveau de C++, qui le rend plus facile à utiliser et plus puissant dans les fonctionnalités qu’il offre aux développeurs. C++14 et C++17 améliorent encore la chose. — Il est multi-paradigme: il n’impose pas une façon unique de concevoir et découper ses programmes mais laisse le développeur libre de ses choix, contrairement à d’autres langages comme Java ou Haskell . Bien entendu, tout n’est pas parfait et C++ a aussi ses défauts. — Son héritage du C: C++ est un descendant du langage C, inventé dans les années 1970. Certains choix de conception, adaptés pour l’époque, sont plus problématiques aujourd’hui, et C++ les traine avec lui. — Sa complexité: il ne faut pas se le cacher, avoir une certaine maîtrise du C++ est très long et demandera des années d’expérience, notamment parce que certaines des fonctionnalités les plus puissantes du C++ requièrent de bien connaître les bases. — Sa bibliothèque standard: bien qu’elle permette de faire beaucoup de choses (et d’ailleurs, nous n’aurons même pas le temps d’en faire un tour complet dans ce cours), elle n’offre pas de mécanisme natif pour manipuler des bases de données, faire des 20 II. Le début du voyage II.2.1.0.1. Survol de Wandbox Figure II.2.1. – L’interface de Wandbox. 1. En haut à gauche, dans un encart vert, c’est le langage de programmation utilisé. Si un autre nom que C++ est écrit, pas de soucis, il suffit de cliquer sur la liste déroulante en dessous, puis sur «C++» et choisir «GCC HEAD» ou «Clang HEAD» (qui sont les toutes dernières versions de ces compilateurs). 2. Un peu plus bas, la liste déroulante commençant par C++ permet de choisir la version du langage. Dans ce tutoriel, nous utiliserons la version «C++17», qui correspond à la version 2017 du langage. Que vous choisissiez «C++17» ou «C++17 (GNU)», cela n’a aucune importance à notre niveau. 3. La grande zone de texte blanche est là où nous écrirons le code. 4. Enfin, le bouton Run (or Ctrl + Enter) servira à lancer le compilateur et lui faire compiler le code écrit dans l’encadré précédent. 5. Quand la compilation est terminée, le résultat apparait ici. II.2.2. Des outils plus poussés Les outils en ligne sont très bien pour des petits codes rapides ou pour faire quelques tests, mais ils sont quand même limités. Sachez qu’il existe cependant des outils très complets tant pour Windows que pour GNU/Linux. Comme mentionné dans le cours d’introduction à la programmation , on peut utiliser un ensemble d’outils et de logiciels différents ou bien utiliser un IDE. 23 II. Le début du voyage II.2.2.1. Visual Studio Community L’IDE par excellence de Microsoft, qui permet de programmer non seulement en C++, mais aussi en Python, en JavaScript, en C#, etc. Configurable, extensible, léger par défaut dans sa version 2019, il est en plus 100% gratuit dans le cadre de l’apprentissage, de la recherche ou des projets open source. Vous n’aurez donc pas besoin de débourser quoi que ce soit pour l’utiliser. Inconvénient? Il n’est disponible que pour Windows (dans sa version 7 au minimum). Pour le télécharger et l’installer, je vous invite à suivre la documentation fournie par Microsoft . L’installation demande une connexion Internet. Figure II.2.2. – Vérifiez que la case C++ est bien cochée. Une fois que Visual Studio est installé pour la première fois et configuré, on arrive sur l’écran d’accueil. Figure II.2.3. – L’écran d’accueil de Visual Studio 2019. On peut directement créer un nouveau projet, ou bien aller directement à la page principale, vide. 24 II. Le début du voyage Figure II.2.4. – La page principale de Visual Studio 2019 est bien vide. Que l’on choisisse de créer directement un nouveau projet, ou bien que, depuis la page d’accueil, on clique sur Fichier -> Nouveau -> Projet… , on se retrouve sur le même écran. Figure II.2.5. – On a le choix de créer tout un tas de projets différents. 25 II. Le début du voyage II.2.2.2. Qt Creator ! Non supporté Nous vous proposons ci-dessous Qt Creator car c’est un autre poids-lourd des IDE, mais aucun de nous deux ne l’utilise ni ne saurait vous aider en cas de problème avec. Les explications qui suivent seront peut-être périmées ou inexactes. Nous en sommes désolé, mais cela demande beaucoup de travail que de les maintenir constamment à jour. Vous pourrez néanmoins trouver un tutoriel français ici , sur le site de @gbdivers, un spécialiste de Qt. Un autre grand IDE pour programmer en C++ se nomme Qt Creator , disponible sous Windows, MacOS et GNU/Linux. Il est fourni par une compagnie du nom de Qt, qui édite également une bibliothèque C++ très populaire et répandue, que vous aurez peut-être l’occasion de croiser ou d’apprendre une fois ce cours terminé. Téléchargez la version Open Source, puis installez-la. Sélectionnez la dernière version de Qt disponible et, dans Tools, prenez la version la plus à jour de MinGW. L’installation peut être plus ou moins longue, en fonction de la qualité de votre connexion Internet notamment. Figure II.2.10. – Voici l’écran d’accueil, au lancement de Qt Creator. Pour créer un nouveau projet, cliquez sur Fichier -> Nouveau fichier ou projet… , puis dans Projets -> Non-Qt Project -> Plain C + Application . 28 II. Le début du voyage Figure II.2.11. – Écran de choix du projet. Cliquez ensuite sur Choose . L’écran d’après vous demande le nom du projet et où il sera localisé. 29 II. Le début du voyage Figure II.2.12. – Choix du nom et de la localisation du projet. Sur les écrans d’après, laissez les choix par défaut et cliquez à la fin sur Terminer . Ouvrez enfin le fichier se terminant par .pro et ajouter la première ligne pour une version de Qt inférieur à 5.12, la deuxième à partir de Qt 5.12. Avant Qt 5.12 1 CONFIG += c++1z À partir de Qt 5.12 1 CONFIG += c++17 II.2.2.3. Pour les autres outils Si vous souhaitez utiliser un autre outil que ceux cités plus haut, vous pouvez, bien entendu. Par contre, vous devrez vous débrouiller pour le configurer, car on ne peut malheureusement 30 II.3. Rencontre avec le C++ Que diriez-vous de rentrer directement dans le vif du sujet en écrivant votre premier code C++? Nous allons commencer par l’un des exemples les plus connus et les plus utilisés: afficher un message. Et, vous verrez, il y a déjà de quoi dire. II.3.1. Compilons notre premier programme Allez donc sur Wandbox , ou bien ouvrez votre projet C++, et copiez-collez ce code dans la zone de texte. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Hello World !" << std::endl; // affiche Hello World ! 6 return 0; 7 } Cliquez ensuite sur Run (pour WandBox), faites Ctrl + F5 (Visual Studio Community), Ctrl + R (Qt Creator), ou compilez et exécutez en ligne de commande, et sous vos yeux émerveillés s’affiche le résultat suivant. 1 Hello World ! Félicitations, vous venez de compiler votre tout premier programme C++! Mais je devine que vous voulez comprendre ce qui s’est passé et avoir des explications sur ce que signifie ce code. 33 II. Le début du voyage II.3.2. Démystification du code II.3.2.1. Inclure des fonctionnalités déjà codées 1 #include <iostream> Le but de notre programme est d’afficher un message. Des développeurs experts ont déjà créé un outil qui permet de le faire facilement. Il se trouve dans un fichier nommé «iostream», acronyme de «Input Output Stream», soit «Flux d’Entrées Sorties» dans la langue de Molière. Ce fichier fait partie de la bibliothèque standard C++, un ensemble de fonctionnalité déjà pré-codées et incluses partout avec chaque compilateur C++. Pour utiliser les fonctionnalités offertes par ce fichier, notamment écrire un message, on doit l’importer dans notre programme. On dit qu’on l’inclut, d’où l’anglais «include». Nous utiliserons beaucoup cette fonctionnalité tout au long du cours. Enfin, dernière remarque, avez-vous noté que la ligne commence par le symbole #? C’est ce qu’on appelle une directive de préprocesseur. Le préprocesseur est un programme qui se lance automatiquement au début de la compilation, notamment pour importer les fichiers qu’on lui demande. Nous le détaillerons plus loin dans ce cours. Retenez que #include nous permet d’importer des fichiers que des programmeurs experts ont déjà écrits avant nous. II.3.2.2. Le point d’entrée 1 int main() 2 { 3 4 } Quant l’ordinateur exécute un programme, il lui faut bien un endroit où commencer, un début, un point d’entrée. À partir de ce point d’entrée, il exécutera des instructions, des ordres, que nous aurons au préalable écrits. Cet endroit s’appelle main (prononcé «mèïne») et est la fonction principale de tout programme C++. Qu’est-ce qu’une fonction? C’est un un regroupement d’instructions. En C++, vous trou- verez ainsi des fonctions pour calculer une racine carrée, pour comparer des durées, trier une liste d’objets, afficher des messages, etc. Nous en utiliserons beaucoup déjà existantes et, plus tard, apprendrons à créer nos propres fonctions. Dans notre cas, la fonction main regroupe deux instructions différentes. 34 II. Le début du voyage II.3.2.3. Voici mes instructions… 1 std::cout << "Hello World !" << std::endl; // Affiche le message Hello World ! La première instruction est justement celle qui nous permet d’afficher un message. Elle débute avec std::cout (à prononcer «ci-aoûte»), qui représente la sortie standard en C++, c’est-à-dire la communication du programme vers l’utilisateur, par l’écran dans notre cas. Le préfixe std:: indique que vous utilisez une fonctionnalité déjà programmée et fournie dans la bibliothèque standard C++. On note ensuite la présence de deux chevrons < qui permettent d’injecter, d’envoyer, du contenu dans la sortie standard, dans std::cout. Dans notre code d’introduction, nous injectons deux choses. — D’abord, "Hello World !", qui est le message que l’on voit s’afficher à l’écran. — Puis std::endl, qui permet d’aller à la ligne, comme son nom l’indique («end line» que l’on traduit par «retour à la ligne»). De même que pour std::cout, std::endl est fourni par la bibliothèque standard. Enfin, elle se termine par un point-virgule ; qui est obligatoire. Chaque instruction doit être terminée par un point-virgule. Ce sont les règles du C++ qui veulent ça. i Chevrons On peut combiner les chevrons < autant que l’on souhaite. Essayez donc d’afficher la phrase «Bonjour, j’écris du C++» suivi d’un retour à la ligne, suivi de «Et j’aime beaucoup.» Contenu masqué n°1 ! Un mot sur Windows Si vous êtes sous Windows et que vous tentez d’afficher du texte avec des accents, vous allez obtenir des caractères bizarres. Pour afficher du code avec des accents, vous allez devoir ajouter les lignes 2, 3 et 8 dans votre code. Nous en reparlerons plus tard. 35 II. Le début du voyage — Les commentaires sont ignorés par le compilateur mais nous sont très utiles à nous, humains. Contenumasqué Contenumasqué n°1 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Bonjour, j'écris du C++" << std::endl << "Et j'aime beaucoup."; 6 7 return 0; 8 } Retourner au texte. 38 II.4. Une super mémoire Vous savez désormais afficher des messages à l’écran. C’est un bon début, mais on est quand même assez limités, n’est-ce pas? Rassurez-vous, C++ nous permet de faire bien plus que ça. Grâce à ce langage, nous allons nous amuser avec cette super calculatrice qu’est notre ordinateur et nous découvrirons qu’il possède aussi une super mémoire! Ce chapitre va nous faire découvrir les littéraux et les variables. II.4.1. Les littéraux Que sont les littéraux? Une valeur écrite littéralement dans le code, d’où son nom. Nous avons rencontré un littéral dans le chapitre précédent: "Hello World !". Ce littéral est ce qu’on appelle une chaîne de caractères. Mais ce n’est pas le seule littéral possible en C++. Examinons tout ça. II.4.1.1. Les caractères Nous avons fait connaissance avec les chaînes de caractères lors du chapitre précédent. Les chaînes de caractères ne sont rien d’autre que du texte. On les reconnait parce qu’elles commencent et finissent par des doubles guillemets ". Entraînez-vous donc à afficher des chaînes de caractères, par exemple un littéral souhaitant une bonne journée. Contenu masqué n°2 Tous comme les mots de la langue française sont des regroupements de lettres, les chaînes de caractères sont une suite de caractères simples. En C++, un caractère est encadré par des guillemets simples '. 1 #include <iostream> 2 3 int main() 4 { 5 // Un caractère peut être une lettre. 6 std::cout << 'A' << std::endl; 7 // Ou bien un chiffre. 39 II. Le début du voyage 8 std::cout << '7' << std::endl; 9 // Ou même de la ponctuation. 10 std::cout << '!' << std::endl; 11 12 return 0; 13 } Les chaînes de caractères permettent de regrouper des caractères et nous facilitent ainsi la vie pour écrire du texte. 1 #include <iostream> 2 3 int main() 4 { 5 // Que c'est fastidieux d'écrire ça ! 6 std::cout << 'S' << 'a' << 'l' << 'u' << 't' << ' ' << 't' << 'o' << 'i' << ' ' << '!' << std::endl; 7 // C'est tellement mieux comme ça. 8 std::cout << "Salut toi !" << std::endl; 9 10 return 0; 11 } ? J’ai mis plusieurs caractères entre guillemets simples, comme ceci 'abc' et mon code compile. Ça veut dire que ça marche? Si vous avez essayé de compiler, vous avez remarqué un message en rouge dans la fenêtre de résultat disant warning: multi-character character constant, ainsi qu’un nombre au lieu de nos caractères. Le warning est un message d’avertissement que le compilateur vous envoie, car il ne sait pas si ce que vous avez fait est une erreur d’inattention ou bien une manœuvre volontaire de votre part. Dans notre cas, la norme C++ n’interdit pas de faire ça, mais ce n’est pas considéré comme une bonne pratique, comme étant du bon code. ! N’ignorez pas les warnings! Les warnings sont des messages importants signalant d’éventuels problèmes. Il ne faut surtout pas les ignorer sous prétexte que le code compile! II.4.1.1.1. Des caractères spéciaux Il existe quelques caractères qui sont un peu particuliers et, pour les introduire, je vais vous demander d’afficher un message contenant un chemin de dossier Windows (C:\Program Files 40 II. Le début du voyage 6 std::cout << "1 - 4 = " << 1 - 4 << std::endl; 7 std::cout << "7.5 * 2 = " << 7.5 * 2 << std::endl; 8 9 std::cout << "9 / 2 = " << 9 / 2 << std::endl; 10 std::cout << "9. / 2 = " << 9. / 2 << std::endl; 11 std::cout << "9 % 2 = " << 9 % 2 << std::endl; 12 13 return 0; 14 } ? Attends, qu’est-ce que c’est que ça? 9 / 2 et 9. / 2 ne donne pas la même chose? Et c’est quoi %? En fait, la raison est très simple: pour C++, si on fait une opération sur deux nombres entiers, le résultat est un nombre entier. Si l’on veut que le résultat soit un nombre à virgule, il faut qu’au moins un des deux nombres soit un flottant. Dans le cas de la division, si les deux nombres sont des entiers, on obtient le quotient de la division euclidienne, le reste s’obtenant avec l’opérateur %, appelé modulo (c’est de l’arithmétique ). Si l’un des deux nombres est un flottant, alors on obtient le résultat de la division réelle, donc un nombre réel. Également, comme en maths, les calculs respectent la distributivité , l’associativité , la commutativité et la priorité des opérateurs . L’exemple suivant est tiré du cours de @gbdivers. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Commutativité :" << std::endl; 6 std::cout << "2 + 3 = " << 2 + 3 << std::endl; 7 std::cout << "3 + 2 = " << 3 + 2 << std::endl; 8 9 std::cout << "Associativité :" << std::endl; 10 std::cout << "2 + (3 + 4) = " << 2 + (3 + 4) << std::endl; 11 std::cout << "(2 + 3) + 4 = " << (2 + 3) + 4 << std::endl; 12 13 std::cout << "Distributivité :" << std::endl; 14 std::cout << "2 * (4 + 3) = " << 2 * (4 + 3) << std::endl; 15 std::cout << "2 * 4 + 2 * 3 = " << 2 * 4 + 2 * 3 << std::endl; 16 17 std::cout << "Priorité des opérateurs :" << std::endl; 18 std::cout << "2 * 6 + 3 = " << 2 * 6 + 3 << std::endl; 19 std::cout << "2 * (6 + 3) = " << 2 * (6 + 3) << std::endl; 20 std::cout << "2 * 4 - 6 / 2 = " << 2 * 4 - 6 / 2 << std::endl; 43 II. Le début du voyage 21 22 return 0; 23 } Nous nous sommes amusés avec les littéraux, mais on est quand même rapidement limité. Imaginons que nous voulions multiplier le résultat précédent par 2 et ce, trois fois. Nous sommes obligés d’écrire un code comme ceci. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "1 * 2 = " << 1 * 2 << std::endl; 6 std::cout << "1 * 2 * 2 = " << 1 * 2 * 2 << std::endl; 7 std::cout << "1 * 2 * 2 * 2 = " << 1 * 2 * 2 * 2 << std::endl; 8 9 return 0; 10 } Maintenant, imaginons qu’on ne multiplie plus par 2 mais par 4, et non plus trois fois mais cinq. Vous visualisez bien tous les changements à faire? C’est pénible, n’est-ce pas? N’y a-t-il pas un moyen de se souvenir de valeurs et de calculs? II.4.2. Les variables La réponse à la question soulevée dans la section précédente se trouve dans le titre. Il s’agit des variables. C’est un concept commun à beaucoup de langages de programmation qui permet de stocker une valeur et de lui associer un nom, afin de faciliter tant l’écriture que la lecture du code. On peut les voir comme des enveloppes, des tiroirs, des conteneurs, bref, une zone où est stockée une valeur, à laquelle on associe un nom. ? Elle est où, cette «zone de stockage»? Toutes les variables sont stockées dans la mémoire vive de l’ordinateur, la RAM . Son fonctionnement est un peu complexe et ne nous intéresse pas (dans le cadre de ce cours tout du moins). Les curieux trouveront beaucoup de ressources sur Internet pour combler leur soif de savoir, allant de la vulgarisation simple à des explications complètes . II.4.2.1. Comment créer des variables en C++ ? Pour déclarer une variable en C++, il faut trois éléments obligatoires. 44 II. Le début du voyage — D’abord, un type, qui indique ce que la variable va stocker (un entier, une chaîne de caractères, etc). — Ensuite, un identificateur, c’est-à-dire le nom associé à la variable. — Enfin, il faut bien donner une valeur à stocker à notre variable. Ceci se fait en mettant cette valeur entre accolades { }. Examinons un cas réel que nous détaillerons. 1 #include <iostream> 2 #include <string> 3 4 int main() 5 { 6 int reponse { 42 }; 7 std::cout << "La réponse à la Grande Question est " << reponse << std::endl; 8 9 double pi { 3.1415926 }; 10 std::cout << "Voici la valeur du célèbre nombre pi : " << pi << std::endl; 11 12 char lettre { 'A' }; 13 std::cout << "La première lettre de l'alphabet français est " << lettre << std::endl; 14 15 std::string phrase { "Bonjour tout le monde !" }; 16 std::cout << "En entrant dans la salle, il s'écria : " << phrase << std::endl; 17 18 return 0; 19 } 1 La réponse à la Grande Question est 42 2 Voici la valeur du célèbre nombre pi : 3.14159 3 La première lettre de l'alphabet français est A 4 En entrant dans la salle, il s'écria : Bonjour tout le monde ! i Syntaxe héritée Il existe une syntaxe alternative, de la forme type identificateur = valeur;. Essayez, vous verrez que ça marche. 45 II. Le début du voyage imposées par C++, cela ne veut pas dire que la variable est bien nommée. — variable: ne veut rien dire. Que stocke-t-elle? Quel est son but? Pourquoi existe-t-elle? — variable_contenant_la_multiplication_de_pi_par_e_au_cube: beaucoup trop long. — cIrCoNfErEnCe_CeRcLe: le nom définit bien le pourquoi de l’existence de notre variable, mais le mélange majuscule / minuscule le rend illisible. — Brzęczyszczykiewicz: aucun sens, sauf si vous aimez l’humour polonais . Avec le temps, en progressant, vous arriverez à trouver plus rapidement et plus facilement des identificateurs qui soient clairs et simples. Dans le cours, je m’efforcerai de le faire afin de vous donner des exemples concrets. II.4.2.1.4. Sinon, par défaut… Abordons un dernier point. Je vous ai dit qu’on donne une valeur entre accolades pour initialiser notre variable. Mais que se passe-t-il si on écrit simplement les accolades, sans aucune valeur dedans? Le code va-t-il toujours compiler? 1 #include <iostream> 2 #include <string> 3 4 int main() 5 { 6 int entier {}; 7 std::cout << "Mon entier vaut " << entier << std::endl; 8 9 double reel {}; 10 std::cout << "Mon réel vaut " << reel << std::endl; 11 12 char lettre {}; 13 std::cout << "Mon caractère vaut " << lettre << std::endl; 14 15 std::string phrase {}; 16 std::cout << "Ma chaîne vaut " << phrase << std::endl; 17 18 return 0; 19 } 1 Mon entier vaut 0 2 Mon réel vaut 0 3 Mon caractère vaut 4 Ma chaîne vaut Non, le programme n’a pas de bugs, il fonctionne très bien. En fait, si aucune valeur n’est spécifiée, nos variables sont initialisées à une valeur par défaut. Pour les entiers et les réels, 48 II. Le début du voyage il s’agit de zéro. Pour les caractères, c’est une valeur spéciale signifiant «pas de caractère», de même que pour les chaînes de caractères, initialisées avec du vide. i À vous de choisir C++ vous laisse libre de vos choix. Dans ce cours, pour commencer, nous écrirons toujours les valeurs explicitement. Au fur et à mesure que vous progresserez, nous utiliserons de plus en plus souvent l’initialisation par défaut. II.4.2.2. Un peu de constance, voyons ! Terminons cette partie en présentant un mot-clé important qui a pour nom const. Il permet d’empêcher toute modification de la variable sur laquelle ce mot-clé s’applique. On dit qu’on crée une constante. Et si l’on essaye de modifier une constante, le compilateur refuse clair et net. 1 int main() 2 { 3 double const pi { 3.141592 }; 4 pi = 4; // Ouch, badaboum ça ne compile pas. 5 6 return 0; 7 } 1 [Visual Studio] 2 C3892 'pi' : vous ne pouvez pas assigner une variable const. 3 4 ------------------------------------------------------------ 5 6 [GCC] 7 prog.cc: In function 'int main()': 8 prog.cc:4:8: error: assignment of read-only variable 'pi' 9 4 | pi = 4; // Ouch, badaboum ça ne compile pas. 10 | ~~~^~~ 11 12 ------------------------------------------------------------ 13 14 [Clang] 15 prog.cc:4:8: error: cannot assign to variable 'pi' with const-qualified type 'const double' 16 pi = 4; // Ouch, badaboum ça ne compile pas. 17 ~~ ^ 18 prog.cc:3:18: note: variable 'pi' declared const here 19 double const pi { 3.141592 }; 49 II. Le début du voyage 20 ~~~~~~~~~~~~~^~~~~~~~~~~~~~~ 21 1 error generated. Certains choisissent de les écrire entièrement en majuscule pour bien les différencier des autres variables. Ce n’est absolument pas une obligation et nous n’imposons sur ce point aucune règle. Quelle en est l’utilité? Il sert pour la qualité du code. Tout ce qui n’est pas destiné à être modifié est ainsi protégé. Cela nous permet également de donner des garanties fortes à notre code. C’est pour ça que nous allons l’utiliser dans tous les exemples. Vous verrez plus tard dans le cours d’autres cas utiles. i Ordre du const Vous verrez souvent des codes qui inversent l’ordre de const et écrivent const int constante {};. Cela est légal et possible en C++, car const respecte une règle simple: il s’applique à ce qui est à sa gauche immédiate, sauf s’il n’y a rien, auquel cas il s’applique à ce qu’il y a à droite. Ici, cela ne change rien, mais plus tard cela aura des conséquences. Nous verrons cela en temps voulu. II.4.2.3. Manipulation de variables Nous ne sommes absolument pas obligés de nous contenter d’afficher nos variables. Au contraire, nous pouvons faire beaucoup d’opérations dessus, notamment combiner les variables entre elles et modifier leur valeur. 1 #include <iostream> 2 3 int main() 4 { 5 int entier { 4 }; 6 std::cout << "Mon entier vaut : " << entier << std::endl; 7 8 // Je peux tout à fait changer la valeur de ma variable. 9 entier = 4 * (8 + 9) - 1; 10 std::cout << "Finalement non, il vaut : " << entier << std::endl; 11 12 // Je peux même utiliser la valeur de ma variable et la réaffecter à la même variable. 13 entier = entier + 7; 14 std::cout << "Et si j'additionne 7 ? " << entier << std::endl; 15 16 int autre_entier { entier * 2 }; 17 // Je peux utiliser d'autres variables également. 50 II. Le début du voyage 1 int main() 2 { 3 // Comme 0 est déjà un littéral entier, pourquoi donc préciser 'int' ? 4 int entier { 0 }; 5 6 // Comme 3.1415 est déjà un littéral flottant, pourquoi donc préciser 'double' ? 7 double reel { 3.1415 }; 8 9 return 0; 10 } Le compilateur peut en effet déduire tout seul le type d’une variable et cela grâce à un nouveau mot-clef: auto. Celui-ci s’utilise en lieu et place du type de la variable. Notre code précédent peut ainsi être réécrit de la manière qui suit. 1 int main() 2 { 3 // Hop, le compilateur déduit que 'entier' est de type 'int'. 4 auto entier { 0 }; 5 6 // Hop, le compilateur déduit que 'reel' est de type 'double'. 7 auto reel { 3.1415 }; 8 9 return 0; 10 } II.4.3.1. Avec const Tout comme dans le cas d’une variable dont le type est explicitement écrit, si vous voulez déclarer une constante, il suffit de rajouter const. 1 int main() 2 { 3 auto const constante { 40 }; 4 return 0; 5 } 53 II. Le début du voyage II.4.3.2. Le cas de std::string Dans le cas des chaînes de caractères, c’est un peu particulier. Déjà, il faut rajouter un s après les guillemets fermants ", et ce pour chaque chaîne de caractères que vous voulez écrire. Ensuite, il faut rajouter une ligne spéciale. Nous expliquerons pourquoi plus loin dans ce cours. L’exemple suivant va vous aider à comprendre. 1 #include <string> 2 3 int main() 4 { 5 // Écrivez cette ligne une seule fois. 6 using namespace std::literals; 7 8 // Puis vous pouvez déclarer autant de chaînes de caractères que vous voulez. 9 auto chaine { "Du texte."s }; 10 auto autre_chaine { "Texte alternatif."s }; 11 auto encore_une_chaine { "Allez, un dernier pour la route."s }; 12 13 return 0; 14 } i Histoire et héritage Si nous sommes obligés de rajouter le s en fin de littéral, c’est parce que nous avons affaire ici à un héritage du C. Sans celui-ci, le compilateur déduit que notre littéral est une chaîne de caractères comme en C et non comme étant une std::string. Nous en reparlerons au moment voulu, mais retenez que ce s est très important dès que vous utilisez auto. II.4.3.3. Les avantages Utiliser auto présente deux avantages majeurs. — D’abord, utiliser auto permet de raccourcir le code. Là, remplacer double par auto n’est pas un gain de place énorme, mais, plus tard dans ce cours, nous verrons des types longs à écrire et lourds à lire, qu’il sera bien plus agréable de remplacer par un concis auto. — Ensuite, cela permet un code plus évolutif. Imaginez des calculs complexes avec des types écrits explicitement. Si vous voulez changer l’un des types, il faut en changer chaque occurrence. Avec auto, vous laissez au compilateur le soin de s’occuper de cette tâche. ? Je suis perdu. Qu’est-ce que je dois choisir entre auto ou le type explicite? 54 II. Le début du voyage C++ vous autorise à faire les deux, donc le choix est vôtre. Certains programmeurs ne jurent que par auto et l’utilisent partout. D’autres préfèrent le réserver aux types longs ou complexes et écrire explicitement les types simples et courts. Dans le cadre de ce cours, j’utiliserai les deux façons de faire. II.4.4. Les entrées Dès le premier code C++ que vous avez étudié, il y avait la notion de sortie standard. Il est temps de voir le concept inverse en manipulant l’entrée standard. Maintenant que nous connaissons le concept des variables, demander des informations à l’utilisateur est à notre portée. Il faut en effet pouvoir stocker quelque part la valeur qu’a tapée l’utilisateur, ce que permettent justement les variables. Manipuler les entrées est un peu particulier avec Wandbox. Il faut cliquer sur l’encadré stdin et taper la valeur que vous souhaitez rentrer. C’est moins pratique qu’avec un IDE. Peu importe ce que vous préférez, l’essentiel est que vous puissiez manipuler pour comprendre la suite du chapitre. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Entre ton age : " << std::endl; 6 int age { 0 }; 7 std::cin >> age; 8 std::cout << "Tu as " << age << " ans.\n"; 9 10 return 0; 11 } Avez-vous remarqué à quel point cin est semblable à cout? Déjà, pour l’utiliser, il faut le préfixer par std::, car cin est un objet appartement à la bibliothèque standard. Et on utilise les chevrons dans le sens inverse de cout. II.4.4.1. Gestion des erreurs Et si vous rentrez une valeur qui n’a rien à voir? Que se passe-t-il si je décide de taper Maurice au lieu de 5? Essayez donc. 1 Entre ton age : 2 Maurice 3 Tu as 0 ans. 4 Appuyez sur une touche pour continuer... 55 II. Le début du voyage Contenumasqué n°3 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Dossier principal : C:\Program Files (x86)" << std::endl; 6 7 return 0; 8 } Retourner au texte. Contenumasqué n°4 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Voici un exemple sans échappement : " << "'" << " est bien affiché." << std::endl; 6 std::cout << "Maintenant, je vais l'échapper : " << '\'' << " est bien affiché grâce à l'échappement." << std::endl; 7 8 std::cout << "La suite, après la tabulation : \tJe suis loin." << std::endl; 9 std::cout << "Ces mots sont sur une ligne.\nEt ceux là sur la suivante.\n"; 10 11 return 0; 12 } Retourner au texte. Contenumasqué n°5 1 #include <iostream> 2 3 int main() 4 { 58 II. Le début du voyage 5 int nombre { 1 }; 6 int const multiplicateur { 2 }; 7 8 nombre = nombre * multiplicateur; 9 std::cout << "Maintenant, mon nombre vaut " << nombre << std::endl; 10 11 nombre = nombre * multiplicateur; 12 std::cout << "Maintenant, mon nombre vaut " << nombre << std::endl; 13 14 nombre = nombre * multiplicateur; 15 std::cout << "Maintenant, mon nombre vaut " << nombre << std::endl; 16 17 return 0; 18 } i Vous remarquerez qu’on répète quand même plusieurs fois les mêmes instructions. Ce n’est pas grave. Nous verrons très bientôt comment remédier à ce problème. L’essentiel est que vous ayez pu voir l’avantage d’utiliser des variables. Retourner au texte. 59 II.5. Le conditionnel conjugué en C++ «Le conditionnel est un mode employé pour exprimer un état soumis à une condition.» Telle est la définition qu’en donne Wikipédia . Cela vous rappelle-t-il vos cours de français? Mais quel peut bien être le rapport avec la programmation? C’est que C++ permet aussi d’exprimer des conditions et donc de modifier le comportement de notre programme. Ce chapitre va donc introduire les conditions à notre palette d’outils et permettra de résoudre la problématique soulevée en conclusion du chapitre précédent. II.5.1. Les booléens Les conditions en C++ sont régies par un principe simple, qui est qu’une condition est soit vraie, soit fausse. Finalement, c’est un peu comme dans la réalité. Si je vous pose la question «Êtes-vous majeurs?», la réponse est soit oui, soit non. De même, «Faîtes-vous 1m80 ou plus?» entraînera soit une réponse positive, soit négative. C++ nous offre un type conçu exprès pour ça, bool. Ce type peut prendre deux valeurs: soit true, signifiant vrai, soit false qui veut dire faux. Voyez par vous-mêmes l’exemple on ne peut plus bête ci-dessous. 1 int main() 2 { 3 bool const vrai { true }; 4 bool const faux { false }; 5 6 return 0; 7 } ? D’accord, mais ça sert à quoi ça? Je vois l’intérêt de manipuler des entiers ou du texte, mais stocker juste vrai ou faux, ça sert quand? L’intérêt semble en effet très faible si l’on se contente du code précédent. Sachez que les booléens sont partout, utilisables grâce à ce que l’on appelle les opérateurs de comparaisons. En voici la liste juste ci-dessous. Opérateur Signification Exemple == Égalité, compare si deux variables sont égales entre elles. a == b 60 II. Le début du voyage Prenons un exemple. Affichons la note à un examen, rentrée par l’utilisateur. Si celle-ci est supérieure ou égale à 16, nous afficherons un message de félicitations. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Indique-moi ta note : "; 6 7 int note { 0 }; 8 std::cin >> note; 9 10 std::cout << "Tu as obtenu " << note << std::endl; 11 12 if (note >= 16) 13 { 14 std::cout << "Félicitations, c'est une très bonne note !" << std::endl; 15 } 16 17 return 0; 18 } Faites-le tourner. Vous verrez, le message de félicitations ne s’affiche que si vous rentrez un nombre supérieur ou égal à 16. Essayez avec 15, vous ne verrez plus le message. II.5.2.1. À portée Nous pouvons également déclarer des variables au sein du bloc d’accolades. Cependant, celles-ci ne sont utilisables que jusqu’à l’accolade fermante correspondante. Ainsi, le code ci-dessous n’est pas correct. 1 #include <iostream> 2 3 int main() 4 { 5 if (true) 6 { 7 int const age { 42 }; 8 // D'autres instructions. 9 10 // Aucun problème. 11 if (age == 42) 12 { 13 // Ici non plus. 14 } 63 II. Le début du voyage 15 } 16 17 // NON ! Le compilateur ne connait pas la variable age. 18 std::cout << age << std::endl; 19 20 return 0; 21 } Ce sont les règles de C++ qui veulent ça. Quand on écrit un nouveau bloc à base d’accolades, on dit qu’on crée une nouvelle portée. Et une variable n’est utilisable que dans la portée, ou le bloc d’accolade, où elle a été déclarée. C’est une bonne pratique de déclarer ses variables dans la plus petite portée possible. Il y a plusieurs raisons à ça. — Dans le cas d’un code long et complexe, déclarer une variable au plus près possible de son utilisation permet de ne pas avoir à parcourir de longues lignes pour en obtenir des détails (quel est son type, sa valeur de base, etc). Cela aide à la lecture et la compréhension du code. — Lorsqu’on atteint la fin du bloc correspondant, le programme libère dans la mémoire les emplacements qu’il avait réservés pour les variables qui s’y trouvaient. Dans le cas d’un int comme ici, ça ne change rien. Mais dans le cas de variables plus complexes que nous verrons plus tard, cela peut avoir une grande incidence sur les performances du programme. Ainsi, je vous encourage fortement à déclarer vos variables à l’intérieur de vos blocs de condition si elles ne sont pas destinées à être utilisées ailleurs. II.5.3. else — Sinon… Maintenant que nous avons vu comment changer le code si une condition est vérifiée, voyons comment faire l’opposé, c’est-à-dire comment agir si celle-ci est fausse. Imaginons un programme demandant si l’utilisateur est majeur ou mineur. On peut imaginer quelque chose comme ce qui suit. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Donne-moi ton âge: "; 6 int age { 0 }; 7 std::cin >> age; 8 9 if (age >= 18) 10 { 11 std::cout << "Tu es majeur." << std::endl; 64 II. Le début du voyage 12 } 13 14 if (age < 18) 15 { 16 std::cout << "Tu es mineur." << std::endl; 17 } 18 19 return 0; 20 } Ce programme est fonctionnel mais un peu lourd, puisqu’on répète deux fois une condition quasiment identique. Heureusement, C++ nous offre un autre mot-clef, else, qui exécute des instructions si la condition du if est fausse. Voyez-vous mêmes le code ci-dessous. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Donne-moi ton âge: "; 6 int age { 0 }; 7 std::cin >> age; 8 9 if (age >= 18) 10 { 11 std::cout << "Tu es majeur." << std::endl; 12 } 13 else 14 { 15 std::cout << "Tu es mineur." << std::endl; 16 } 17 18 return 0; 19 } Le code se lit ainsi en français: «Si l’âge rentré par l’utilisateur est supérieur ou égal à 18 ans, alors afficher “Tu es majeur”, sinon afficher “Tu es mineur”.» Le mot-clef else est en effet un mot d’anglais qui existe et qui signifie, comme vous l’avez compris, «sinon». 65 II. Le début du voyage 14 std::cout << "Salade grecque ? De pâtes ?" << std::endl; 15 } 16 else 17 { 18 std::cout << "Nous avons également de la purée, une macédoine de légumes, une omelette..." << std::endl; 19 } 20 } 21 else 22 { 23 bool const viande { true }; 24 if (viande) 25 { 26 std::cout << "Bleue, saignante, à point, bien cuite ?" << std::endl; 27 } 28 else 29 { 30 std::cout << "Sinon niveau poisson il y a pavé de saumon, filet de cabillaud..." << std::endl; 31 } 32 } 33 34 return 0; 35 } i Instruction condensée L’instruction else if, vue plus haut, correspond en fait à un if dans un else. 68 II. Le début du voyage i 1 if (/* condition 1 */) 2 { 3 } 4 else if (/* condition 2 */) 5 { 6 } 7 8 // Équivaut à ceci. 9 10 if (/* condition 1 */) 11 { 12 } 13 else 14 { 15 if (/* condition 2 */) 16 { 17 } 18 } II.5.6. [T.P] Gérer les erreurs d’entrée — Partie I Vous souvenez-vous de la problématique du chapitre précédent? Nous avions des problèmes quand l’utilisateur rentrait du texte à la place d’un entier, par exemple. Eh bien nous pouvons déjà apporter une première solution à ce problème, solution que nous améliorerons au fur et à mesure. Les développeurs ayant écrit la bibliothèque standard C++ ont déjà tout prévu. Trois fonctions, déjà programmées, vont nous intéresser. — std::cin > x est en fait une fonction qui renvoie true si tout est correct ou false si on a rencontré une erreur lors de la saisie. — std::cin.clear() restaure std::cin à un état fonctionnel, sans erreur. — std::cin.ignore() permet d’ignorer un nombre défini de caractères, soit jusqu’à un nombre maximum (exemple 500), soit jusqu’à un caractère précis (exemple '\n' ou 'a'). Dans notre cas, nous allons utiliser ceci: 1 std::cin.ignore(255, '\n'); Maintenant, vous avez toutes les informations nécessaires pour commencer la protection de nos entrées. À vous de jouer! Correction T.P Partie I 69 II. Le début du voyage Voilà, nous avons déjà une petite protection. Mais elle ne marche qu’une fois: impossible de la faire marcher tant que l’utilisateur n’a pas rentré quelque chose de valide. Pour l’instant, laissez ça de côté, nous en reparlerons dans le prochain chapitre. II.5.7. La logique booléenne Nous avons vu les différents moyens de tester des conditions, ainsi que différents opérateurs de comparaisons qui retournent des booléens. Mais ce ne sont pas les seuls. Cette section va introduire l’algèbre booléenne , et rassurez-vous, c’est simple à comprendre, puissant et bien utile. II.5.7.1. AND — Tester si deux conditions sont vraies Imaginons un instant que vous souhaitiez faire l’acquisition d’une voiture. Pour cela, il vous faut remplir deux conditions: avoir le permis et suffisamment d’argent. Si l’une des deux conditions n’est pas remplie, ou les deux, vous continuerez à prendre le bus. Le seul moyen de faire hurler le moteur sur l’autoroute, c’est d’avoir assez d’argent ET d’avoir le permis. C++ nous fournit deux moyens d’exprimer cet opérateur logique «ET»: && et and. Les deux sont parfaitement valables et interchangeables. Le deuxième était notamment prévu à l’époque où tous les claviers ne possédaient pas le symbole & . ! Ancienne spécificité Microsoft Si and ne marche pas avec Visual Studio, il faut inclure le fichier <ciso646>. Avec une version à jour, ce n’est cependant plus nécessaire. 1 #include <iostream> 2 3 int main() 4 { 5 int const prix_voiture { 5000 }; 6 int const argent { 2000 }; 7 bool const a_le_permis { true }; 8 9 if (argent >= prix_voiture && a_le_permis) 10 { 11 std::cout << "Voici les clés, bonne route." << std::endl; 12 } 13 else 14 { 15 std::cout << "Désolé, vous allez devoir prendre le bus." << std::endl; 16 } 17 70 II. Le début du voyage serait de ne traiter que le cas «Pas de maillot de bain». C++ nous permet justement cela avec l’opérateur de négation ! ou not. Celui-ci renvoie la valeur inverse de l’expression testée. Si l’expression vaut true, alors cet opérateur renverra false; si, au contraire, elle valait false, sa négation donnera true. ! Ancienne spécificité Microsoft Si not ne marche pas avec Visual Studio, il faut inclure le fichier <ciso646>. Avec une version à jour, ce n’est cependant plus nécessaire. 1 int main() 2 { 3 bool const ai_je_un_maillot { true }; 4 if (!ai_je_un_maillot) 5 { 6 // Je dois aller acheter un maillot. 7 } 8 9 // Je nage et je suis heureux. 10 return 0; 11 } Notre code devient plus court, plus concis et plus agréable à lire, il gagne en qualité. Je vous mets en dessous la table de vérité, bien plus courte cette fois. Valeur de la condition Résultat de l’opérateur «NOT» true false false true ? Il y a juste quelque chose que je ne comprends pas. Pourquoi ne pas créer tout simplement un booléen inverse, genre pas_de_maillot? Pourquoi se casser la tête à tester la négation d’une condition et ne pas tester la condition inverse tout de suite? C’est une très bonne question. Dans un exemple aussi simpliste que celui-ci, monté de toute pièce, on aurait pu, c’est vrai. Mais d’autres fois nous n’avons pas le choix, car nous utilisons du code qui a été programmé d’une certaine façon. II.5.8. Tester plusieurs expressions Nous ne sommes absolument pas limités à tester deux expressions en même temps. On peut le faire avec trois, quatre, dix, soixante (bien que soixante soit un exemple extrême et vraiment trop peu lisible). Le code suivant le prouve. 73 II. Le début du voyage 1 #include <iostream> 2 3 int main() 4 { 5 bool const ai_je_envie_de_nager{ true }; 6 bool const ai_je_un_maillot { true }; 7 int const argent { 20 }; 8 int const prix { 5 }; 9 10 if (ai_je_envie_de_nager && ai_je_un_maillot && argent >= prix) 11 { 12 std::cout << "PLOUF !" << std::endl; 13 } 14 else 15 { 16 std::cout << "Huum, un autre jour." << std::endl; 17 } 18 19 return 0; 20 } Dans le cas du même opérateur, ils sont évalués de gauche à droite. C’est le cas du code précédent. Mais que se passe t-il si l’on mélange plusieurs opérateurs différents dans la même expression? Sauriez-vous dire ce que quelque chose comme expression1 && expression 2 || expression3 va donner? En effet, les opérateurs logiques sont comme les opérateurs mathématiques que nous avons vus dans les chapitres précédents: ils ont une priorité. 1. Le plus prioritaire, c’est la négation !. 2. Ensuite vient le «ET» &&. 3. Enfin, le «OU» || est le moins prioritaire. Ainsi, dans l’exemple !a && b, c’est d’abord !a qui est évalué, puis la nouvelle valeur et b sont testées avec l’opérateur ET &&. Avec le code a && b || c && d, dans l’ordre, on évalue a && b, c && d et enfin a && b || c && d. Bien que la priorité des opérateurs soit clairement définie par C++, une bonne pratique consiste à ajouter des parenthèses autour des expressions pour rendre le code plus lisible et plus clair. Si l’on reprend nos exemples, cela donne (!a) && b pour le premier et (a && b) || (c && d) pour le deuxième. C’est clair? Prouvez-le-moi en mettant les parenthèses au bon endroit dans ces codes (piqués à @gbdivers). 1 a && b && c 2 a || b || c 3 a || b && c 4 a && b || c 5 74 II. Le début du voyage 6 !a && b 7 a || !b 8 9 a && b || c && d 10 a || b && c || d Correction i Parenthèses À partir de maintenant, je vais mettre des parenthèses dans le code pour le rendre clair et explicite. II.5.8.1. Évaluation en court-circuit Imaginez un formulaire à remplir, avec de multiples questions, pour demander une place de parking dans votre immeuble. Pour ça, il faut déjà habiter l’immeuble en question et avoir une voiture. Si vous habitez ailleurs, pas la peine de réfléchir à la possession ou non d’une voiture, vous êtes inéligible pour cette place de parking. Eh bien le compilateur mène le même raisonnement quand il évalue une expression constituée de «AND». S’il détecte qu’une condition est fausse, alors il ne sert à rien d’évaluer le reste de l’expression puisque le résultat est forcément faux. Si vous ne voyez pas pourquoi, retournez un peu plus haut jeter un œil à la table de vérité de «AND». 1 #include <iostream> 2 3 int main() 4 { 5 bool const ai_je_une_voiture { false }; 6 bool const habite_immeuble { true }; 7 8 // Comme ai_je_une_voiture vaut false, le compilateur ne va pas tester l'expression habite_immeuble. 9 if (ai_je_une_voiture && habite_immeuble) 10 { 11 std::cout << "Voici votre place de parking." << std::endl; 12 } 13 else 14 { 15 std::cout << "Désolé, vous n'êtes pas éligible." << std::endl; 16 } 17 75 II. Le début du voyage 10 if (age < 5u) 11 { 12 std::cout << "Tu n'es pas un peu jeune pour naviguer sur internet ?" << std::endl; 13 } 14 else if (age < 18u) 15 { 16 std::cout << "Tu es mineur !" << std::endl; 17 } 18 else if (age < 30u) 19 { 20 std::cout << "Vous êtes majeur !" << std::endl; 21 } 22 else if (age < 50u) 23 { 24 std::cout << "Vous n'êtes plus très jeunes, mais vous n'êtes pas encore vieux." << std::endl; 25 } 26 else if (age < 70u) 27 { 28 std::cout << "Vous commencez à prendre de l'âge." << std::endl; 29 } 30 else if (age < 120u) 31 { 32 std::cout << "Vous avez du en voir, des choses, durant votre vie !" << std::endl; 33 } 34 else 35 { 36 std::cout << "Quelle longévité !" << std::endl; 37 } 38 39 return 0; 40 } Retourner au texte. Contenumasqué n°7 : 78 II. Le début du voyage Correction T.P Partie I 1 #include <iostream> 2 #include <string> 3 4 int main() 5 { 6 std::cout << "Entre ton age : "; 7 unsigned int age { 0 }; 8 9 if (std::cin >> age) 10 { 11 // Tout va bien. 12 std::cout << "Tu as " << age << " ans.\n"; 13 } 14 else 15 { 16 // Si std::cin a rencontré une erreur quelconque. 17 std::cout << "Tu n'as pas rentré un entier, il y a eu une erreur." << std::endl; 18 std::cin.clear(); // On remet std::cin dans un état fonctionnel. 19 std::cin.ignore(255, '\n'); // On vide les caractères mémorisés. 20 } 21 22 std::cout << "Maintenant, vérifions que tout va bien." << std::endl; 23 std::cout << "Entre ton nom : "; 24 std::string nom { "" }; 25 std::cin >> nom; 26 std::cout << "Tu t'appelles " << nom << ".\n"; 27 28 return 0; 29 } Si vous avez eu du mal ou n’avez pas trouvé, ce n’est pas grave, vous êtes en train d’apprendre. N’hésitez pas à relire la solution jusqu’à ce que tout vous paraisse limpide. Retourner au texte. Contenumasqué n°8 : Correction Voici la solution. L’avez-vous trouvée? Vous êtes sur la bonne voie! Vous avez-eu du mal? N’hésitez pas à relire les passages précédents à tête reposée et à faire vos propres exemples. 79 II. Le début du voyage 1 (a && b) && c 2 (a || b) || c 3 a || (b && c) 4 (a && b) || c 5 6 (!a) && b 7 a || (!b) 8 9 (a && b) || (c && d) 10 (a || (b && c)) || d Retourner au texte. Contenumasqué n°9 : Correction pseudo-horloge 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Quelle heure est-il ?" << std::endl; 6 int heure { 0 }; 7 std::cin >> heure; 8 9 if (heure > 0 && heure < 7) 10 { 11 std::cout << "Zzz..." << std::endl; 12 } 13 else if (heure >= 7 && heure < 12) 14 { 15 std::cout << "C'est le matin !" << std::endl; 16 } 17 else if (heure == 12) 18 { 19 std::cout << "Il est midi !" << std::endl; 20 } 21 else if (heure > 12 && heure < 18) 22 { 23 std::cout << "C'est l'après-midi !" << std::endl; 24 } 25 else if (heure >= 18 && heure < 24) 26 { 27 std::cout << "C'est le soir !" << std::endl; 28 } 29 else if (heure == 24 || heure == 0) 80 II. Le début du voyage 18 19 return 0; 20 } Sinon vous pouvez utiliser xor, si vous incluez bien <ciso646> avec Visual Studio. Retourner au texte. 83 II.6. Des boucles qui se répètent, répètent, répètent… Nous sommes maintenant capables d’exécuter des codes différents en fonction de conditions. Mais notre programme reste très linéaire: nous exécutons les instructions l’une après l’autre, du début à la fin, de haut en bas. Dans la droite ligne du chapitre précédent, nous allons donc voir un mécanisme offert par C++ pour répéter autant de fois que l’on souhaite une série d’instructions. Ce chapitre introduira les boucles et permettra d’améliorer encore notre gestion des erreurs, vue dans le chapitre précédent. II.6.1. while — Tant que… Commençons ce chapitre avec une boucle while. En toute originalité, ce mot-clef est aussi un mot anglais qui signifie «tant que». Elle exécute une série d’instructions tant que la condition est vraie. Par contre, dès que la condition est évaluée à false, la boucle s’arrête. On dit aussi qu’on boucle ou qu’on itère. 84 II. Le début du voyage Figure II.6.1. – Image originale tirée du tutoriel sur le langage C . Prenons un exemple tout bête: notre programme va compter de 0 à 9. Voici le code correspon- dant. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Salut, je vais compter de 0 à 9." << std::endl; 6 int compteur { 0 }; 7 8 while (compteur < 10) 9 { 10 std::cout << compteur << std::endl; 11 ++compteur; 12 } 13 14 std::cout << "Je m'arrête, après je sais pas faire." << std::endl; 15 return 0; 16 } Le code est exécuté ainsi: on évalue la condition. Tant que compteur est strictement inférieur à 10, alors on affiche le nombre puis on l’incrémente. Quand finalement compteur vaut 10, la condition devient fausse, on passe à la suite du code. × Boucle infinie Il est important de vérifier qu’à un moment ou un autre la condition devienne fausse et qu’on sort bien de la boucle. Si l’on n’y prend pas garde, on tombe dans le piège de la boucle infinie! 85 II. Le début du voyage II.6.3. do while — Répéter… tant que La deuxième boucle offerte par C++ est très proche de la précédente. En fait, c’est la même, à deux différences près. Une boucle do while s’exécute toujours une fois au minimum, même si la condition est fausse. La condition est en effet vérifiée après l’exécution du code. Figure II.6.2. – Do while La deuxième, c’est qu’il faut un point-virgule après le while. Voyez par vous-mêmes le code suivant. 1 #include <iostream> 2 3 int main() 4 { 5 do 6 { 7 std::cout << "On passe quand même ici." << std::endl; 8 } while (false); 9 10 return 0; 11 } 88 II. Le début du voyage Hormis ces deux subtiles différences, do while se comporte exactement comme while et permet elle aussi de boucler. Nous allons voir dans la section suivante comment les deux nous aiderons à résoudre le problème de sécurisation des entrées, soulevé au chapitre précédent. II.6.4. [T.P] Gérer les erreurs d’entrée — Partie II Dans la première partie, nous avions un mécanisme qui ne nous protégeait qu’une seule fois des erreurs. Maintenant, nous sommes en mesure de nous protéger tant que l’entrée n’est pas correcte. Améliorez donc le code que vous avez écrit pour qu’il soit capable de protéger le code suivant. 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Quel jour es-tu né ? "; 6 int jour { 0 }; 7 std::cin >> jour; 8 9 std::cout << "Quel mois es-tu né ? "; 10 int mois { 0 }; 11 std::cin >> mois; 12 13 std::cout << "Tu es né le " << jour << "/" << mois << "." << std::endl; 14 return 0; 15 } Correction T.P partie II Petit à petit, grâce à nos connaissances qui s’étoffent, nous améliorons la protection des entrées. Mais c’est dommage d’avoir le même code dupliqué à plusieurs endroits. C’est sale, ça nous fait perdre du temps si l’on doit modifier un morceau de code dans chaque endroit; et je ne parle pas des erreurs liés à des morceaux de codes différents des autres. Nous apprendrons dans le chapitre suivant comment s’en sortir. II.6.5. for — Une boucle condensée Les boucles while et do while sont très utiles et ajoutent une corde à notre arc. Mais ne trouvez-vous pas ça dommage d’avoir nos variables liées à l’itération (comme compteur) séparées de la boucle elle-même? Actuellement, notre code est simple, mais imaginons un instant un code bien plus complexe. Il serait mieux de séparer les opérations liées à la boucle de nos autres variables 89 II. Le début du voyage importantes. Cela rendra le code plus clair et plus compréhensible. C’est exactement ce que permet for («pour» en anglais). 1 for (/* initialisation */; /* condition */; /* itération */) 2 { 3 // Code de la boucle. 4 } 5 6 // Est équivalent à la boucle ci-dessous. 7 8 // Notez la création d'une portée artificielle. 9 { 10 // Initialisation. 11 while (/* condition */) 12 { 13 // Code de la boucle. 14 /* itération */ 15 } 16 } Hormis cette syntaxe différente, for s’utilise comme ses consœurs. Nous sommes libres de l’initialisation, de la condition et de l’itération. 1 #include <iostream> 2 3 int main() 4 { 5 // Compte de 10 à 1. On décrémente ici. 6 for (int compteur {10}; compteur > 0; --compteur) 7 { 8 std::cout << compteur << std::endl; 9 } 10 11 std::cout << "Fin du programme." << std::endl; 12 return 0; 13 } Nous pouvons même effectuer plusieurs opérations en même temps, tant que les variables déclarées sont du même type. Cette possibilité est cependant à prendre avec des gants parce qu’elle peut rendre le code très peu lisible. 1 #include <iostream> 2 3 int main() 4 { 90 II. Le début du voyage 5 for (int i { 0 }; i < 10; ++i) 6 { 7 // Si i vaut 3, j'arrête la boucle. 8 if (i == 3) 9 { 10 break; 11 } 12 13 std::cout << i << std::endl; 14 } 15 16 return 0; 17 } Dans le cas de boucles imbriquées, break ne stoppe l’exécution que de la boucle dans laquelle il se trouve, mais pas les boucles englobantes. 1 for (int i { 0 }; i < 5; ++i) 2 { 3 for (int j { 0 }; j < 3; ++j) 4 { 5 if (j == 1) 6 { 7 // Quand j vaut 1, on retourne dans le for(i). 8 break; 9 } 10 11 std::cout << "Voici la valeur de j : " << j << std::endl; 12 } 13 14 std::cout << "Voici la valeur de i : " << i << std::endl; 15 } Pour illustrer son fonctionnement avec un cas plus utile, prenons un exemple mathématique. Connaissez-vous le concept du test de primalité ? Il s’agit d’un test pour déterminer si un entier est premier, c’est-à-dire divisible uniquement par 1 et par lui-même; 13 est un nombre premier mais pas 10, car divisible par 1, 2, 5, et 10. Essayez donc de faire cet exercice. Indice Correction 93 II. Le début du voyage II.6.8.2. continue — Saute ton tour ! L’autre mot-clef, continue, permet de sauter l’itération courante. Toutes les instructions qui se trouvent après ce mot-clef sont donc ignorées et la boucle continue au tour suivant. Imaginons que nous voulions un programme permettant d’afficher les nombres impairs compris entre 0 et un nombre choisi par l’utilisateur. Essayez donc de le faire, avec les connaissances que vous avez. Indice Correction × Potentielle boucle infinie Attention lorsque vous utilisez continue au sein d’une boucle while ou do while, parce que TOUT le code situé après est sauté, même les instructions d’incrémentation. Le code suivant est donc un exemple de boucle infinie. 1 int i { 0 }; 2 while (i < 10) 3 { 4 if (i == 5) 5 { 6 // Ohoh... 7 continue; 8 } 9 10 ++i; 11 } II.6.8.3. En résumé — C++ nous offre trois façons de boucler: while, do while et for. — while s’utilise plutôt pour boucler tant qu’une condition n’est pas remplie alors que for est utilisé pour itérer sur un nombre connu d’éléments. — Il faut faire attention à ne pas tomber dans une boucle infinie. — Nous disposons de deux mots-clefs, break et continue, pour affiner notre contrôle sur l’exécution de la boucle. 94 II. Le début du voyage Contenumasqué Contenumasqué n°13 : Correction laverie 1 #include <iostream> 2 3 int main() 4 { 5 std::cout << "Bienvenue à la laverie de Clem. Combien de kilos de linge as-tu ? "; 6 int kilos { 0 }; 7 std::cin >> kilos; 8 9 if (kilos <= 5) 10 { 11 std::cout << "Tu as peu de linge, mets-le dans une machine de 5kg." << std::endl; 12 } 13 else if (kilos <= 10) 14 { 15 std::cout << "Tu as beaucoup de linge, mets-le dans une machine de 10kg." << std::endl; 16 } 17 else 18 { 19 // On a plus que 10 kilos, il va falloir diviser le linge en plusieurs machines. 20 std::cout << "Dites donc, il faut laver son linge plus souvent !" << std::endl; 21 22 int nb_machines_10_kilos { 0 }; 23 24 while (kilos > 5) 25 { 26 // Pour chaque machine de 10kg utilisée, on enlève 10kg au total de linge restant. 27 kilos -= 10; 28 ++nb_machines_10_kilos; 29 } 30 31 std::cout << "Tu as besoin de " << nb_machines_10_kilos << " machine(s) de 10kg." << std::endl; 32 if (kilos >= 0) 95