Vous êtes sur la page 1sur 52

CHAPITRE 2

DU C À C++

Olfa FAKHFAKH POO – ENSI – 2011/2012


Plan
2

• Introduction
• Historique de C++
• Types de données - définition / déclaration
• Les fonctions
• Structuration d’un programme C++
Introduction
3

Système
d’exploitation
Langage

Modèle physique

Bibliothèques
Historique C++
4

• 1980 au laboratoire AT&T Bell (Stroustrup)


• Les classes introduites pré-compilateur de C
• 1985 : 1ère version publique
• 1995-1997 : révision standard ANSI
o soit pour améliorer les caractéristiques de la norme
ANSI, soit pour préparer le terrain pour les aspects
Objets

• Disponible sur toutes les plateformes. Il est distribué en


logiciel :
o domaine publique (environnement GNU),
o plusieurs sociétés commerciales (Microsoft, Borland,
Zortech, …).
C++ versus C
5

• Principal avantage : compatibilité C/C++


o même syntaxe de base
o code C "propre" directement compilable en C++
o facilité d'intégration de fichiers C++ et C dans un
même programme ( langage hybride)

• Principal inconvénient : compatibilité C/C++


o C++ hérite de certains choix ennuyeux du langage C !
Les commentaires
6

• ....
/* je suis un super commentaire en C
et je étends sur plusieurs lignes
printf("Gros commentaire"); */
....
// je suis un super commentaire C++ sur une ligne
....

• // n'appartient qu'au C++


Types de données
7

• C++ introduit le type bool pour palier à cette carence en C.


• Il s'accompagne des mot-clés true et false.
bool flag=true;

• Définition implicite du type, sans avoir à utiliser typedef :


enum values {1,2,3,4};
enum couleur { rouge=1, noir = 3, blanc =7};

// Ceci est aussi valable pour : union et struct


Types de données
8
Délocalisation des déclarations
9

• C
int i=5, itmp;
int j=2; i variable de
... parcours temporaire
for (itmp=0; itmp<10; itmp++)
{
j+=itmp;
} • C++
int i=5;
...
int j=2;
for (int i=0; i<10; i++)
{
j+=i; // on est sur le i local
}
// i vaut 5 !
// j vaut 47 !
Délocalisation des déclarations
10

• C++
void main()
{
Int k=100;
for ( int i = 0;i<10;i++ )
{
int j; // les variables i et j ne sont
} connues que du bloc
cout<< i;
cout << j;

cout << k; // la variable k est connue de


toute la fonction «main()»

}
Nouvelles possibilités d’E/S
11

 On peut utiliser en C++ les fonctions d’entrées/sorties


classiques du C (printf, scanf, puts, gets, putc, getc
...), à condition de déclarer le fichier d’en-tête
stdio.h.

 Il existe de nouvelles possibilités en C++, à condition


de déclarer le fichier d’en-tête iostream.h.

 Ces nouvelles possibilités ne nécessitent pas de


FORMATAGE des données
Nouvelles possibilités d’E/S
12

 Cout

 cout << "BONJOUR"; // équivalent à puts("BONJOUR");


 int n = 25;
 cout << "Valeur: "; // équivalent à puts("Valeur");
 cout << n; // équivalent à printf("%d",n);
 On peut encore écrire directement:
 cout <<"Valeur:" << n;
 cout <<"\n "; // pour aller à la ligne
 char c = ‘a’;

 cout << c << endl;


Nouvelles possibilités d’E/S
13

 Cin
 int n;
 cout<<"Saisir un entier: ";
 cin >> n; // équivalent à scanf("%d",&n);
 int a, b;
 cin >> a >> b; // saisie de 2 entiers séparés par un Retour
Charriot
Les conversions de type
14

 En C, lorsqu'on souhaitait réaliser la conversion d'une


expression dans un type donné, on utilisait la syntaxe
suivante :
 (type)expression (version C)
 Mais cette approche n'est pas cohérente avec le formalisme
