Utilisateur:Merrheim/TEST10
Le C++ est un langage de programmation. Ce langage permet la programmation sous de multiples paradigmes comme, par exemple, la programmation procédurale, la programmation orientée objet et la programmation générique. Au cours des années 1990, le C++ est devenu l'un des langages de programmation les plus populaires dans l'industrie informatique. Personne ne possède le langage C++. Il est libre de droit. Le document de standardisation n'est quant à lui pas disponible gratuitement.
Historique
modifierDu C au C++
modifierBjarne Stroustrup a développé le C++ au cours des années 1980, alors qu'il travaillait dans le laboratoire de recherche Bell d'AT&T. Il s'agissait en l'occurrence d'améliorer le langage C et il l'avait d'ailleurs nommé C with classes (« C avec des classes »). Les premières améliorations se concrétisèrent donc par l'ajout du support des classes, suivies par de nombreuses autres comme les fonctions virtuelles, la surcharge d'opérateurs, l'héritage (simple ou multiple), les « templates », la gestion d'exceptions...
Le langage C++ est normalisé par l'ISO. Sa première normalisation date de 1998 (ISO/CEI 14882:1998), et sa dernière de 2003 (ISO/CEI 14882:2003). La normalisation de 1998 standardise la base du langage (Core Language) ainsi que la bibliothèque standard du C++ (C++ Standard Library).
Le nom signifie « C incrémenté », puisqu'on incrémente une variable (c'est-à-dire qu'on lui ajoute 1) en notant « ++ » derière elle :
l'instruction i++
, par exemple, est l'équivalent de celle-ci : i=i+1
Il existe de nombreuses autres bibliothèques en C++ non incluses dans le standard. De plus, le C++ permet l'utilisation des nombreuses bibliothèques C existantes.
Fonctionnalités introduites par le C++
modifierOn peut considérer que le C++ « est du C » avec un ajout de fonctionnalités. Une remarque importante est à faire cependant : Certains programmes syntaxiquement corrects en C, ne le sont pas en C++.
Les fonctionnalités ajoutées sont :
- les déclarations reconnues comme instructions (repris dans C99) ;
- les opérateurs
new
etdelete
pour la gestion d'allocation mémoire ; - le type de données
bool
(booléen) ; - les références ;
- le mot clé
const
pour définir des constantes (repris par C à la fin des années 1980) ; - les fonctions
inline
; - les paramètres par défaut dans les fonctions ;
- les référentiels lexicaux (namespace) et l'opérateur de résolution
::
; - les classes, ainsi que tout ce qui y est lié : l'héritage, les fonctions membres, les fonctions membres virtuelles, les constructeurs et le destructeur ;
- la surcharge des opérateurs ;
- les templates ;
- la gestion d'exceptions ;
- l'identification de type pendant l'exécution (RTTI : run-time type identification) ;
- le commentaire de fin de ligne introduit par « // » (existant dans BCPL, repris dans C99).
La compilation d'un programme en C++ effectue également un contrôle plus minutieux sur le typage.
Histoire du C++
modifierStroustrup a commencé à travailler sur du C avec classes en 1979. L'idée de créer un nouveau langage vient de l'expérience en programmation de Stroustrup pour sa thèse de doctorat. Stroustrup trouvait que Simula avait des fonctionnalités très utiles pour le développement de gros programmes mais qu'il était trop lent pour être utilisé en pratique (dû à un problème d'implémentation du compilateur Simula), tandis que BCPL était rapide mais de trop bas niveau et pas adapté au développement de gros logiciels. Quand Stroustrup commença à travailler dans les laboratoires de Bell, on lui demanda d'analyser le noyau UNIX en vue de faire du calcul distribué. Se rappelant sa thèse, Stroustrup commença à améliorer le langage C avec des fonctionnalités similaires à celle de Simula. C a été choisi parce qu'il est rapide, portable et d'usage général. Au départ, classe (avec encapsulation des données), classe dérivée, vérification des types renforcés (typage fort), inlining, et argument par défaut étaient des fonctionnalités ajoutées au C.
Comme Stroustrup développait le C avec classes, il a aussi écrit CFront, un compilateur qui génère du code source C à partir de code source C avec classes (C++). La première commercialisation fut en octobre 1985.
En 1983, le nom du langage fut changé de "C avec classes" en C++. Parmi les nouvelles fonctionnalités qui furent ajoutées au langage, il y avait les fonctions virtuelles, la surcharge des opérateurs et des fonctions, les références, les constantes, le contrôle du typage amélioré et un nouveau style de commentaire (//). En 1985 fut publiée la première édition de The C++ programming Language, apportant ainsi une référence importante au langage qui n'avait pas encore de standard officiel. En 1989, sortie de la version 2.0 du C++. Parmi les nouvelles fonctionnalités, il y avait l'héritage multiple, les classes abstraites, les fonctions membres statiques, les fonctions membres constantes, et les membres protégés. En 1990, The Annotated C++ Reference Manual fut publié apportant les bases du futur standard. Les ajouts de fonctionnalités tardifs comprennent les templates, les exceptions, les espace de noms, les nouvelles conversions et le type booléen.
Comme le langage C++ évoluait, la bibliothèque standard évoluait de concert. La première addition à la bibliothèque standard du C++ fut les flux d'E/S qui apporte les fonctionnalités nécessaires au remplacement des fonctions C traditionnelles telles que printf et scanf. Ensuite, parmi les additions les plus importantes, il y a la Standard Template Library.
Après des années de travail, un comité réunissant l'ANSI et l'ISO standardisa le C++ en 1998 (ISO/CEI 14882:1998). Pendant quelques années après la sortie officielle du standard, le comité traita le rapport de problèmes et publia une version corrigée du standard C++ en 2003.
Un premier programme : Hello world
modifierVoici l'exemple de Hello world donné dans The C++ Programming Language, Third Edition de Bjarne Stroustrup :
#include <iostream> int main() { std::cout << "Hello, new world!\n"; }
Notions de base du C++
modifierDéclarations, types de base et affectation
modifierIdentificateur
modifierChaque variable en C++ doit posséder un identificateur qui est le nom de la variable. Un identficateur est une suite de caractères ou de chiffres, ou d'underscores _. Un identificateur ne peut pas commencer par un chiffre.
Exemple : a, a1, toto, y78, nom_employe
Déclaration
modifierChaque variable utilisée en C++ doit être déclarée : la déclaration va fixer le type et l'identificateur de la variable. Le type peut être vu comme la nature des données que contient la variable. Le C++ a un typage strict : le type d'une variable ne peut pas changer au cours de l'exécution du programme.
La syntaxe d'une déclaration est la suivante :
type identificateur
Exemple de déclaration
modifierint a;
On déclare une variable d'identificateur a de type int (entier).
Types de base
modifierUn certain nombre de type de base sont définis dans le langage C++ :
- les types entiers
- le type int permet de stocker un entier.
- le type short int permet de stocker un entier mais cet entier devra évoluer dans un plage de valeur plus restreinte que le type int.
- le type long int permet de stocker un entier mais cet entier devra évoluer dans un plage de valeur plus grande que le type int.
- le type unsigned int permet de représenter des entiers mais uniquement positif ou nul.
- il existe aussi les type unsigned short int' et unsigned long int permettant de représenter des entiers positifs ou nul respectivement courts et longs.
Une des grosse difficulté avec le C++ et que le nombre de bits ssur lesquels sont représentés les types int, short et long ne sont pas précisés. Ainsi un int peut être représenté aussi bien sur 32 bits que sur 64 bits. Ceci pose de gros problème de portabilité. La seule chose qui est spécifiée est qu'un long int est plus long qu'un int et qu'un short int est plus court qu'un int. Cela peut causer de gros soucis de portabilité.
- les types réels
- le type float : il permet de représenter des réels en simple précision.
- le type double : il permet de représenter des réels en double précision.
Les systèmes de représentation utilisés par les double et les int ne sont pas précisés.
- le type char : permet de représenter un caractère. Le système de représentation (souvent le coage ASCII) n'est pas spécifié ni le nombre de bits utilisés (souvent 8 bits).
- le type bool : le type bool permet de représenter un booléen c'est à dire une valeur pouvent valoir soit true soit false.
L'affectation
modifier- Syntaxe :
identificateur=expression
- sémantique
On commence par évaluer l'expression, on stocke ensuite sont résultat dans la variable s.
Les opérateurs
modifier- sur les entiers :
- les symboles +, - , * et / sont utilisés pour faire respctivement des additions, soustractions, multiplications et divisions sur des entiers. La division sur les entiers entraîne une troncature.
- le symbole % permet de faire le module. 8%3 est 8 modulo 3 c'est-à-dire le résultat de la division de 8 par 3 c'est-à-dire 2.
- on peut utiliser les parenthèses pour préciser l'ordre des opérations.
- sur les réels :
- les symboles +, - , * et / sont utilisés pour faire respctivement des additions, soustractions, multiplications et divisions sur des réels.
- on peut utiliser les parenthèses pour préciser l'ordre des opérations.
- sur les booléens :
- le test d'égalité utilise le symbole ==
- le test différent utilise le symbole !=
- le test strictement supérieur utilise le symbole >
- le test supérieur ou égal utilise le symbole >=
- le test strictement inférieur utilise le symbole <
- le test inférieur ou égal utilise le symbole <=
- le symbole && représente le ET logique.
- le symbole || représente le OU logique.
- le symbole ! représente le NON logique.
- on peut utiliser les parenthèses pour préciser l'ordre des opérations.
Exemple de programme
modifier#include <iostream> using namespace std; int main() { int a,b,s; cout<<"Tapez la valeur de a : ";cin>>a; cout<<"Tapez la valeur de n : ";cin>>b; s=a+b; cout<<"La somme a+b vaut : "<<s<<endl; return 0; }
Exécution :
Tapez la valeur de a : 45
Tapez la valeur de b : 67
La somme a+b vaut 112
Explications : dans ce programme, on déclare 3 variables a, b et c. On demande à l'utilisateur du programme de taper la valeur de a puis la valeur de b. cout sert à l'affichage à l'écran et cin à la saisie au clavier. Le programme calcule ensuite dans la variable s la somme a+b. On affiche finalement la valeur de s.
Les pointeurs
modifierUn pointeur correpond à l'adresse en mémoire où est stockée une variable d'un certain type. Il permet d'accéder indirectement à une variable. Il permet également de construire des structures de données complexes.
Déclaration
modifiertype * identificateur;
La variable identificateur est un pointeur vers une variable de type type.
L'opérateur &
modifierIl permet d'obtenir un pointeur vers une variable.
&identificateur permet d'obtenir un pointeur vers la variable identificateur.
L'opérateur *
modifierIl permet de déréférencer un pointeur c'est-à-dire à partir d'un pointeur il permet d'obtenir la valeur de la variable pointée.
*pointeur permet d'obtenir la valeur de la variable pointée par pointeur.
Exemple de programme
modifier#include <iostream> using namespace std; int main() { int a,b,c; int *x,*y; a=98; b=108; x=&a; c=*x+5; y=&b; *y=a+10; cout<<"La variable b vaut : "<<b<<endl; cout<<"La variable c vaut : "<<c<<endl; return 0; }
Exécution :
La variable b vaut 88
La variable c vaut 103
Explications :
- dans ce programme, on déclare 3 variables a, b et c. On déclare ensuite 2 pointeurs vers des entiers x et y.
- a est initialisé à 98 et b à 78.
- x=&a; permet de mettre dans x l'adresse de a. x est désormais un pointeur vers a.
- x est la valeur de la variable pointée par x, c'est-à-dire la valeur de a, et vaut donc 98.
c=*x+5; permet donc de tranférer 98+5 donc 103 dans la variable c.
- y=&b permet de mettre dans y l'adressee la variable b. y est désormais un pointeur vers b.
a+10 vaut 98+10 donc 108.
*y=a+10; permet de tranférer dans la variable pointée par y la valeur de a+10, c'est-à-dire 108. On transfère donc 108 dans b.
- on affiche ensuite les valeurs de b et c c'est à dire respectivement 108 et 103.
Les références
modifierLes référence peuvent être vue comme un moyen d'accès indirect à une variable.
Déclarations
modifierSyntaxe :
type & identificateur1=identificateur2;
Sémantique
modifierLa variable identificateur1 est une référence vers la variable identificateur2. La variable identificateur2 doit être de type type.
Exemple de programme
modifier#include <iostream> using namespace std; int main() { int a,b,c; a=98; b=78; int &x=a; c=x+5; int &y=b; y=a+10; cout<<"La variable b vaut : "<<b<<endl; cout<<"La variable c vaut : "<<c<<endl; return 0; }
Exécution
La variable b vaut : 108
La variable c vaut : 103
Explications
- Dans ce programme, on définit 3 variables entières a, b et c et on initialise a à 98 et b à 78.
- int &x=a; permet de déclarer une référence x vers la variable a.
x+5 vaut donc la même chose que a+5 donc 103.
c=x+5; permet donc de transférer 103 dans la variable c.
- int &y=b; permet de déclarer une référence y vers la variable b.
a+10 vaut 98+10 donc 108.
y=a+10; permet de transférer 108 dans la variable b.
- on affiche ensuite b et c c'est-à-dire respectivement 108 et 103.
Les structures de contrôle
modifierLe structures de contrôle permettent d'interrompre l'exécution séquentielle des différentes instructions d'un programme pour effectuer des tests (les conditionnelles) ou pour répéter certaines partie d'un programme (les boucles). La notion de structure de contrôle est une notion fondamentale en programmation et est à la base de toute l'algorithmiqe. En C++, on trouve comme structure de contrôle :
- trois structures de contrôle conditionnelles :
- le if.
- le if...else....
- le switch.
- trois structures de contrôle répétitives :
- le for.
- le while.
- le do...while.
- deux autres structure de contrôle un peu particulière le goto et le break.
Le if
modifierCette structure de contrôle permet d'exécuter une instruction ou une suite d'instructions seulement si une condition est vraie.
- Syntaxe :
if(condition) instruction;
- Sémantique :
On évalue la condition :
- si elle est vraie on exécute l’instruction et on passe à l ’instruction suivante.
- si elle est fausse on passe directement à l ’instruction suivante.
L ’instruction peut être remplacée par une suite d ’instructions entre accolades
- Exemple :
#include <iostream> using namespace std; int main() { int a; cout << "Tapez la valeur de a : "; cin >> a; if (a > 10) cout << "a est plus grand que 10" << endl; cout << "Le programme est fini" << endl; return 0; }
Ce programme demande à l'utilisateur de taper un entier a. Si a est strictement plus grand que 10, il affiche "a est plus grand que 10". Dans le cas contraire, il n'affiche rien.
Exécution 1 :
Tapez la valeur de a : 12
a est plus grand que 10
Exécution 2 :
Tapez la valeur de a : 8
Le if ...else...
modifierCette structure de contrôle permet d'exécution soit l'instruction1, soit l'instruction2 en fonction du résultat d'une condition.
- Syntaxe :
Syntaxe : if(condition) instruction1; else instruction2;
- Sémantique :
1) On évalue la condition,
2) si elle est vraie, on exécute l ’instruction1 et on passe à l ’instruction suivante.
3) si elle est fausse, on exécute l ’instruction2 et on passe à l ’instruction suivante.
L’instruction1 ou l ’instruction2 peuvent être remplacées par des suite d ’instructions entre accolades .
- Exemple :
#include <iostream> using namespace std; int main() { int a; cout << "Tapez la valeur de a : "; cin >> a; if (a > 10) cout << "a est plus grand que 10" << endl; else cout << "a est plus inférieur ou égal à 10" << endl; return 0; }
Ce programme demande à l'utilisateur de taper un entier a. Si a est strictement plus grand que 10, il affiche "a est plus grand que 10". Dans le cas contraire, il affiche "a est plus inférieur ou égal à 10" .
Exécution 1 :
Tapez la valeur de a : 12
a est plus grand que 10
Exécution 2 :
Tapez la valeur de a : 8
"a est plus inférieur ou égal à 10"
Le switch
modifier- Syntaxe :
switch(identificateur) { case c1:instruction1;break; case c2:instruction2;break; case c3:instruction3;break; ... default: instruction;break; }
- Sémantique du switch :
On teste la variable définie par l'identificateur. On la compare successivement aux constantes c1, c2, c3,…etc… Si la variable vaut c1 alors on exécute l’instruction1 et on passe à l’instruction suivante. Si elle vaut c2, on exécute l'instruction2 et on passe à l’instruction suivante. Idem s'il vaut c3. Si elle ne vaut ni c1, ni c2, ni c3 alors on exécute l'instruction après default et on passe à l’instruction suivante. Le default est facultatif. On peut remplacer les instructions instruction1, instruction2, instruction3 par des suites d'instructions sans mettre d'accolades. Les valeurs c1, c2,c3 .. sont obligatoirement des constantes.
- Exemple
#include <iostream> using namespace std; int main() { int a; cout << "Tapez la valeur de a : "; cin >> a; switch(a) { case 1 : cout<<"a vaut 1"<<endl; break ; case 2 : cout<<"a vaut 2"<<endl; break ; case 3 : cout<<"a vaut 3"<<endl; break ; default : cout<<"a ne vaut ni 1, ni 2, ni 3"<<endl; break ; } return 0; }
Ce programme demande à l'utilisateur de taper une variable a. On tete ensuite la valeur de a : en fonction de cette valeur on affiche respectivement les messages "a vaut 1" , ou "a vaut 2" , ou "a vaut 3" ,ou "a ne vaut ni 1, ni 2, ni 3".
Exécution 1 :
Tapez la valeur de a : 1
a vaut 1
Exécution 2 :
Tapez la valeur de a : 2
a vaut 2
Exécution 3 :
Tapez la valeur de a : 3
a vaut 1
Exécution 4 :
Tapez la valeur de a : 11
a vaut ne vaut ni 1, ni 2, ni 3
Le while
modifier- Syntaxe :
while(condition)instruction;
- Sémantique du do … while
1) On teste la condition :
2) si elle est vraie, on exécute l’instruction puis on recommence au 1).
3) si elle est fausse, on passe à l’instruction suivante.
L’instruction peut être une suite d ’instructions entre accolades.
- Exemple de programme
#include <iostream> using namespace std; int main() { int i=0; while(i<10) { cout<<"La valeur de i vaut : "<<i<<endl; i++; } cout<<"La valeur finale de i vaut : "<<i<<endl; return 0; }
Exécution :
La valeur de i est : 0
La valeur de i est : 1
La valeur de i est : 2
La valeur de i est : 3
La valeur de i est : 4
La valeur de i est : 5
La valeur de i est : 6
La valeur de i est : 7
La valeur de i est : 8
La valeur de i est : 9
La valeur finale de i est : 10
Explications
La variable i est initialisée à 0.
A chaque étape, à la fin du corps du while, on incrémente i de 1.
On exécute donc le corps du while la première fois avec i valant 0, la dernière fois avec i valant 9.
Lorsqu’on sort du while i vaut 10.
Le do ... while....
modifier- Syntaxe :
do {instruction; } while(condition);
- Sémantique :
1) on exécute l’instruction.
2) on évalue la condition.
3) si elle est vraie, on recommence au 1.
4) si elle est fausse, on passe à l ’instruction suivante.
- Exemple
#include <iostream> using namesapce std; int main() { int i=0; do { cout<<"La valeur de i vaut : "<<i<<endl; i=i+1; }while(i<10); cout<<"La valeur finale de i est "<<i<<endl; return 0; }
Exécution :
La valeur de i vaut : 0
La valeur de i vaut : 1
La valeur de i vaut : 2
La valeur de i vaut : 3
La valeur de i vaut : 4
La valeur de i vaut : 5
La valeur de i vaut : 6
La valeur de i vaut : 7
La valeur de i vaut : 8
La valeur de i vaut : 9
La valeur finale de i est : 10
Le for
modifierLe for est une structure de contrôle qui permet de répéter un certain nombre de fois une partie d'un programme.
- Syntaxe :
for(instruction1; condition; instruction2) instruction3;
- Sémantique du for :
1) on exécute l’instruction1.
2) On teste la condition :
- si elle est vraie, on exécute l’instruction3, puis l’instrution2 puis on revient au 2).
- si elle est fausse on passe à l’instruction suivante.
L’instruction3 peut être une suite d ’instructions entre accolades.
- Exemple
#include <iostream> using namespace std; int main() { int i; for(i=0;i<10;i=i+1) cout<<"BONJOUR"<<endl; return 0; }
Le goto
modifier
break
modifier
Les tableaux
modifierLes tableaux sont des structures de données constituées d'un certain nombre de case. On peut accéder directement au contenu d'une case en indiquant l'indice de la case.
Les tableaux statiques
modifier- Syntaxe
type identificateur[taille]
- Sémantique :
identificateur est un tableau de taille cases contenant chacune un élément de type type. taille est obligatoirement une valeur constante. La taille du tableau est donc figée une fois pour toute et ne peut pas être modifiée en cours d'exécution. Pour désigner la i-ième case de tableau, on écrit identificateur[i] où i est un entier quelconque. Les cases sont numérotées à partir de 0 : les valeurs possibles de i vont donc de 0 à taille-1.
- Pointeurs et tableaux
Il existe un lien entre les pointeurs et les tableaux : identificateur est en fait un pointeur constant vers un élément de type type.
- Exemple
#include <iostream> using namespace std; int main() { int i; int t[10]; for(i=0;i<10;i++) t[i]=i*i; for(i=0;i<10;i++) cout<<t[i]<<endl; return 0; }
Exécution :
0
1
4
9
16
25
36
49
64
81
Les tableaux dynamiques
modifierUn tableau dynamique est un tableau dont le nombre de cases peut varier au cours de l'exécution du programme. Il permet d'ajuster la taille du tableau au besoin du programmeur.
- L'opérateur new
Syntaxe : pointeur=new type[taille];
Cette utilisation du new permet de demander un tableau de taille cases contenant chacune un élement de type type. La variable taille est un entier qui peut être quelconque. new reverra un pointeur vers un type. La variable pointeur est donc du type type *. Les cases du tableaux seront numérotées de 0 à taille-1 et on y accédera comme un tableau statique. S'il n'y a pas assez de mémoire disponible, new renvoie le pointeur NULL.
- L'opérateur delete
Syntaxe : delete []pointeur;
Cette utilisation de delete permet de détruire un tableau précédemment alloué grâce à new. Le programmeeur en C++ doit gérer la destruction effective des tableaux qu'il a créé dynamiquement.
- Exemple
#include <iostream> using namespace std; int main() { int i,taille; cout<<"Tapez la valeur de taille : ";cin>>taille; int *t; t=new int[taille]; for(i=0;i<taille;i++) t[i]=i*i; for(i=0;i<taille;i++) cout<<t[i]<<endl; delete []t; return 0; }
Exécution 1 :
Tapez la valeur de taille : 4
0
1
4
9
Exécution 2 :
Tapez la valeur de taille : 6
0
1
4
9
16
25
Les structures
modifierPrésentation
modifierLes structures permettent de regrouper dans une même entité plusieurs variables. Ainsi il est possible de construire de nouveaux types plus complexes.
Syntaxe
modifierstruct identificateur { //liste des différents champs constituant notre structure };
Nous définissions ici une structure appelée identificateur.
Exemple
modifier#include <iostream> #include<cmath> using namespace std; struct Point { double x; double y; }; int main() { Point A,B; double dx, dy,distance; cout<<"Tapez l'abscisse de A : ";cin>>A.x; cout<<"Tapez l'ordonnée de A : ";cin>>A.y; cout<<"Tapez l'abscisse de B : ";cin>>B.x; cout<<"Tapez l'ordonnée de B : ";cin>>B.y; dx=A.x-B.x; dy=A.y-B.y; distance=sqrt(dx*dx+dy*dy); cout<<"La distance AB vaut : "<<distance<<endl; return 0; }
Les fonctions
modifierLe C++ est un langage procédural, on peut définir des fonctions qui vont effectuer une certaine tâche. On peut paramètrer des fonctions qui vont permettre de paramétrer cette tâche et rendre ainsi les fonctions réutilisables dans d'autres contextes. Une fonction pourra appeler d'autres fonctions et ainsi de suite. Une fonction peut même s'appeler elle-même : on parle alors de fonctions récursives.
Prototype d'une fonction
modifierDéfinition d'une fonction
modifierPassage de pointeurs en paramètre
modifierPassage de références en paramètre
modifierExemple
modifier
La programmation orientée objet en C++
modifierLe C++ utilise les concepts de la programmation orientée objet et permet entre autres :
- La classification,
- L'encapsulation,
- La composition de classes,
- L'association de classes,
- L'héritage, qui permet le polymorphisme,
- L'abstraction,
- La généricité.
La notion de classe
modifierUne classe permet de regrouper dans une même entité des données membres et des fonctions permettant de manipuler ces données appelées méthodes. La classe est la notion de base de la programmation orientée objet. Il s'agit en fait d'une évolution de la notion de structure mais la classe apporte de nouvelles notions orientées objet absolument fondamentales. Un objet est un élément d'une certaine classe : on parle de l'instance d'une classe.
L'encapsulation en C++
modifierL'encapsulation est un mécanisme qui interdit d'accéder à certaines données depuis l'extérieur de la classe. Ainsi, un utilisateur de la classe ne pourra pas accéder à tous les éléments de celles-ci. Il sera obligé d'utiliser certaines fonctions membres de la classe (celles qui sont publiques). L'avantage de cette restriction est qu'il empêche par exemple un utilisateur de la classe de mettre les données dont un état incohérent. Vue de l'extérieur, la classe apparait comme une boîte noire qui a un certain comportement à laquelle on ne peut accéder que par les méthodes publiques. Cette notion est extrêmement puissante et permet de nombreux effets de bord.
L'encapsulation permet de distinguer très nettement ce que fait la classe et sa sémantique précises de la manière dont on l'implémente. Cette réflexion permet de répondre dans un premier temps à la question "Comment on utilise la classe ?". Ce n'est que dans un second temps que l'aspect technique entre en jeu et que le programmeur doit répondre à la question "Comment vais-je programmer les fonctionnalités de la classe qui ont été spécifiées". L'encapsulation permet de faire abstraction du fonctionnement interne (c'est-à-dire, l'implémentation) d'une classe et ainsi de ne se préoccuper que des services rendus par celle-ci.
Le C++ implémente l'encapsulation en permettant de déclarer les membres d'une classe avec le mot réservé public
, private
ou protected
. Ainsi, lorsqu'un membre est déclaré :
- public, il sera accessible depuis n'importe quelle fonction.
- private, il sera uniquement accessible d'une part, depuis les fonctions qui sont membres de la classe et, d'autre part, depuis les fonctions autorisées explicitement par la classe (par l'intermédiaire du mot réservé
friend
). Ces dernière fonctions sont appelées fonctions amies de la classe. - protected, il aura les mêmes restrictions que s'il était déclaré private, mais il sera en revanche accessible par les classes filles.
Le C++ n'impose pas l'encapsulation des membres dans leurs classes. On pourrait donc déclarer tous les membres publics, mais en perdant une partie des bénéfices apportés par la programmation orientée objet. Il est de bon usage de déclarer toutes les données privées, ou au moins protégées, et de rendre publiques les méthodes agissant sur ces données. Ceci permet de cacher les détails de l'implémentation de la classe.
Constructeurs et destructeurs
modifier- Constructeurs
- Lorsqu'on crée une nouvelle instance d'une classe, les données membres de cette instance ne sont pas initialisées par défaut. Un constructuer est une méthode qui sera appelée au moment de la création d'une nouvelle instance d'une classe. Il peut avoir plusieurs constructeurs d'une classe avec différents paramètres qui serviront à initialiser notre classe. Le constructeur d'une classe A est appelé automatiquement lorsqu'on crée un instance en écriavant : A toto; ou encore A toto(6,9);. Ils sont également appelé lorsqu'une intsnace est créée grâce à l'opérateur new.
- Syntaxe :
A(); où A est le nom de la classe.
A(paramètres);
- Destructeurs
- Les destructeurs sont appelés lorsqu'une instance d'une classe est détruite. Cela arrive à la fin de l'exécution d'une méthode : si vous avez déclaré , localement à une méthode un élément d'un classe A par A toto; alors à la fin de l'appel de la méthode, le destructeur éventuelle de la classe est appelé. Il est également appelé lorsqu'on détruit une instance grâce à delete. Il ne peut y avoir qu'un seul destructeur pour une même classe.
- Syntaxe :
~A(); où A est le nom de la classe.
Les opérateurs new et delete
modifierIl est parfois intéressant de crée dynamiquement de nouvelles instances d'une classe. cela s'avère indispensable lorsque vous manipulez certaines structures de données complexes. L'opérateur new permet de créer un nouvelle instance d'une classe à en écrivant
pointeur=new A();
La variable pointeur doit alors être du type A *.
Exemples de classes
modifierExemple 1
modifier- Fichier Point.h
#ifndef POINT_H #define POINT_H #include<iostream> using namespace std; class Point { public: // Constructeurs Point(); Point(double x, double y); //Accesseurs et mutateurs void setX(double x); void setY(double y); double getX(); double getY(); // Autres méthodes double distance(const Point &P); Point milieu(const Point &P); private: double x,y; }; #endif
- Fichier Point.cpp
#include "Point.h" #include<cmath> #include <iostream> using namespace std; Point::Point() : x(0),y(0) { } Point::Point(double x, double y) : x(x),y(y) { } void Point::setX(double x) { this->x=x; } void Point::setY(double y) { this->x=x; } double Point::getX() { return x; } double Point::getY() { return y; } double Point::distance(const Point &P) { double dx,dy; dx=x-P.x; dy=y-P.y; return sqrt(dx*dx+dy*dy); } Point Point::milieu(const Point &P) { Point M; M.x=(P.x+x)/2; M.y=(P.y+y)/2; return M; } void Point::saisir() { cout<<"Tapez l'abscisse : ";cin>>x; cout<<"Tapez l'ordonnée : ";cin>>y; } void Point::afficher() { cout<<"L'abscisse vaut "<<x<<endl; cout<<"L'abscisse vaut "<<y<<endl; }
- Fichier main.cpp
#include <iostream> using namespace std; #include"Point.h" int main() { Point A,B,C; double d; cout<<"SAISIE DU POINT A"<<endl; A.saisir(); cout<<endl; cout<<"SAISIE DU POINT B"<<endl; B.saisir(); cout<<endl; C=A.milieu(B); d=A.distance(B); cout<<"MILIEU DE AB"<<endl; C.afficher(); cout<<endl; cout<<"La distance AB vaut :"<<d<<endl; return 0; }
Exemple 2
modifierExemple de la déclaration de la classe MessageInternet comportant des attributs privés et des méthodes publiques dont le constructeur 'MessageInternet'.
class MessageInternet { private: string m_sujet; string m_expediteur; string m_destinataire; public: MessageInternet (string sujet, string expediteur, string destinataire); string sujet (); string expediteur (); string destinataire (); };
Surcharge d'opérateurs
modifierPrésentation
modifierPour certaine classe, la notion d'addition ou de multiplication est totalement naturelle. La surcharge d'opérateurs permet d'écrire directement U+V lorsqu'on veut additionner deux instances U et V d'une même classe A.
Syntaxe
modifierPour surcharge l'opérateur+ de la classe A, il suffit de créer une méthode :
A operator+(A Fraction & f);
Exemple
modifier- Fichier Fraction.h
#ifndef FRACTION_H #define FRACTION_H #include<iostream> using namespace std; class Fraction { friend ostream & operator<<(ostream & out, const Fraction &f); friend istream & operator>>(istream &in, Fraction &f); public: Fraction(); Fraction(int i); Fraction(int num,int den); Fraction operator+(const Fraction & f); Fraction operator-(const Fraction & f); Fraction operator*(const Fraction & f); Fraction operator/(const Fraction & f); private: int num,den; int pgcd(int x, int y); void normalise(); }; #endif
- Fichier Fraction.cpp
#include"Fraction.h" #include<sstream> Fraction::Fraction():num(0),den(1) { } Fraction:: Fraction(int i):num(i),den(1) { } Fraction::Fraction(int num,int den) : num(num),den(den) { normalise(); } ostream & operator<<(ostream & out, const Fraction &f) { if(f.den!=1)out<<f.num<<"/"<<f.den; else out<<f.num; return out; } istream & operator>>(istream &in, Fraction &f) { string s; bool ok=true; do { cout<<"Tapez le numerateur : ";getline(in,s); istringstream is1(s); ok=(is1>>f.num) && is1.eof(); }while(!ok); do { cout<<"Tapez le denominateur : ";getline(in,s); istringstream is2(s); ok=(is2>>f.den)&& is2.eof(); }while(!ok); f.normalise(); } int Fraction::pgcd(int x, int y) { int r; if(x<=0 || y<=0)r=-1; else{ while(x!=0 && y!=0 && x!= y)if(y>x)y=y%x; else x=x%y; if(x==0)r=y; else r=x; } } void Fraction::normalise() { int s,n,d,p; if(den<0){s=-1;d=-den;}else {s=1;d=den;} if(num<0){s=-s;n=-num;} else n=num; if(n!=0) { if(d !=0){p=pgcd(n,d);n=n/p;d=d/p;num=n*s;den=d;} } else {num=0;den=1;} } Fraction Fraction::operator+(const Fraction & f) { Fraction r; r.num=f.den*num+den*f.num; r.den=f.den*den; r.normalise(); return r; } Fraction Fraction::operator-(const Fraction & f) { Fraction r; r.num=f.den*num-den*f.num; r.den=f.den*den; r.normalise(); return r; } Fraction Fraction::operator*(const Fraction & f) { Fraction r; r.num=f.num*num; r.den=f.den*den; r.normalise(); return r; } Fraction Fraction::operator/(const Fraction & f) { Fraction r; r.num=f.den*num; r.den=f.num*den; r.normalise(); return r; }
- Fichier main.cpp
#include<iostream> using namespace std; #include"Fraction.h" int main() { Fraction f1,f2,f3,f4,E; cout<<"SAISIE de f1 "<<endl;cin>>f1; cout<<"SAISIE de f2 "<<endl;cin>>f2; f3=Fraction(3,4); f4=Fraction(5,8); E=(f1+f3-f2)/(f1*f2-f4)+4; cout<<"E="<<E<<endl; return 0; }
Héritage
modifierPrésentation
modifierA partir d'une classe A, on peut créer un classe B qui possède toutes les caractéristiques de la classe A mais on a rajouté un certains nombre de méthodes qui sont spécifique à A. Cette notion orientée objet fondamentale s'appelle l'héritage.
Il existe en fait 3 types d'héritage public, private ou protected qui permet de spécifier si oui ou non une méthode de le classe B peut modifier une données membres de la classe A, selon qu'elle soit public, private ou protected.
Syntaxe
modifierclass B : type_héritage A { ....... };
type_héritage est le mot clé public, protected ou private.
Exemple
modifierClasses abstraites
modifierPrésentation
modifierUne classe abstraite est une classe pour laquelle on a défini une méthode mais on a explicitement indiqué qu'on ne fournira aucune implémentation de cette méthode. Il est interdit de créer une instance d'une classe abstraite. Ce mécanisme est extrêmement puissant pour manipuler des concepts abstraits. On peut même avoir une classe pour laquelle toutes les méthodes sont abstraites, on parle alors de classe abstraite pure.
Syntaxe
modifiertype nom_méthode(paramètres) =0
Exemple
modifierLa généricité avec les templates
modifierÀ quoi servent les templates ?
modifierAvec les templates, on peut écrire des fonctions et des classes en paramétrant le type de certains de leurs constituants (type des paramètres ou type de retour pour une fonction, type des éléments pour une classe collection par exemple). Les templates permettent d'écrire du code générique, c'est-à-dire qui peut servir pour une famille de fonctions ou de classes qui ne diffèrent que par la valeur de ces paramètres.
Pourquoi utiliser des templates ?
modifierEn programmation, il faut parfois écrire de nombreuses versions d'une même fonction ou classe suivant les types de données manipulées.
Par exemple, un tableau de int ou un tableau de double sont très semblables, les fonctions de tri ou de recherche dans ces tableaux sont identiques au type près.
En résumé, l'utilisation des templates permet de "paramétrer" le type des données manipulées.
Avantages à utiliser des templates
modifier- écritures uniques pour les fonctions et les classes.
- moins d'erreur dû à la réécriture (copier-coller assassin!).
- constitution d'une bibliothèque de classes et de fonctions réutilisables dans d'autres contextes.
Exemple de templates
modifierDans la bibliothèque standard C++, il y a de nombreux templates. On citera à titre d'exemple, les entrée/sorties, les chaînes de caractères ou les containers. Les classes string, istream, ostream et iostream sont toutes des instanciations de char type.
Les fonctions de recherche et de tri sont aussi des templates écrites et utilisables avec de nombreux types.
// La fonction template Max peut être appelée avec tout type // copiable et comparable avec l'opérateur <. template <typename T> T Max(T a, T b) { return a < b ? b : a; } #include <string> int main() { int i = Max(3, 5); char c = Max('e', 'b'); std::string s = Max(std::string("hello"), std::string("world")); float f = Max<float>(1, 2.2); }
La bibliothèque standard (C++ standard library)
modifierLa bibliothèque standard du C++ est en grande partie un surensemble des fonctions disponibles dans la bibliothèque standard du C. Elle englobe la STL qui met à la disposition du programmeur des outils puissants comme les collections (conteneurs) et les itérateurs.
A l'origine, la STL était une bibliothèque développée par Hewlett-Packard. Dans la norme, celle-ci n'est pas appelée STL, car elle est considérée comme faisant partie de la bibliothèque standard du C++. Toutefois, beaucoup de personnes l'appellent encore de cette manière pour distinguer d'une part, les fonctions d'entrées/sorties comprises dans cette bibliothèque et, d'autre part, celles fournies par la bibliothèque C.
Comme pour le C, l'utilisation d'une bibliothèque se fait par l'intermédiaire de la directive #include
(suivie du nom du fichier d'en-tête).
Bibliographie
modifier- Bjarne Stroustrup, Le langage C++, 2003, ISBN 2-7440-7003-3
- Bjarne Stroustrup, The Design and Evolution of C++, Addison-Wesley, 1st Ed., 1994, ISBN 0201543303
Liens externes
modifier- français Livre en ligne sur le langage C++
- français Centre de Développement Visual C++ - Site MSDN Contenu complet pour débutant, confirmé et expert
- français La F.A.Q C++
- anglais Coding style en C++
- anglais The C++ resources network
- anglais Site officiel du compilateur libre GCC
- anglais Site officiel de la librairie Standard C++ du compilateur GCC