Section courante

A propos

Section administrative du site

 Langage  Elément  Tutoriel  Programmation  Bibliothèque  API  SDK  Cadre d'application  Boite à outils  Projet  IDE  Annexe  Aide 
ABAP/4
Ada
Assembleur
Assembly & bytecode
ASP (Active Server Pages)
Basic
C
C++
C# (C Sharp)
Cobol
ColdFusion
Fortran
HTML
Java
JavaScript
LISP
Logo
LotusScript
Oberon
Pascal
Perl
PHP
PL/1
Prolog
Python
Rebol
REXX
Ruby
SAS
NoSQL
SQL
Swift
X++ (Axapta)
GNAT
SMALLAda
VHDL
Assembleur 370
Assembleur 1802
Assembleur 4004
Assembleur 6502
Assembleur 6800
Assembleur 68000
Assembleur 8080 et 8085
Assembleur 8089
Assembleur 80x86
Assembleur AGC4
Assembleur ARM
Assembleur DPS 8000
Assembleur i860
Assembleur Itanium
Assembleur MIPS
Assembleur PDP-11
Assembleur PowerPC
Assembleur RISC-V
Assembleur SPARC
Assembleur SuperH
Assembleur UNIVAC I
Assembleur VAX
Assembleur Z80
Assembleur Z8000
Assembleur z/Architecture
ASSEMBLER/MONITOR 64
Micol Assembler
GFA Assembler
A86
MASM (Macro Assembler)
TASM (Turbo Assembler)
CIL
Jasmin
LLVM
MSIL
Parrot
P-Code (PCode)
SWEET16
G-Pascal
ASP 1.0
ASP 2.0
ASP 3.0
ASP.NET
ASP.NET Core
ABasiC (Amiga)
Adam SmartBASIC
Altair BASIC
AmigaBASIC (Amiga)
AMOS Basic (Amiga)
Atari Basic (Atari 400, 600 XL, 800, 800XL)
Basic Apple II (Integer BASIC/APPLESOFT)
Basic Commodore 64 (CBM-BASIC)
Basic Commodore 128 (BASIC 7.0)
Basic Commodore VIC-20 (CBM-BASIC 2.0)
Basic Coco 1 (Color Basic)
Basic Coco 2 (Extended Color Basic)
Basic Coco 3 (Extended Color Basic 2.0)
BASICA (PC DOS)
Basic Pro
BBC BASIC
Blitz BASIC (Amiga)
DarkBASIC
Dartmouth BASIC
GFA-Basic (Atari ST/Amiga)
GWBASIC (MS-DOS)
Liberty BASIC
Locomotive BASIC (Amstrad CPC)
MSX-Basic
Omikron Basic (Atari ST)
Oric Extended Basic
Power Basic
Quick Basic/QBasic (MS-DOS)
Sinclair BASIC (ZX80, ZX81, ZX Spectrum)
ST BASIC (Atari ST)
Turbo Basic
Vintage BASIC
VBScript
Visual Basic (VB)
Visual Basic .NET (VB .NET)
Visual Basic pour DOS
Yabasic
BeckerBASIC
SIMONS' BASIC
Basic09 d'OS-9
Disk Extended Color Basic
Basic09 d'OS-9
Disk Extended Color Basic
Access
Excel
Visual Basic pour Windows
Visual Basic .NET pour Windows
C Shell Unix (csh)
C pour Amiga
C pour Atari ST
C pour DOS
C pour Falcon030
C pour GEMDOS (Atari ST)
C pour Linux
C pour PowerTV OS
C pour OS/2
C pour Unix
C pour Windows
Aztec C
CoCo-C
GNU C
HiSoft C
IBM C/2
Introl-C
Lattice C
Microsoft C
MinGW C
MSX-C
Open Watcom C
OS-9 C Compiler
Pure C
Quick C
Turbo C
HiSoft C for Atari ST
HiSoft C for CP/M (Amstrad CPC)
C++ pour OS/2
C++ pour Windows
Borland C++
C++Builder
IBM VisualAge C++
Intel C++
MinGW C++
Open Watcom C++
Symantec C++
Turbo C++
Visual C++
Visual C++ .NET
Watcom C++
Zortech C++
C# (C Sharp) pour Windows
Apple III Cobol
Microsoft Cobol
BlueDragon
Lucee
OpenBD
Railo
Smith Project
Microsoft Fortran
WATFOR-77
CSS
FBML
Open Graph
SVG
XML
XSL/XSLT
LESS
SASS
GCJ (GNU)
JSP
Jython
Visual J++
Node.js
TypeScript
AutoLISP
ACSLogo
LotusScript pour Windows
Amiga Oberon
Oberon .NET
Apple Pascal
Delphi/Kylix/Lazarus
Free Pascal
GNU Pascal
HighSpeed Pascal
IBM Personal Computer Pascal
Lisa Pascal
Maxon Pascal
MPW Pascal
OS-9 Pascal
OSS Personal Pascal
Pascal-86
Pascal du Cray Research
Pascal/VS
Pascal-XT
PURE Pascal
QuickPascal
RemObjets Chrome
Sun Pascal
THINK Pascal
Tiny Pascal (TRS-80)
Turbo Pascal
UCSD Pascal
VAX Pascal
Virtual Pascal
Turbo Pascal for CP/M-80
Turbo Pascal for DOS
Turbo Pascal for Macintosh
Turbo Pascal for Windows
CodeIgniter (Cadre d'application)
Drupal (Projet)
Joomla! (Projet)
Phalanger (PHP .NET)
phpBB (Projet)
Smarty (balise)
Twig (balise)
Symfony (Cadre d'application)
WordPress (Projet)
Zend (Cadre d'application)
PL360
PL/M-80
PL/M-86
Turbo Prolog
CPython
IronPython
Jython
PyPy
AREXX
Regina REXX
JMP
Btrieve
Cassandra
Clipper
CouchDB
dBASE
Hbase
Hypertable
MongoDB
Redis
Access
BigQuery
DB2
H2
Interbase
MySQL
Oracle
PostgreSQL
SAP HANA
SQL Server
Sybase
U-SQL
Introduction
Les remarques
Les opérateurs
Les instructions conditionnelles
Les instuctions de boucle
Type de données
Fichier d'entête de bibliothèque
Définition de procédure et fonction
Mot réservés
Référence de procédures et fonctions
Références des classes
STL : Standard Template Library
cassert (assert.h)
cctype (ctype.h)
cmath (math.h)
csetjmp (setjmp.h)
csignal (signal.h)
cstdarg (stdarg.h)
cstdio (stdio.h)
cstdlib (stdlib.h)
cstring (string.h)
ctime (time.h)
Prototype
Les premiers pas
Les opérations
Envoyer un courriel
Bonjour
Astronomie
Biochimie
Fichier
Finance
Géographie
Géométrie
Gouvernement
Histoire
Mathématique
Météorologie
Océanographie
Sport
Temps
Trigonométrie
Validation
Phase lunaire
Calcul du calcium corrigé
Calcul le taux d'alcoolémie
Lecture d'un fichier texte séquentiel
IPaymt/Interet
NPer
PPaymt/Principal
Distance en Km entre deux longitudes et latitudes
Aire d'un cercle
Aire d'une surface de prisme rectangulaire
Aire d'un triangle
Distance entre deux points
Taxe de vente canadienne
Chiffre romain
Exp
Factoriel
Fibonacci
Log
Nombre premier
Odd
Polygone
Random
Round (arrondir)
Sqrt
Triangle Pascal
Unité de mesure
Fréquence des vagues
Hockey
Année bissextile
Date de la Pâque
Heure courante
FirstDayOfMonth
ArcCos
ArcSin
Atn/ATan/ArcTan/ArcTangente
Cos
Sin
Courriel
ALGLIB
Boost
Eigen
Hunspell
LibSass
MITIE
MSXML
OpenCV
OpenGL
POCO C++ Libraries
RapidJSON
Rcpp
regex
SentencePiece
Skia
SystemC
TensorFlow
Unreal Engine (UE)
API de Windows
API d'OS/2
Power TV OS API
OCI API pour Oracle Database SQL
Ageia PhysX SDK
CUDA
Cocos2d
Hyperledger Iroha
Qt
ONNX
OpenMM
Unity
Chrome V8
KDE
CodeBlocks
Eclipse
NetBeans
SET's Editor
Visual Studio
Xcode
Bibliographie
Préface
Notes légales
Dictionnaire
Recherche

Les premiers pas

Cette page présente de manière informelle la notation du C++, le modèle de mémoire et de calcul du C++, ainsi que les mécanismes de base permettant d'organiser le code dans un programme. Elle aborde également les différentes particularités du langage facilitant l'écriture de programmes structurés, en mettant l'accent sur les éléments qui facilitent la gestion de la mémoire, ainsi que la manipulation des données et des variables. Il s'agit des fonctionnalités du langage prenant en charge les styles les plus souvent rencontrés en C, incluant les structures de contrôle classiques, ainsi que les mécanismes permettant de travailler avec des pointeurs et de gérer les allocations dynamiques de mémoire. Ces concepts sont parfois appelés programmation procédurale et sont essentiels pour comprendre les bases du C++ avant d'aborder des paradigmes plus avancés comme la programmation orientée objet. En somme, cette présentation vise à offrir une vue d'ensemble de ces mécanismes fondamentaux, tout en expliquant leur utilisation et leur impact sur la structure d'un programme C++.

Les bases

Le C++ est un langage de programmation compilé, ce qui signifie que son code source doit être transformé en un programme exécutable avant de pouvoir être exécuté. Cette transformation passe par plusieurs étapes essentielles, à commencer par la compilation proprement dite, où chaque fichier source est converti en un fichier objet indépendant. Ces fichiers objets contiennent le code machine partiel, devant ensuite être combiné avec d'autres fichiers objets et des bibliothèques par un éditeur de liens pour produire le programme final. L'ensemble de ce processus garantit que le programme est optimisé pour une architecture matérielle spécifique et peut tirer parti des optimisations offertes par le compilateur. Un programme C++ se compose généralement de plusieurs fichiers sources organisés selon une structure modulaire, facilitant la maintenance et la réutilisation du code. Ces fichiers sont souvent accompagnés de fichiers d'entête, déclarant les fonctions et classes utilisées dans différents modules du programme.

Une fois compilé et lié, un programme exécutable est conçu pour fonctionner sur une combinaison spécifique de matériel et de système d'exploitation. Il ne peut pas être exécuté directement sur une autre plateforme sans une recompilation appropriée, car les instructions générées sont spécifiques à l'architecture cible. Par exemple, un programme compilé pour Windows sur une machine x86 ne pourra pas fonctionner sur un Mac équipé d'un processeur ARM sans adaptation. Cette dépendance au matériel et au système d'exploitation est une contrainte importante du développement en C++, mais elle est aussi une source de performance, car elle permet d'optimiser le programme pour l'environnement dans lequel il sera utilisé. Certains compilateurs offrent des options pour générer du code multiplateforme, mais cela nécessite souvent des ajustements et des bibliothèques adaptées à chaque environnement cible.

Lorsqu'on parle de portabilité en C++, il est généralement question de la capacité du code source à être compilé et exécuté sur plusieurs systèmes avec un minimum de modifications. Un code bien écrit, utilisant des bibliothèques standard et évitant les dépendances spécifiques à un système d'exploitation particulier, a plus de chances d'être portable. Cependant, certains aspects, comme la gestion des fichiers, l'allocation mémoire ou l'interaction avec le matériel, peuvent nécessiter des ajustements pour s'adapter aux différentes plateformes. Pour améliorer la portabilité, les développeurs utilisent souvent des directives de préprocesseur (#ifdef, #ifndef) pour inclure des sections de code spécifiques à une plateforme. L'utilisation de bibliothèques multiplateformes comme Boost ou Qt peut également simplifier le processus en offrant des abstractions standardisées pour différentes fonctionnalités du système.

La norme ISO C++ définit deux types d'entités :

Les composantes de la bibliothèque standard sont du code C++ tout à fait ordinaire fourni par chaque implémentation C++. En d'autres termes, la bibliothèque standard C++ peut être implémentée en C++ lui-même (et ce, avec des utilisations très mineures de code machine pour des choses telles que le changement de contexte de processus léger). Cela implique que C++ est suffisamment expressif et efficace pour les tâches de programmation système les plus exigeantes.

Le C++ est un langage de programmation typé statiquement. En d'autres termes, le type de chaque entité (par exemple, objet, valeur, nom et expression) doit être connu du compilateur au moment de son utilisation. Le type d'un objet détermine l'ensemble des opérations lui étant applicables.

Un premier programme

Le programme C++ minimal est :

  1. int main() { }     // Le programme C++ minimal

Cela définit une fonction appelée main, ne prenant aucun paramètre et ne faisant rien.

Les accolades, { }, expriment le regroupement en C++. Ici, elles indiquent le début et la fin du corps de la fonction. La double barre oblique, //, commence un commentaire qui s'étend jusqu'à la fin de la ligne. Un commentaire est destiné au lecteur humain ; ainsi le compilateur ignore les commentaires.

Chaque programme C++ doit avoir exactement une fonction globale nommée main(). Le programme commence par exécuter cette fonction. La valeur int renvoyée par main(), le cas échéant, est la valeur de retour du programme au «système». Si aucune valeur n'est renvoyée, le système recevra une valeur indiquant la réussite de l'exécution. Une valeur différente de zéro de main() indique un échec. Tous les systèmes d'exploitation et environnements d'exécution n'utilisent pas cette valeur de retour : les environnements basés sur Linux/Unix le font souvent, mais les environnements basés sur Windows le font rarement.

En général, un programme produit une sortie. Voici un programme écrivant Bonjour le monde ! :

  1. #include <iostream>
  2.  
  3. int main() {
  4.      std::cout << "Bonjour le monde !\n";
  5. }    

La ligne #include <iostream> indique au compilateur d'inclure les déclarations des fonctions d'entrée/sortie de flux standard telles qu'elles se trouvent dans iostream. Sans ces déclarations, l'expression :

  1. std::cout << "Bonjour le monde !\n";

n'aurait aucun sens. L'opérateur << («put to») écrit son deuxième paramètre sur son premier. Dans ce cas, la chaîne de caractères littérale "Bonjour le monde !\n" est écrite sur le flux de sortie standard std::cout. Une chaîne de caractères littérale est une séquence de caractères entourée de guillemets. Dans une chaîne littérale, le caractère barre oblique inverse \ suivi d'un autre caractère désigne un seul «caractère spécial». Dans ce cas, \n est le caractère de nouvelle ligne, de sorte que les caractères écrits sont Bonjour le monde ! suivi d'un retour à la ligne.

Le std:: spécifie que le nom cout doit être trouvé dans l'espace de noms de la bibliothèque standard. Nous omettons généralement le std:: lorsque nous discutons des fonctionnalités standard.

Essentiellement, tout le code exécutable est placé dans des fonctions et appelé directement ou indirectement depuis main(). Par exemple :

  1. #include <iostream>
  2.  
  3. using namespace std;      // rendre les noms de std visibles sans std::
  4.  
  5. double carre(double x) { // le carré d'un nombre réel à virgule flottante de double précision
  6.  return x*x;
  7. }

Avec le code suivant :

  1. void affiche_le_carre(double x) {
  2.  cout << "le carré de " << x << " est " << carre(x) << "\n";
  3. }
  4.  
  5. int main() {
  6.  affiche_le_carre(1.234);      // afficher : le carré de 1,234 est 1,52276
  7. }

Types, variables et arithmétique

En C++, les types de données définissent la nature des valeurs que peuvent contenir les variables. On distingue les types fondamentaux comme les entiers (int), les nombres à virgule flottante (float, double), les caractères (char) et les booléens (bool). À ces types s'ajoutent des variantes qualifiées par des mots-clefs comme unsigned (sans signe) ou long (taille étendue). Le langage de programmation permet aussi de créer des types personnalisés avec typedef ou using, et d'utiliser des structures (struct), des classes (class) ou des énumérations (enum) pour organiser les données de manière plus complexe.

Les variables en C++ doivent être déclarées avant utilisation et leur type ne peut généralement pas changer après l'initialisation. Une variable peut être définie avec une valeur initiale explicite, mais peut aussi être laissée non initialisée, ce qui peut entraîner un comportement indéfini. Le mot-clef auto permet au compilateur de déduire le type d'une variable en fonction de son initialisation, réduisant ainsi la nécessité d'écrire des types explicites. De plus, les variables peuvent être modifiées avec des qualificateurs comme const (constante) ou volatile (susceptible d'être modifiée en dehors du programme).

L'arithmétique en C++ repose sur les opérateurs de base (+, -, *, /, %) qui permettent d'effectuer des calculs sur les variables numériques. Les opérations entre types différents peuvent impliquer des conversions implicites, appelées promotions ou troncatures, selon la compatibilité des types. Des opérateurs d'incrémentation (++, --) et de composition (+=, -=, *=,...) facilitent les modifications de valeurs. Enfin, la bibliothèque <cmath> fournit des fonctions avancées comme sqrt() pour les racines carrées, pow() pour les puissances ou abs() pour la valeur absolue, enrichissant ainsi les possibilités de calcul en C++.

Chaque nom et chaque expression ont un type déterminant les opérations pouvant être effectuées sur eux. Par exemple, la déclaration :

  1. int pouce;

spécifie que pouce est de type de données int; c'est-à-dire que pouce est une variable entière.

Une déclaration est une instruction introduisant un nom dans le programme. Elle spécifie un type pour l'entité nommée :

Le C++ propose une variété de types fondamentaux. Par exemple :

Type de données Description
bool Booléen, les valeurs possibles sont true et false
char Caractère, par exemple, « a », « z » et « 9 »
int Entier, par exemple, -213, 42 et 1066
double Nombre à virgule flottante double précision, par exemple 3,14 et 299793,0.

Une variable char a la taille naturelle pour contenir un caractère sur une machine donnée (généralement un octet de 8 bits), et les tailles des autres types sont indiquées en multiples de la taille d'un char. La taille d'un type est définie par l'implémentation (c'est-à-dire qu'elle peut varier selon les machines) et peut être obtenue par l'opérateur sizeof ; par exemple, sizeof(char) est égal à 1 et sizeof(int) est souvent égal à 4.

Les opérateurs arithmétiques peuvent être utilisés pour des combinaisons appropriées de ces types :

Opérateur Description
x+y Plus
+x Unaire plus
x-y Moins
-x Moins unaire
x*y Multiplier
x/y Diviser
x%y Reste (module) pour les entiers

Les opérateurs de comparaison peuvent également :

Opérateur Description
x==y Égal
x!=y Pas égal
x<y Moins que
x>y Plus grand que
x<=y Inférieur ou égal
x>=y Supérieur ou égal

Dans les affectations et dans les opérations arithmétiques, C++ effectue toutes les conversions significatives entre les types de base afin qu'ils puissent être mélangés librement :

  1. void some_function() { // fonction ne renvoyant pas de valeur
  2.  double d = 2.2;       // initialiser un nombre à virgule flottante
  3.  int i = 7;            // initialiser l'entier
  4.  d = d+i;              // attribuer la somme à d
  5.  i = d*i;              // affecter le produit à i (tronquer le double d*i en un int)
  6. }

Notez que = est l'opérateur d'affectation et que == teste l'égalité.

C++ propose une variété de notations pour exprimer l'initialisation, telles que = utilisé ci-dessus, et une forme universelle basée sur des listes d'initialisation délimitées par des accolades :

  1. double d1 = 12.34;       // initialiser d1 avec 12.34
  2. double d2 {12.34};       // initialiser d2 avec 12.34
  3.  
  4. complex<double> z = 1;           // un nombre complexe avec des scalaires à virgule flottante double précision
  5. complex<double> z2 {d1,d2};
  6. complex<double> z3 = {1,2};      // le = est facultatif avec { ... }
  7.  
  8. vector<int> v {1,2,3,4,5,6,7};     // un vecteur d'entiers

La forme = est traditionnelle et remonte au C, mais en cas de doute, utilisez la forme générale de liste {}. Au moins, elle vous évite les conversions perdant des informations (conversions restreintes) :

  1. int x1 = 7.3;       // x1 devient 7 (surprise ?)
  2. int x2 {7.3};       // erreur : conversion de nombre à virgule flottante en nombre entier
  3. int x3 = {7.3};     // erreur : conversion de nombre à virgule flottante en nombre entier (le = est redondant)

Une constante ne peut pas rester non initialisée et une variable ne doit rester non initialisée que dans des circonstances extrêmement rares. N'introduisez pas de nom tant que vous n'avez pas de valeur appropriée pour celui-ci. Les types définis par l'utilisateur (tels que string, vecteur, Matrice, Controleur_Moteur et Guerrier_Orc) peuvent être définis pour être implicitement initialisés.

Lors de la définition d'une variable, vous n'avez pas réellement besoin d'indiquer explicitement son type lorsqu'il peut être déduit de l'initialiseur :

  1. auto b = true;     // un bool
  2. auto ch = 'x';     // un char
  3. auto i = 1234;     // un int
  4. auto d = 1.234;    // un double
  5. auto y = sqrt(x);  // y a le type de ce que sqrt(x) renvoie

Avec auto, nous utilisons la syntaxe = car il n'y a pas de conversion de type impliquée qui pourrait causer des problèmes.

Nous utilisons auto lorsque nous n'avons pas de raison spécifique de mentionner explicitement le type. Les «raisons spécifiques» incluent :

En utilisant auto, nous évitons la redondance et l'écriture de noms de types longs. Ceci est particulièrement important dans la programmation générique où le type exact d'un objet peut être difficile à connaître pour le programmeur et les noms de types peuvent être assez longs.

En plus des opérateurs arithmétiques et logiques classiques, C++ propose des opérations plus spécifiques pour modifier une variable :

Opérateur Description
x+=y x = x+y
++x incrémentation : x = x+1
x-=y x = x-y
--x Décrementation : x = x-1
x*=y Mise à l'échelle : x = x*y
x/=y Mise à l'échelle : x = x/y
x%=y x = x%y

Ces opérateurs sont concis, pratiques et très fréquemment utilisés.

Les constantes

Le C++ prend en charge deux notions d'immuabilité :

Notion Description
const Ce qui signifie approximativement «Nous promettons de ne pas modifier cette valeur». Cela sert principalement à spécifier des interfaces, afin que les données puissent être transmises aux fonctions sans crainte d'être modifiées. Le compilateur applique la promesse faite par const.
constexpr Ce qui signifie approximativement «à évaluer au moment de la compilation». Cela sert principalement à spécifier des constantes, à permettre le placement de données en mémoire en lecture seulement (où il est peu probable qu'elles soient corrompues) et à des fins de performances.

Voici quelques exemples :

  1. const int dmv = 37;                         // dmv est une constante nommée
  2. int var = 37;                               // var n'est pas une constante
  3. constexpr double max1 = 1.5*square(dmv);    // Correcte si square(37) est une expression constante
  4. constexpr double max2 = 1.5*square(var);    // Erreur : var n'est pas une expression constante
  5. const double max3 = 1.5*square(var);        // Correcte, peut être évalué au moment de l'exécution
  6. double sum(const vector<double>&);          // La somme ne modifiera pas son paramètre
  7. vector<double> v {9.8, 7.6, 5.4};           // v n'est pas une constante
  8. const double s1 = sum(v);                   // Correcte : évalué au moment de l'exécution
  9. constexpr double s2 = sum(v);               // Erreur : sum(v) n'est pas une expression constante

Pour qu'une fonction soit utilisable dans une expression constante, c'est-à-dire dans une expression étant évaluée par le compilateur, elle doit être définie constexpr. Par exemple :

  1. constexpr double carre(double x) { return x*x; }

Pour être constexpr, une fonction doit être assez simple : juste une instruction de retour calculant une valeur. Une fonction constexpr peut être utilisée pour des arguments non constants, mais lorsque cela est fait, le résultat n'est pas une expression constante. Nous autorisons une fonction constexpr à être appelée avec des arguments non constants dans des contextes ne nécessitant pas d'expressions constantes, de sorte que nous n'avons pas à définir essentiellement la même fonction deux fois : une fois pour les expressions constantes et une fois pour les variables.

Dans quelques endroits, les expressions constantes sont requises par les règles du langage (par exemple, les limites de tableau, les étiquettes de cas, certains arguments de modèle et les constantes déclarées à l'aide de constexpr). Dans d'autres cas, l'évaluation au moment de la compilation est importante pour les performances. Indépendamment des problèmes de performances, la notion d'immuabilité (d'un objet avec un état immuable) est une préoccupation de conception importante.

Les tests et les boucles

Le C++ fournit un ensemble d'instructions conventionnelles pour exprimer la sélection et la boucle. Par exemple, voici une fonction simple invitant l'utilisateur et renvoie un booléen indiquant la réponse :

  1. bool accepte() {
  2.  cout << "Voulez-vous continuer (o ou n)?\n";    // Écrire une question
  3.  char reponse = 0;
  4.  cin >> reponse;                                 // Lire la réponse
  5.  if (reponse == 'o') return true;
  6.  return false;
  7. }

Pour correspondre à l'opérateur de sortie << («put to»), l'opérateur >> («get from») est utilisé pour l'entrée; cin est le flux d'entrée standard. L'opérande de droite de >>> est la cible de l'opération d'entrée et le type de cet opérande détermine quelle entrée >> accepte. Le caractère \n à la fin de la chaîne de sortie représente une nouvelle ligne.

L'exemple pourrait être amélioré en prenant en compte une réponse n (pour «non») :

  1. bool accepte2() {
  2.  cout << "Voulez-vous continuer (o ou n)?\n"; // Écrire une question
  3.  char reponse = 0;
  4.  cin >> reponse;                               // Lire la réponse
  5.  switch (reponse) {
  6.   case 'o':
  7.    return true;
  8.   case 'n':
  9.    return false;
  10.   default:
  11.    cout << "Nous prenons ça pour un non.\n";
  12.    return false;
  13.  }
  14. }

Une instruction switch teste une valeur par rapport à un ensemble de constantes. Les constantes de case doivent être distinctes, et si la valeur testée ne correspond à aucune d'entre elles, la valeur par défaut est choisie. Si aucune valeur par défaut n'est fournie, aucune action n'est entreprise si la valeur ne correspond à aucune constante de case.

Peu de programmes sont écrits sans boucles. Par exemple, nous aimerions donner à l'utilisateur quelques essais pour produire une entrée acceptable :

  1. bool accepte3() {
  2.  int essaies = 1;
  3.  while (essaies<4) {
  4.   cout << "Voulez-vous continuer (o ou n)?\n\n";              // Écrire une question
  5.   char reponse = 0;
  6.   cin >> reponse;                                             // Lire la réponse
  7.   switch (reponse) {
  8.    case 'o':
  9.     return true;
  10.    case 'n':
  11.     return false;
  12.    default:
  13.     cout << "Désolé, je ne comprends pas cette réponse.\n";
  14.     ++essaies;                                                // incrémentation
  15.   }
  16.  }
  17.  cout << "Nous prenons ça pour un non.\n";
  18.  return false;
  19. }    

L'instruction while s'exécute jusqu'à ce que sa condition devienne fausse.

Pointeurs, tableaux et boucles

Un tableau d'éléments de type char peut être déclaré comme ceci :

  1. char v[7];   // tableau de 7 caractères

De même, un pointeur peut être déclaré comme ceci :

  1. char* p;     // pointeur vers un caractère

Dans les déclarations, [] signifie «tableau de» et * signifie «pointeur vers». Tous les tableaux ont 0 comme limite inférieure, donc v a sept éléments, v[0] à v[6]. La taille d'un tableau doit être une expression constante. Une variable pointeur peut contenir l'adresse d'un objet du type approprié :

  1. char* p = &v[5];          // p pointe vers le quatrième élément de v
  2. char x = *p;              // *p est l'objet vers lequel p pointe

Dans une expression, le préfixe unaire * signifie «contenu de» et le préfixe unaire & signifie «adresse de».

Considérez la copie de douze éléments d'un tableau à un autre :

  1. void fonction_de_copie() {
  2.  int vecteur1[12] = {0,1,2,3,4,5,6,7,8,9,10,11};
  3.  int vecteur2[12];                               // devenir une copie de vecteur1
  4.  for (auto i=0; i!=12; ++i)                      // copier des éléments
  5.   vecteur2[i]=vecteur1[i];
  6.  // ...
  7. }

Cette instruction for peut être lue comme «définir i à zéro; tant que i n'est pas 12, copier le ième élément et incrémenter i». Lorsqu'il est appliqué à une variable entière, l'opérateur d'incrémentation, ++, ajoute simplement 1. C++ propose également une instruction for plus simple, appelée instruction range-for, pour les boucles parcourant une séquence de la manière la plus simple :

  1. void affiche() {
  2.  int vecteur[] = {0,1,2,3,4,5,6,7,8,9,10,11};
  3.  for (auto x : vecteur)     // pour chaque x dans vecteur
  4.   cout << x << '\n';
  5.  for (auto x : {10,16,24,37,43,54,65,74})
  6.   cout << x << '\n';
  7.  // ...
  8. }

La première instruction range-for peut être lue comme « pour chaque élément de vecteur, du premier au dernier, placez une copie dans x et affichez-la». Notez que nous n'avons pas besoin de spécifier une limite de tableau lorsque nous l'initialisons avec une liste. L'instruction range-for peut être utilisée pour n'importe quelle séquence d'éléments.

Si nous ne voulions pas copier les valeurs de vecteur dans la variable x, mais plutôt que x fasse simplement référence à un élément, nous pourrions écrire :

  1. void increment() {
  2.  int vecteur[] = {0,1,2,3,4,5,6,7,8,9,10,11};
  3.  for (auto& x : vecteur)
  4.   ++x;
  5.  // ...
  6. }

Dans une déclaration, le suffixe unaire & signifie «référence à». Une référence est similaire à un pointeur, sauf que vous n'avez pas besoin d'utiliser un préfixe * pour accéder à la valeur à laquelle la référence fait référence. De plus, une référence ne peut pas être utilisée pour faire référence à un objet différent après son initialisation. Lorsqu'ils sont utilisés dans les déclarations, les opérateurs (tels que &, * et []) sont appelés opérateurs de déclaration :

  1. T arr[n]; // T[n] : tableau de n T
  2. T* ptr;   // T*   : pointeur vers T 
  3. T& ref;   // T&   : référence à T 
  4. T f(A);   // T(A) : fonction prenant un argument de type A renvoyant un résultat de type T

Nous essayons de garantir qu'un pointeur pointe toujours vers un objet, de sorte que le déréférencement soit valide. Lorsque nous n'avons pas d'objet vers lequel pointer ou si nous devons représenter la notion d'«aucun objet disponible» (par exemple, pour une fin de liste), nous donnons au pointeur la valeur nullptrle pointeur nul»). Il n'y a qu'un seul nullptr partagé par tous les types de pointeurs :

  1. double* pd = nullptr;
  2. Link<Record>* lst = nullptr; // pointeur vers un lien vers un enregistrement
  3. int x = nullptr;             // erreur : nullptr est un pointeur et non un entier

Il est souvent judicieux de vérifier qu'un paramètre pointeur étant censé pointer vers quelque chose, pointe réellement vers quelque chose :

  1. int compteur_x(char* ptr, char x) {
  2.  // compter le nombre d'occurrences de x dans ptr[]
  3.  // ptr est supposé pointer vers un tableau de caractères terminé par zéro (ou vers rien)
  4.  if (ptr==nullptr) return 0;
  5.  int count = 0;
  6.  for (; *ptr!=0; ++ptr) if (*ptr==x) ++count;
  7.  return count;
  8. }

Notez comment nous pouvons déplacer un pointeur pour pointer vers l'élément suivant d'un tableau en utilisant ++ et que nous pouvons laisser de côté l'initialiseur dans une instruction for si nous n'en avons pas besoin.

La définition de compteur_x() suppose que le char* est une chaîne de caractères de style C, c'est-à-dire que le pointeur pointe vers un tableau de char terminé par zéro.

Dans le code plus ancien, 0 ou NULL est généralement utilisé à la place de nullptr. Cependant, l'utilisation de nullptr élimine la confusion potentielle entre les entiers (tels que 0 ou NULL) et les pointeurs (tels que nullptr).

Types définis par l'utilisateur

Nous appelons types intégrés les types pouvant être construits à partir des types fondamentaux, du modificateur const et des opérateurs déclarateurs. L'ensemble des types et opérations intégrés de C++ est riche, mais volontairement de bas niveau. Ils reflètent directement et efficacement les capacités du matériel informatique conventionnel. Cependant, ils ne fournissent pas au programmeur des fonctionnalités de haut niveau pour écrire facilement des applications avancées. Au lieu de cela, C++ augmente les types et opérations intégrés avec un ensemble sophistiqué de mécanismes d'abstraction à partir desquels les programmeurs peuvent créer de telles fonctionnalités de haut niveau. Les mécanismes d'abstraction de C++ sont principalement conçus pour permettre aux programmeurs de concevoir et d'implémenter leurs propres types, avec des représentations et des opérations adaptées, et pour que les programmeurs puissent utiliser ces types de manière simple et élégante. Les types construits à partir des types intégrés à l'aide des mécanismes d'abstraction de C++ sont appelés types définis par l'utilisateur. Ils sont appelés classes et énumérations.

Les structures

La première étape de la création d'un nouveau type consiste souvent à organiser les éléments dont il a besoin dans une structure de données, une struct :

  1. struct Vecteur {
  2.  int taille;       // nombre d'éléments
  3.  double* element;  // pointeur vers les éléments
  4. };

Cette première version de Vecteur se compose d'un int et d'un double*.

Une variable de type Vecteur peut être définie ainsi :

  1. Vector vec;

Cependant, cela n'est pas très utile en soi, car le pointeur element de vec ne pointe vers rien. Pour que cela soit utile, nous devons donner à vec des éléments vers lesquels pointer. Par exemple, nous pouvons construire un Vecteur comme ceci :

  1. void vecteur_init(Vecteur& vec, int t) {
  2.  vec.element = new double[t];              // allouer un tableau de s doubles
  3.  vec.taille = t;
  4. }


PARTAGER CETTE PAGE SUR
Dernière mise à jour : Vendredi, le 24 janvier 2025