fonctionnel
 C'est réparé dans le C++ et la même conversion s'écrit
désormais de la manière suivante :
 type(expression) (version C++)
 À noter qu'on peut aussi se sécuriser en faisant un mixage
des deux approches :
 (type)(expression) (version mixte)
Les conversions de type
15

int a,b;
The value of a is: 4
float x=3.2,y=1.9;

a = (int)x+y;
b = int(x+y); The value of b is: 5

cout << "The value of a is:" << a << endl;

cout << "The value of b is:" << b<< endl;


Les conversions de type
16

 Le langage C++ autorise les conversions de type entre variables de type


char, int, float, double:
Exemple:

The value of j is:97
int main(){ The value of j is:678
char c='a',d=25,e;
int i=67,j; The value of s is:25.0
float r=678.9,s; The value of e is:C
j = c;
cout << "The value of j is:" << j << endl;
j = r;
cout << "The value of j is:" << j << endl;
s = d;
cout << "The value of s is:" << s << endl;
e = i;
cout << "The value of e is:" << e << endl;
}

Une conversion de type float --> int ou char est dite dégradante
Une conversion de type int ou char --> float est dite non dégradante
Les constantes
17

• Le mot-clé const remplace la directive du préprocesseur #define


o constante typée /* constantes classiques en C */
o même les pointeurs ! #define PI 12
#define MOI "Etudiant II2"
#define MAX 100
/* quelques constantes classiques */
const int PI=12;
const char MOI[]="Etudiant II2";
const int MAX=100;
int tab[MAX]; /* tableau statique de 100 entiers */
float tab2[MAX + 1][MAX *2];
char c;
const char *p='t'; /* pointeur sur un caractere constant */
char * const q=&c; /* pointeur constant sur un caractere */
const char * const q=MOI; /* pointeur constant sur un caractere
constant */
....
Les constantes
18

 const T * p = &v; pointeur modifiable p vers un objet non


modifiable de type T

 T * const p = &v; pointeur p non modifiable vers un objet


modifiable de type T

 const T * const p = &v; pointeur p non modifiable vers un


objet non modifiable de type T
Les constantes
19
Les constantes
20
Typage et prototypage obligatoire
21
des fonctions
 La déclaration des arguments se fait toujours à l’intérieur des parenthèses.
 Le typage des fonctions est obligatoires, et possède un sens fort :
 on ne peut pas retourner une valeur si la fonction a été déclarée void, et
réciproquement, on doit retourner une valeur dans le cas contraire.
 Exemple :
void f(int, char*) ;
void f(int i, char* c) ;
int f(int i) { …return ‘une valeur entière’ };
….

 f(); // f ne peut pas être appelée avec des arguments.


 f(…) ; // f peut être appelée avec un nombre quelconque d’arguments.
Conversions de type lors d’appel à
22
fonction
 Le C++, contrairement au C, autorise, dans une certaine mesure, le non-
respect du type des arguments lors d’un appel à fonction:
 le compilateur opère alors une conversion de type.
 Exemple:

double ma_fonction(int u, float f)


void main()
{
char c; int i, j; float r; double r1, r2, r3, r4;
r1 = ma_fonction( i, r ); // appel standard
r2 = ma_fonction( c, r); // appel correct, c est converti en int
r3 = ma_fonction( i, j); // appel correct, j est converti en float
r4 = ma_fonction( r, j); // appel correct, r est converti en int
// et j est converti en float
}
La surcharges des fonctions
23

• Elle permet de déclarer puis définir des fonctions ayant un nom


identique mais une signature différente.
• Attention toutefois : le type de retour ne fait pas partie de la
signature. La surcharge doit par conséquent préserver le type de
retour, elle ne touche qu'aux paramètres.
 Exemple :
int f(int gros_entier);
int f(double gros_reel);
int f(const char gros_nom[], bool gros_flag);

 Remarques :
• La surcharge est une forme faible de polymorphisme.
• elle est surtout utilisée dans les classes, pour définir plusieurs variantes du
constructeur
• la surcharge peut se révéler particulièrement intéressante lorsqu'on souhaite
éviter des conversions de types indésirables lors du passage des
paramètres.
Les paramètres avec valeurs par
24
défaut
• C++ procure cette facilité en nous autorisant à fournir une
valeur par défaut aux paramètres.
• Il existe cependant une restriction importante dans la mise
en œuvre des paramètres par défaut:
o À partir du moment où un paramètre possède une valeur
par défaut, tous les paramètres suivants doivent également
en posséder une.
Les paramètres avec valeurs par
25
défaut
Exemple
void f1(int n = 3) // par défaut le paramètre n vaut 3
void f2(int n, float x = 2.35) // par défaut le paramètre x vaut 2.35
void f3(char c, int n = 3, float x = 2.35) // par défaut le paramètre n vaut 3

void main()
{
char a = 0; int i = 2; float r = 5.6;
f1(i); // l’argument n vaut 2, l’initialisation par défaut est ignorée
f1(); // l’argument n prend la valeur par défaut
f2(i,r); // les initialisations par défaut sont ignorées
f2(i) // le second paramètre prend la valeur par défaut
// f2(); interdit
f3(a, i, r); // les initialisations par défaut sont ignorées
f3(a, i); // le troisième paramètre prend la valeur par défaut
f3(a); // le deuxième et le troisième paramètres prennent
} // les valeurs par défaut
Les paramètres avec valeurs par
26
défaut
En effet, dans le cas contraire, cela pourrait
poser des problèmes pour le compilateur :
int f(int a=0, int b, int c=0);
....
i=f(1, 2, 3); // OK
j=f(4); // toujours OK ~ f(0, 4, 0)
k=f(5, 6);
// argh ! ~ f(5, 6, 0)
// ou f(0, 5, 6) ?
En revanche, l'exemple suivant est
// non respect de la contigüité valide :
void f(double x, double y=0.0, double z=0.0);
....
f(a); // OK ~ f(a, 0.0, 0.0)
f(a, b); // OK ~ f(a, b, 0.0)
f(a, b, c); // OK ~ f(a, b, c)
// respect de la contiguïté
Les paramètres anonymes
27

• C++ permet de déclarer des paramètres anonymes, c'est-


à-dire des paramètres dont seul le type est spécifié dans la
signature.
 Exemple:

int main (int argc, char *argv[ ]) int main (int, char **)
{ {
.... ....
} }
version C (nommage obligatoire) version C++ (paramètres
anonymes)
Allocation de la mémoire
28

Version C Version C++

#include <malloc.h> type *ptr, *ptr_T;


type*ptr; //réservation d’un espace
/*réservation d’un espace //mémoire pour les valeurs
mémoire pour les valeurs*/ ptr=new type;
ptr=(type*)malloc(sizeof(type)* ptr_T= new type[NbrDeValeurs];
NbrDeValeurs);
// libération
/* libération */
free ptr
delete ptr;
delete[ ] ptr_T;
La libération d'un bloc de mémoire
préalablement alloué par malloc
se fait par la fonction void free (void *). L'opérateur delete sert à détruire
Cette fonction n'annule pas le contenu du un objet ou un tableau créé par
pointeur. new.
Allocation de la mémoire
29

// déclaration d’un pointeur sur un entier


int *ad;
ad = new int; // réservation de place en mémoire pour un entier
//int *ad = new int;

char *adc;
//réservation de place en mémoire pour 100 caractères
adc = new char[100];
// char *adc = new char[100];

int *adi; // réservation de place en mémoire pour 40 entiers


adi = new int[40]; // int *adi = new int[40];

delete ad; // libération de place


delete adc;
delete adi;
Pile/Tas (Stack/Heap)
30

Mémoire allouée de Mémoire Allouée


manière statique (Pile) Dynamiquement (Tas)

Variables globales
Arguments Pointers
Valeurs de retour

Cell * ConstruireListe(int taille) {


int i; struct Cell {
Cell *cour, *tete; int valeur;
tete = NULL; Cell * suivant;
for (i=taille; i >= 0; i--) { }
cour = (Cell*) malloc (sizeof(Cell));
cour->valeur = i;
cour->suivant = tete;
// Point d’arrêt 2 void main () {
tete = cour;} Cell * tete ;
return tete;} tete = ConstruireListe(4);
}
Pile/Tas (Stack/Heap)
31
Pile/Tas (Stack/Heap)
32
Les références (alias)
33

 Une référence est un identificateur supplémentaire pour un


objet.
 On peut désormais définir des variables référence,
 c'est-à-dire des variables que l'on peut identifier à d'autres

variables.
int n,m ;
int& i=n ; // i variable référence sur n

i=m; // Signifie n=m et


// non que i devient une référence sur m !
•Physiquement, il s'agit d'un pointeur constant sur un objet,
•mais que le programme manipule comme s'il s'agissait directement de l'objet lui-même.
•(Toute opération citant une référence porte sur l'objet référencé, jamais sur le pointeur.)
Les références (alias)
34

Exemple:
int n;

int &p = n;
// p est une référence à n
// p occupe le même emplacement mémoire que n

n = 3;
cout<< p; // l’affichage donnera 3
Rappel : Passage de paramètres
35

Pour rappel, il y a 2 types de paramètres:


 paramètres (effectifs) réels: dans l'appel de fonction
 paramètres formels: dans l'entête de la fonction

En C++, 3 types de passage de paramètres:


 par valeur (existe aussi dans les langages C et Java)
 par adresse (existe aussi dans le langage C)
 par référence (uniquement dans les langages C++ et Java)
Passage de paramètres par valeurs
36

void increment(int n, int z) { n=n+z; }

Void main()
{
int k=7;
increment(k,3);
cout << k << endl; // affiche 7 mais pas 10 (i.e. 7+3)
}
Passage de paramètres par adresses
37 Remarque :
void increment(int *n, int z) { *n= *n + z; }
Int * k =new int (7);
Void main() { Increment(k,3);
int k=7; Cout << *k;
increment(&k,3);
cout << k << endl; // affiche 10 car c'est l'adresse qui a été passée.
}
Passage de paramètres par référence
38

 Une référence est surtout utilisée comme paramètre formel d'une fonction.
 A chaque appel de la fonction, elle est initialisée par le paramètre effectif
correspondant.
void increment(int& n, int z) { n= n + z; }

Void main()
{
int k=7;
increment(k,3);
cout << k << endl; // affiche 10
}

 En C++ le compilateur peut se charger lui même de la gestion des adresses.


 Le paramètre formel est un alias(référence) de l'emplacement mémoire du
paramètre réel.
Passages par références
39

Version C Version C++

void Swap (int * a, int * b) void Swap (int & a, int & b)
{ {
int tmp=*a; int tmp=a;
*a=*b; a=b;
*b=tmp; b=tmp;
} }
.... ....
int i=2, j=4; int i=2, j=4;
Swap (i, j);
Swap (&i, &j); // i vaut 4 et j vaut 2
/* i vaut 4 et j vaut 2 */
Passages par références
40

Remarque:
Lorsqu’on doit transmettre en argument la référence d’un
pointeur : int * & adr;

 adr: est une référence à un pointeur sur un int.


Rappel Macro en C
41

 Les macro sont remplacés dans le code avec la compilation


(preprocessing)
 Code volumineux
 Plus d’espace mémoire
 Les fonctions : à chaque appel il y aura mise en place des
instructions :
 Accès mémoire et modification des registres
 Perte de temps d’exécution

 L’appel d’un Macro est plus rapide relativement à un appel de


fonction
Rappel Macro en C
42

 Les macro sans paramètres : constantes #define N 10


 Utilisé dans le cas des structures de données contigües
 Exemple tableau : int tab [N]
 Facilites la modification du prog
 Non typée
 Les macro avec paramètres : fonctions
 MAX(a,b) (((a)>=(b)) ? (a) : (b))
 Économie de temps d’exécution : le macro ne passe pas dans la chaine de
compilation classique, c’est une injection dans le .obj
 Risque d’effet de bord non désirés
 #define CAREE (a)((a)*(a))
 CAREE (x++) donne ((x++) * (x++) ) -> l’opérateur ++ s’applique 2 fois
 Non typée : MAX (‘a’ , ‘b’) correcte syntaxiquement mais pas sémantique !
Fonctions inlines
43
Fonctions inlines
44

• En C, lorsqu'on souhaite factoriser un morceau de code sans pour autant


créer une fonction, on a la possibilité de définir une macro.

 macro / fonction (exécutables plus volumineux !)


• Les macros peuvent entraîner des effets de bords désastreux
lorsqu'elles sont mal définies.
• D'autre part, il n'y a aucun contrôle sur le type des arguments.
• En C++, l'introduction du mot-clé inline va nous permettre d'éviter le
recours aux macros.
 le compilateur se charge de la convertir en macro
• On a la sécurité d'une fonction et la rapidité d'une macro.

#define MAX(a,b) (((a)>=(b))? (a) : (b))


 inline int Max (int a, int b) {return (a>=b) ? a : b);}
Fonctions inlines
45

 Inline : demande au compilateur de ne pas instancier cette


fonction : le compilateur remplace l’appel de la fonction par le
code correspondant
 Programme volumineux
 Programme rapide : les mécanismes d’appel de fonction, de passage
des paramètres et de la valeur de retour sont évités
 Non récursives
 Pas de pointeurs sur une fonction inline

inline int Max (int a, int b) {return (a>=b) ? a : b);}


Structuration d’un programme C++
46

• Un programme C++ est constitué :


o une fonction main (point d’entrée)
o de classes réparties dans plusieurs fichiers (.cpp/.h)
o (éventuellement) de fonctions et variables globales (.c/.h)

• Chaque fichier peut comprendre :


o un nombre arbitraire de classes (si ça a un sens ...)
o des namespaces
Les inclusions des bibliothèques
47

• La manière classique d'inclure les fichiers d'en-tête des


bibliothèques du C était la suivante :
o #include <stdio.h>
#include <math.h>
#include <string.h>
• En C++, il n'est plus nécessaire de spécifier l'extension sur
les fichiers d'en-tête standards du C, mais il faut spécifier
que c'est un fichier de la librairie C en ajoutant le caractère
'c' devant
o #include <cstdio>
#include <cmath>
• Lorsqu’il s’agit d’une bibliothèque C++, pas d’extension
o #include <iostream>
Les espaces de nommages
48

Lorsque l'on doit utiliser plusieurs


bibliothèques dans un programme, on peut
être confronté au problème qu'un même
identificateur est utilisé par plusieurs
bibliothèques.
Les espaces de nommages
Donner un nom à un
49
"espace" de
déclarations
Les espaces de nommages
50

 En C, il était difficile de faire cohabiter plusieurs versions d'une même


structure de données.
 Pour éviter le conflit de noms, on était obligé de modifier les noms de
chaque structure

 C++ propose un moyen simple de résoudre ce problème : les


espaces de nommage.
 Les espaces de nommage permettent de définir une unité
cohérente dans laquelle regrouper les déclarations des
différents objets (types, constantes, variables, fonctions).
 Les identificateurs présents dans l'espace de nommage
possèdent alors une portée qui leur est spécifique.
Exemple : espaces de nommages
51

définition/utilisation du namespace
différenciation par les namespaces
namespace A
namespace Version1 {
{ void f() { ... };
typedef unsigned int B; }
.... namespace Version2 {
} void f() { ... };
.... }
A::B i; ....
// une variable de type B void main () {
Version1::f();
Version2::f();
....
}

spécifier l'espace de nommage par défaut à l'aide du mot-clé using.


using namespace A;
B i;
52

Vous aimerez peut-être aussi