0% ont trouvé ce document utile (0 vote)
0 vues24 pages

Cours

Ce document présente un cours sur le langage C++ destiné aux physiciens, en commençant par les bases du langage C. Il couvre des sujets tels que les déclarations de variables, les structures de contrôle, les fonctions, les tableaux, et les pointeurs, tout en soulignant les spécificités du C++. Le cours inclut également des exercices d'application pour renforcer la compréhension des concepts abordés.

Transféré par

Reda Mohammed
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
0 vues24 pages

Cours

Ce document présente un cours sur le langage C++ destiné aux physiciens, en commençant par les bases du langage C. Il couvre des sujets tels que les déclarations de variables, les structures de contrôle, les fonctions, les tableaux, et les pointeurs, tout en soulignant les spécificités du C++. Le cours inclut également des exercices d'application pour renforcer la compréhension des concepts abordés.

Transféré par

Reda Mohammed
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Université Henri Poincaré – Nancy I

Faculté des Sciences

Le langage C++ pour physiciens

Résumé de cours

X. CARON

1
PLAN

LE LANGAGE C

Introduction 3
Commentaires 3
Déclarations 3
Notion de bloc 4
Variables 4
Constantes nommées 5
Conversion de variables (transtypage) 5
Opérateurs de comparaison 5
Test 5
Boucles 6
Aiguillages 7
Opérateurs d'incrémentation 7
Les fonctions 7
Ordres de précompilation 8
Tableaux à une dimension 8
Tableaux à plusieurs dimensions 9
Pointeurs 9
Passage d’un tableau en paramètre dans une fonction 9
Allocation statique et allocation dynamique 9
Les entrées-sorties en C 10

LE LANGAGE C++

Spécificités du C++ 12
Passage de données 12
Notions de classe et d'objet 13
La classe, le constructeur, le destructeur 13
Les paramètres par défaut 15
Les variables statiques 16
L'allocation dynamique et le constructeur de recopie 16
Les fonctions amies 18
La redéfinition des opérateurs 18
Les patrons de classe 19
L'héritage (la POO) 20
Méthodes virtuelles 21
Classes virtuelles 22
Les flots d'entrée-sortie en C++ 22
Références 22
Exercices d'application 23

2
LE LANGAGE C

Le langage C++ utilisant comme base syntaxique le langage C, ce chapitre en rappelle quelques notions.

Le langage C a été créé en 1973 par l’équipe de Dennis Ritchie pour la mise au point du système
d’exploitation UNIX.
Il y a plusieurs normes pour ce langage. Ce document présente la norme ANSI agrémentée de facilités
d’écriture provenant du C++ (d’où l’obligation d’utiliser un compilateur C++).

* Introduction :

Programme le plus simple en C :


void main(void)
{
}

Ce programme se lance et se termine : il ne fait rien.


void veut dire vide et main indique que c'est le programme principal. Le premier void est le paramètre
de sortie (ici il ne sort rien, mais certains compilateurs exigent par exemple un entier en sortie) et le
deuxième void est le paramètre d'entrée.
Le programme doit être écrit dans un fichier dont le nom comporte l’extension .c (pour une compilation
en C) ou .cpp (pour une compilation en C++).

* Commentaires :

Syntaxe C : /* Ceci est un commentaire


il est compris entre /* et */ et peut tenir sur
plusieurs lignes */
Syntaxe C++ : // Ceci est un commentaire. Il se termine à la fin de la ligne

* Déclarations :

En C comme en FORTRAN, la déclaration des variables se fait au début du programme :


void main(void)
{
int a; // déclaration de a
float b; // déclaration de b
a=1; // définition de a
b=2.0f; // définition de b
}

Il y a toujours un point-virgule (;) pour signifier la fin d'une instruction ce qui permet d'éventuellement
mettre autant d'instructions que l'on veut sur une même ligne.

3
En C++, on place les déclarations là où on en a besoin :
void main(void)
{
int a;
a=1;
float b;
b=2.0f;
}

* Notion de bloc :

Tout ce qui est entre les crochets { } est un bloc.


Les variables déclarées dans un bloc sont détruites à la sortie du bloc :
void main (void)
{ // bloc principal
float a=0.f;
a = a + 1; // a=1
int j=0; // a et j sont connus dans le bloc
// principal et le bloc secondaire
{ // bloc secondaire
int i; // i n'est connu que dans le bloc
// secondaire. i=0
i = i + a; // i=2
j = i + 1; // j=3
} // i est détruit, j et a ne sont pas détruits
j = j + 1; // j=4
} // a et j sont détruits ici

* Variables :

Il n'y a pas de déclaration implicite des donnés en C contrairement au FORTRAN (instruction :


implicit).
Les entiers :
short : entier 16 bits (2 octets) signé [-32768,+32767]
unsigned short : entier 16 bits (2 octets) non signé [0,+65535]
long : entier 32 bits (4 octets) signé [-2 147 483 648,+2 147 483 647]
unsigned long : entier 32 bits (4 octets) non signé [0,+4 294 967 295]
int : entier signé short ou long selon le matériel
unsigned int : entier non signé short ou long selon le matériel
Les réels :
float : réel 32 bits (4 octets) signé ±3.4 10 (7 décimales)
±38

double : réel 64 bits (8 octets) signé ±1.7 10 (15 décimales)


±308

long double : réel 80 bits (10 octets) signé ±1.2 10 (19 décimales)
±4932

Les caractères :
char : caractère signé (entier sur 8 bits)
unsigned char : caractère non signé (entier positif sur 8 bits)
Exemple :
int a,b; // déclaration de a et b entiers
a=2; // définition de a
long i,j=1; // i et j entiers longs et j est mis à 1 (i est implicitement mis à 0)
float c=3.f; // c est un réel. La lettre f après une constante flottante indique

4
// une constante de type : float
int m=1,n; // m et n sont des entiers et m est mis à 1
i=j+2l; // l ou L après un entier indique un entier long
i=j+2L; // (idem pour avoir un flottant long : 2.36L)

* Constantes nommées :

L'instruction const placé devant une déclaration permet de faire d'une variable une constante de
manière à être sûr qu'elle ne soit pas modifiée par la suite. Cette notion sera très utile en C++ où la
protection des variables est un point essentiel.
Exemple : const int toto = 10; // toto est une constante entière de valeur 10
toto = 5; // cette ligne provoque une erreur à la compilation
// car toto ne peut pas être modifiée

* Conversion de variables (transtypage):

Une variable d'un type donné peut avoir besoin d'être convertie dans un autre type.
Exemple :
float a = 1.f; // a est un réel
int b = 2; // b est un entier
int c; // c est un entier
c = b + a; // cette ligne provoquera un "warning" à la compilation car on additionne
// un réel et un entier
c = b + int(a); // cela passe à la compilation car on convertit a en entier
c = b + (int)a; // autre écriture possible pour la conversion

* Opérateurs de comparaison :

< : strictement inférieur


> : strictement supérieur
<= : inférieur ou égal
>= : supérieur ou égal
== : égal
!= : n'est pas égal
&& : et
|| : ou
! : non
valeur logique : Faux = 0
Vrai ≠ 0

* Test :

if (condition)
instruction 1
else
instruction 2

Si la condition est satisfaite, alors l'instruction 1 est exécutée, sinon l'instruction 2 est exécutée.
Exemple très classique : résolution de l'équation du second degré
void main (void)
{

5
float a,b,c;
a=1.f; b=2.f; c=3.f;
float delta,rac1,rac2,rac;
delta = b*b – 4.f*a*c;
if (delta >= 0.f)
if (delta == 0.f)
rac = -b/2.f/a;
else
{
rac1 = (-b-sqrt(delta))/2.f/a;
rac2 = (-b+sqrt(delta))/2.f/a;
}
}

* Boucles :
Il y a 2 façons de faire une boucle : soit avec un for soit avec un while (tant que). Le while ne se
jusitifie que si le for n’est pas bien adapté au problème. En général « un for avec un if est un while ».
Dans ce cas le while permet d’éviter l’utilisation de l’instruction break (voir l’exemple qui suit).

Syntaxes :
for ( instruction1 ; condition ; instruction2 ) instruction3
Possibilité de sortie de boucle : dès la rencontre de l'instruction break.
while (expression) instruction ou do instruction while (expression);
Tant que l'expression est satisfaite, exécuter l'instruction. La seconde écriture permet d'avoir au
moins une exécution même si l'expression est fausse au départ.

Exemple : Soit un point de coordonnées (xd,yd) situé dans un rectangle de sommets (0,0) et
(xmax,ymax). On déplace le point de a suivant x et b suivant y. On veut arrêter la boucle lorsque 1000
déplacements ont été effectués ou lorsque le point sort du rectangle.
void main (void)
{
float xd=1.f , yd=1.f , xmax=10.f , ymax=10.f;
float x , y , a=.1f , b=.2f;
// au moins 4 écritures équivalentes :
int i;
x = xd; y = yd;
for ( i=0 ; i<1000 ; i=i+1)
{
x = x + a;
y = y + b;
// le break force à sortir de la boucle
if ( x<0 || x>xmax ) break;
if ( y<0 || y>ymax ) break;
}
// OU
x = xd; y = yd;
for ( int i=0 ; i<1000 ; i++)
{
x += a;
y += b;
if ( x<0 || x>xmax ) break;
if ( y<0 || y>ymax ) break;

6
}
// OU
for ( x=xd, y=yd, int i=0 ; i<1000 && x>0 && x<xmax && y>0 && y<ymax ;
i++ , x+=a , y+=b);
// OU
int i=0;
x=xd; y=yd;
while ( i<1000 && x>0 && x<xmax && y>0 && y<ymax )
{
i ++;
x += a;
y += b;
}
}

* Aiguillages :
Dans le cas où une variable aiguille sur plusieurs cas suivant sa valeur, on peut écrire :
switch (toto) // suivant la valeur de toto
{

case 0 : … ; break ; // si toto=0 faire les instructions et sortir (ordre break)

case 1 : … ; break ; // si toto=1 faire les instructions et sortir (ordre break)

* Opérateurs d'incrémentation :

i += a est équivalent à : i= i+a


i -= a est équivalent à : i= i-a
i *= a est équivalent à : i= i*a
i /= a est équivalent à : i= i/a

i ++ et ++ i sont équivalents à : i = i + 1
Différence entre les deux écritures :
opérateur ++ avant : on incrémente avant la prise de valeur
opérateur ++ après : on incrémente après la prise de valeur
exemple :
for ( i=0 ; i++ <= 10 ; ) cout << i; // i varie de 1 à 11 (à la sortie : i=12)
for ( i=0 ; ++i <= 10 ; ) cout << i; // i varie de 1 à 10 (à la sortie : i=11)

* Les fonctions :

Une fonction possède des paramètres d'entrée fournis entre parenthèses et un paramètre de sortie.
Elle doit être écrite en dehors du programme principal. Chaque fonction doit avoir un prototype. Il sert
à décrire le type des variables en entrée et en sortie. On doit obligatoirement le placer avant l’appel de
la fonction, dans le bloc où se trouve cet appel.

Exemple :
#include <iostream.h> // pour pouvoir faire des sorties à l'écran (voir C++)
void main (void)
{

7
float carre (float); // prototype de la fonction carre
// placé avant l'appel. Ne lance rien à l'exécution.
float x,ca;
cin >> x; // entrée de x au clavier
ca = carre(x); // appel de la fonction carre
cout << "Le carré de " << x << " est égal à " << ca << "\n";
}

float carre(float a)
{
float res;
res = a*a;
return (res);
}

* Ordres de précompilation :

Les ordres de précompilation sont précédés du signe #. Ils sont exécutés avant la phase de
compilation.
#include <toto.h> // inclus le fichier toto.h qui se trouve dans le répertoire racine
#include "toto.h" // inclus le fichier toto.h qui se trouve dans le répertoire courant

Par exemple, pour ne compiler qu'une seule fois une partie d'un programme :
#ifndef TOTO // si la variable TOTO n'est pas définie, on fait la suite
#define TOTO // défini la variable TOTO
......
#endif // fin du ifndef

* Tableaux à une dimension :

Syntaxe : type nom[dimension]


Exemple : int toto[10]; // toto est un tableau de 10 entiers
Attention : les indices vont de 0 à dimension-1 soit pour cet exemple de 0 à 9

Exemple : calcul et stockage des factorielles de 1 à 10


void main (void)
{
long int fact[10]; // tableau de 10 entiers longs
int i;
long int calcule (int); // prototype de la fonction calcule
for ( i=1 ; i<=10 ; i++)
fact[i-1] = factorielle(i);
}
long int factorielle (int nombre)
{
long int res = 1;
int j;
for ( j=1 ; j<=nombre ; j++)
res *= j;
return (res);
}

8
* Tableaux à plusieurs dimensions :

Syntaxe : type nom[dimension 1][dimension 2]...[dimension n]


Exemple : int toto[10][5]; // toto est un tableau de 10x5 entiers
toto[i][j] : contient l'élément de la i ème ligne et j ème colonne
(inversé par rapport au FORTRAN)

* Pointeurs :

A une variable sont associées deux notions : son adresse en mémoire et son contenu. Un pointeur
permet d'accéder à une donnée quelconque (variable, fonction, objet, ...) par l'intermédiaire de son
adresse en mémoire.

Syntaxe : type * nom;


nom : contient l'adresse de la donnée
*nom : représente le contenu à l'adresse de nom
& : affecte l'adresse d'une variable à un pointeur

Exemple :
#include <iostream.h>
void main (void)
{
float x = 1.f; // x est un flottant
float *toto; // toto est un pointeur de flottant
toto = &x; // toto contient l'adresse de x

int a = 10; // a est un entier


int *pointentier = &a; // pointentier est un pointeur d'entier qui contient
// l'adresse de a
cout << a; // affichage de a, c'est-à-dire : 10
cout << *pointentier; // affichage de la variable contenue à
// l'adresse pointentier, c'est-à-dire : 10
cout << pointentier; // affichage de l'adresse de a (fixée à l'exécution)
}

* Passage d’un tableau en paramètre dans une fonction :

Exemple : passage en paramètre d’un tableau de 10 points


{
float t[10]; //
void ssprog(float *); OU void ssprog(float [ ]);
ssprog(t) ;
}
void ssprog(float *a); OU void ssprog(float a[ ]);
{
a[0]= …
}

* Allocation statique et allocation dynamique :

9
Il y a deux manières de déclarer une variable ou un tableau. La manière « classique » consiste à
déclarer un tableau ou une variable avec l’allocation statique. Si on a besoin de contrôler la durée de vie
de la variable ou du tableau on utilise l’allocation dynamique. En C elle est réalisée avec les fonctions
malloc et desalloc. En C++ ce sont les fonctions new et delete. Ces instructions en C et en C++ sont
incompatibles entre elles. Pour cette raison nous n’utilisons ici que l’allocation dynamique en C++.
Voici un résumé des différentes possibilités :

variable variable tableau tableau


alloc. statique alloc. dynamique alloc. statique alloc. dynamique
{ { { {
int a ; int *a ; int a(10] ; int *a ;
a=1 ; a = new int ; a = new int [10] ;
ou delete [ ] a ;
a = new int [1] ;
*a=1 ;
ou
a[0]=1 ;
delete a ;
} } } }

* Les entrées-sorties en C :

Pour des raisons de familiarité avec le C, certains programmeurs utilisent encore les E/S (entrées-
sorties) dans ce langage. Il faut cependant se rendre à l'évidence que les E/S par flots en C++ ont une
garantie beaucoup plus grande au niveau de la sécurité et qu'elles assurent une syntaxe identique
quelque soit le type d'objet à sortir.
Les ordres d'E/S en C nécessitent l'insertion du fichier contenant les prototypes :
#include <stdio.h> // STanDard Input Output

Exemple :
longueur = 10;
printf (" Longueur = %d mètres", longueur);
Affichage à l'écran :
Longueur = 10 mètres

Après le signe %, on indique le type de donnée :


%d entier
%ld entier long
%nd entier sur n caractères
%nld entier long sur n caractères
%[Link] entier entre p et n caractères

%f flottant
%nf flottant sur n caractères (le signe moins(-) et le point (.) sont des caractères)
%[Link] flottant sur n caractères et d décimales

%e flottant avec exposant


%ne flottant avec exposant sur n caractères ( -3.56E-02 possède 9 caractères)
%[Link] flottant avec exposant sur n caractères et d décimales

10
%c caractère
%s chaîne de caractères
%ns chaîne sur n caractères minimum

Les caractères spéciaux :


\a sonnerie
\b recul d'un caractère
\f saut d'une page
\n fin de ligne
\r retour en début de ligne
\t tabulation horizontale
\v tabulation verticale
\\ affiche le caractère : \
\? affiche le caractère : ?
\' affiche le caractère : '
\" affiche le caractère : "

11
LE LANGAGE C++

La programmation en C++ est une Programmation Orientée Objet (POO). Le C++ n'apporte au
vocabulaire du C qu'une dizaine de mots supplémentaires.

Le langage C++ a été créé en 1983 par un universitaire : Bjarne Stroustrup. Il obéit à une norme ANSI.

* Spécificités du C++ :

- Surdéfinition des fonctions :


Contrairement à certains langages, le C++ distingue les fonctions pas seulement par leur nom mais aussi
par le nombre et le type de paramètres d'entrée et de sortie.
Par exemple, ces 4 fonctions sont 4 fonctions bien distinctes :
void calcule ( float, float);
void calcule ( float, int);
void calcule ( float );
int calcule ( float);

- Fonctions en ligne :
Il est possible, au lieu d'écrire un prototype et plus loin la fonction, d'écrire directement la fonction
en ligne à l'endroit où se trouve le prototype à l'aide du mot-clé inline de façon à améliorer le temps
d'exécution.
Par exemple :
inline float carre (float a) { return (a*a);}

* Passage de données :

- Passage par valeur :


Exemple :
#include <iostream.h>
void main (void)
{
float x = 1.f; // x est un flottant
void calcule (float); // prototype de la fonction
cout << x; // affichage de x
calcule (x); // appel de la fonction
cout << x; // affichage de x
}
void calcule (float a)
{
a = 2;
}
affichage avant l'appel de la fonction : 1
affichage après l'appel de la fonction : 1
Il n'y a pas d'effet de bord, la fonction calcule travaille sur la variable a et pas sur la variable x. La
valeur de x n’est pas changée par l’appel de la fonction.

- Passage par adresse :


Exemple :

12
#include <iostream.h>
void main (void)
{
float x = 1.f; // x est un flottant
void calcule (float *); // prototype de la fonction
cout << x; // affichage de x
calcule (&x); // appel dela fonction
cout << x; // affichage de x
}
void calcule (float *a)
{
*a = 2;
}
affichage avant l'appel de la fonction : 1
affichage après l'appel de la fonction : 2
Il y a un effet de bord, la variable x est modifiée au retour par l’intermédiaire de son adresse.

- Passage par référence :


Exemple :
#include <iostream.h>
void main (void)
{
float x = 1.f; // x est un flottant
void calcule (float &); // prototype de la fonction
cout << x; // affichage de x
calcule (x); // appel dela fonction
cout << x; // affichage de x
}
void calcule (float &a)
{
a = 2;
}
affichage avant l'appel de la fonction : 1
affichage après l'appel de la fonction : 2
Il y a un effet de bord comme dans le passage par adresse. Par contre la syntaxe est cette fois-ci
beaucoup moins lourde. Elle est identique au passage par valeur avec un & en plus dans le prototype.

* Notions de classe et d'objet :

L'idée de base est que des langages du type FORTRAN ou C permettent de manipuler et de déclarer
uniquement des nombres ou des caractères. La Programmation Orientée Objet va plus loin et permet de
manipuler des nombres, des caractères mais aussi des objets quelconques.
Qu'est-ce qu'une classe ?
Une classe définit un ensemble d'objets.
Qu'est-ce qu'un objet ?
C'est n'importe quoi dans les limites de l'imagination du programmeur.

* La classe, le constructeur, le destructeur :

On construit une classe pour les utilisateurs de cette classe.


La structure et l'organisation des fichiers est la suivante :

13
Fichier ma_classe.h :
# ifndef MA_CLASSE
# define MA_CLASSE
class ma_classe
{
private :
... // données, informations, objets
...
public :
int tourner (void);
... // prototypes des méthodes qui manipulent,
... // modifient les objets, les données
...
};
# endif

Fichier ma_classe.cpp :

#include "ma_classe.h"
int ma_classe::tourner (void) // méthode tourner
{
int a;
...
...
return (a);
}

Fichier mon_programme_principal.cpp :

#include "ma_classe.h"
void main(void)
{
ma_classe toto;
[Link]( );
}

Une classe possède une zone de données privées (private) qui ne sont accessibles que par la classe elle-
même ce qui assure la protection totale de ces données vis-à-vis des autres classes et des utilisateurs
de la classe. Ceux-ci n'ont accès qu'à la partie publique (public) de la classe.

Exemple : on veut écrire une classe appelée : homme qui permet de définir et faire évoluer un homme.
Fichier homme.h :
# ifndef HOMME
# define HOMME
class homme
{
private :
int age; // age de l'homme en années
float taille; // taille de l'homme en mètres
public :

14
homme ( int, float); // CONSTRUCTEUR. Il se trouve obligatoirement
// en public.
~homme (void); // DESTRUCTEUR.
void vieillir (void); // méthode qui fait vieillir d'un an.
};
# endif

Fichier [Link] :

#include "homme.h"
homme::homme (int i, float a)
{
age = i;
taille = a;
}

homme::~homme (void)
{}

void homme::vieillir (void)


{
age += 1;
}

Fichier mon_programme_principal.cpp :

#include "homme.h"
void main(void)
{
homme robert(20,1.7); // on lance le constructeur
[Link]( ); // on lance la méthode vieillir
} // la fin du bloc lance le destructeur

Du fait de la possibilité de la surdéfinition des fonctions, il peut et il est même conseillé d'avoir
plusieurs constructeurs.

* Les paramètres par défaut :


On peut donner des valeurs par défaut aux paramètres. Par exemple au lieu d’écrire :
class homme
{ private :

public :
homme ( void); // CONSTRUCTEUR
homme ( int, float); // CONSTRUCTEUR

};
homme::homme (void)
{
age = 20;
taille = 1.7f;
}

15
homme::homme (int i, float a)
{
age = i;
taille = a;
}
on pourra écrire :
class homme
{ private :

public :
homme ( int = 20, float = 1.7f); // CONSTRUCTEUR

};

homme::homme (int i, float a)


{
age = i;
taille = a;
}
Dans ce cas on pourra utiliser la classe ainsi :
homme toto(18,1.8f),titi ; // toto a 18 ans et titi a 20 ans
On peut aussi ne mettre que quelques paramètres pas défaut :
homme ( int, float = 1.7f);
Dans ce cas, l’écriture : homme toto(20) veut dire que toto a 20 ans et fait 1m70.

* Les variables statiques :


Si on veut par exemple compter le nombre d’hommes créé, il faut utiliser un compteur statique qui sera
utilisé par tous les objets de la classe :
class homme
{
private :
static int nombre; // nombre d’hommes

public :

}
Dans le fichier [Link] on initialise le compteur et dans le constructeur et le destructeur on
l’incrémente et le décrémente :
#include "homme.h"
int homme ::nombre=0 ;
homme::homme (int i, float a)
{
nombre += 1 ;

}

* L'allocation dynamique et le constructeur de recopie :

L'allocation dynamique est réalisée en C++ avec les mots new et delete.
Elle permet de manipuler des pointeurs d'objets (utile entre autre pour définir un tableau d'objets).
Par exemple, pour manipuler un pointeur d'homme et contrôler sa durée de vie indépendamment du

16
bloc:

homme *robert; // robert est un pointeur d'homme


robert = new homme (20,1.7); // on lance le constructeur
...
...
delete robert; // on lance le destructeur

Ou alors pour manipuler un tableau de 10 hommes :


homme *tabhomme; // robert est un pointeur d'homme
tabhomme = new homme [10] ; // on lance le constructeur pour 10 hommes
...
...
delete [ ] tabhomme; // on lance le destructeur
Attention : l’écriture tabhomme = new homme [10] (20,1.7); ne fonctionne pas avec les versions
actuelles des compilateurs.

Autre exemple :
int *toto; // déclaration du pointeur d'entiers
toto = new int; // demande d'allocation mémoire pour une variable
// dynamique de type int
*toto = 10;
delete toto;

float *pt;
pt = new float[10];
for (int i=0 ; i<10 ; i++)
{
*(pt+i) = i * 2;
cout << *(pt+i);
}
delete [ ] pt;

Important : lorsqu'on transmet un objet par valeur en paramètre d'une fonction, le C++ lance un
constructeur appelé constructeur de recopie qui existe implicitement. Si l'objet contient des données
sous forme dynamique (tableaux), il va y avoir une mauvaise recopie. Il est dans ce cas indispensable
d'écrire soi-même le constructeur de recopie.
Par exemple, si la classe homme contient un tableau d'entiers (tableau de notes), il est indispensable
d'écrire un constructeur de recopie :
class homme
{
private :
...
int *notes; // tableau de notes
public :
homme (int , float); // constructeur
homme (const homme&); // constructeur de recopie
...
};

homme::homme (int i, float a)


{

17
age = i;
taille = a;
notes = new int [10];
for (int j=0; j<10 ;j++) notes[j] = 10;
}

homme::homme (const homme& toto)


{
age = [Link];
taille = [Link];
notes = new int [10];
for (int j=0; j<10 ;j++) notes[j] = [Link][j];
}

Equivalence d’écriture :
Si on a un pointeur sur un objet :
homme *toto ;
alors au lieu d’écrire :
(*toto).vieillir( ) ;
on pourra écrire :
toto -> vieillir( ) ;

* Les fonctions amies :

Il peut se poser dans certains cas un problème de symétrie. Par exemple, si on possède une méthode
appelée mariage :
void mariage (homme);
L'appel de cette méthode peut être :
[Link] (berthe);
Mais l'appel suivant conduit au même résultat :
[Link] (robert);
Le problème de manque de symétrie vient du fait qu'une méthode est obligatoirement appliquée à un
objet. On pourrait contourner ceci en écrivant une fonction :
void mariage (homme,homme);
L'inconvénient est que la fonction n'a pas accès aux données placées en private (seules les méthodes y
ont accès).
Il suffit de placer devant la fonction le mot friend pour en faire un fonction amie de la classe et ainsi
elle aura accès à toutes les données de la classe :
friend void mariage (homme,homme);
Remarque : une fonction peut être amie de plusieurs classes.

* La redéfinition des opérateurs :

Les différents opérateurs existant en C peuvent être redéfinis en C++.


Par exemple, redéfinition de l'opérateur d'addition dans une classe complexe :
class complexe
{
private :
float reel;
float imag;

18
public :
complexe (float =0.f, float =0.f);
friend complexe operator + (complexe, complexe);
complexe &operator ++ (void) ;
};

complexe::complexe (float a, float b)


{
reel = a;
imag = b;
}

complexe operator + (complexe z1, complexe z2)


{
complexe res;
[Link] = [Link] + [Link];
[Link] = [Link] + [Link];
return (res);
}

complexe &complex ::operator ++ (void)


{
reel = reel + 1;
return (*this);
}
Important : le mot-clé this désigne l’adresse de l’objet lui-même. Ici, il faut retourner l’objet *this et
pas son adresse.
void main (void)
{
complexe a(1.0f,2.0f),b(0.f,-5.f),c;
c = a + b;
c++ ;
}

Liste des opérateurs redéfinissables :


( ), [ ], ->, +, -, ++, --, !, ~, &, new, delete, *, /, %, <<, >>, <, >, >=, <=, ==, !=, ||, &&, +=, -=, *=, /=, %=

Exemple de redéfinition de l’opérateur [ ] :


int & operator [ ] (int) ;
int &tab::operator [ ] (int i)
{
if ( (i>=0)&&(i<nmax) ) return ( t[i] ) ;
else cout << …
}

* Les patrons de classe :

Un patron de classe (ou classe paramétrée) permet d'écrire une classe pour un type d'objets inconnus.
Par exemple une classe homme où on ne connaît pas la nature du tableau de notes (int, float, ...):
template <class toto> class homme

19
{
private :
toto *notes;
int age;
...
public :
...
void vieillir(void);
};

template <class toto> void homme <toto>::vieillir (void)


{
age += 1;
}

void main (void)


{
homme <int> robert; // robert a un tableau d'entiers
homme <complexe> albert; // albert a un tableau de complexes
...
}

* L'héritage (la POO) :

Manipuler et créer des objets, c'est faire de la Programmation Objet. L'Orientation Objet consiste à
créer une hiérarchie dans les classes avec une ou plusieurs classes de base et des classes dérivées qui
héritent de ces classes de base. L'intérêt est d'éviter de réécrire ce qui a déjà été écrit.

Par exemple, la classe base décrit une particule :


class particule
{
private :
float masse, charge,x,y;
public :
particule (float,float,float,float);
void deplace (void);
};

La classe dérivée décrit une particule possédant une couleur :


class particulecoloree : public particule
{
private :
int couleur; // le reste est déjà écrit dans particule
public :
particulecoloree (float,float,float,float);
};

particulecoloree ::particulecoloree (float m,float c,float a,float b, float co)


: particule (m,c,a,b)
{
couleur = co;
}

20
On n'a pas besoin de redéfinir toutes les caractéristiques d'une particule colorée et comment la
déplacer car elle hérite de toutes les propriétés de particule.

void main (void)


{
particule electron;
particulecoloree quark;
[Link] ( );
[Link] ( );
}

Remarque : Une classe dérivée a accès à toutes les méthodes publiques de la classe de base mais pas
aux méthodes privées. Si on veut que des données ou des méthodes soient accessibles aux classes
dérivées tout en restant inaccessibles aux autres classes et aux utilisateurs, on les précède non pas du
mot private mais du mot protected.
class particule
{
protected :
float x,y; // accessible par la classe particule et
// les classe dérivées
private :
float masse, charge; // accessible par la classe particule uniquement
public :
...
}

Héritage privé :
Si au lieu de l’héritage public :
class particulecoloree : public particule
on écrit l’héritage privé :
class particulecoloree : private particule
alors la classe dérivée n’hérite que des données de la classe de base et pas des méthodes. Ces
méthodes restent applicables aux objets de la classe de base mais pas aux objets de la classe dérivée.
Important : pour savoir si on doit faire ou pas de l’héritage avec une classe, il suffit de se dire que si la
classe contient la classe de base, alors ce n’est pas un héritage. Par contre si elle est la classe de base,
alors c’est de l’héritage.

* Méthodes virtuelles :
Quand on utilise de pointeurs sur des objets dérivant d’une classe de base, l’utilisation du mot-clé
virtual peut éviter certains problèmes. Par exemple si on déclare dans la classe de base particule la
méthode affiche en virtual :
virtual void affiche (void) ;
void particule::affiche(void)
{ cout << "Coordonnes" << x << " " << y << "\n " ; }
et si dans la classe particule coloree on déclare aussi une méthode affiche :
void affiche (void) ;
void particulecoloree::affiche(void)
{ cout << "Coordonnes" << x << " " << y << "\n " ;
cout << "Couleur" << couleur << "\n " ; }
alors on pourra écrire si adrpart est un pointeur de particule et adrpartcol est un pointeur de particule

21
colorée :
adrpart -> affiche( ) ; // affiche les coordonnées de la particule
adrpartcol -> affiche( ) ; // affiche les coordonnées et la couleur de la particule colorée
ce qui fonctionne même sans déclarer affiche en méthode virtuelle mais si on écrit :
adrpart = adrpartcol ;
adrpart -> affiche( ) ; // affiche les coordonnées et la couleur de la particule colorée
cela fonctionne car l’appel à la méthode est résolu au moment de l’exécution (c’est ce qu’on appelle le
typage dynamique) alors que sans le mot-clé virtual il ne serait fait appel qu’à la méthode affiche de la
classe particule.

* Classes virtuelles :
Quand une classe dérivée dérive de 2 classes qui elles-mêmes dérivent d’une classe de base commune
alors la classe dérivée contient 2 fois la classe de base. Pour lever toute ambiguïté, il faut déclarer la
classe de base virtuelle dans la déclaration de la classe dérivée :
Class derivee : virtual base

* Les flots d'entrée-sortie en C++ :

Le fichier à inclure pour l'utilisation des flux d'E/S est le suivant :


#include <iostream.h> // Input Output STREAM

La sortie est gérée par l'instruction cout :


a = 2;
cout << a; // l'opérateur << veut dire : "vers"
// la variable "a" est dirigée vers la sortie
cout << "la longueur est de" << a << " mètres \n";

Redéfinition de l'opérateur de sortie pour un type utilisateur :


// exemple de sortie d'un nombre complexe
ostream& operator << (ostream& s, complex z)
{
return s << "( " << [Link]( ) << "," << [Link]( ) << " )";
}
L'utilisation sera la suivante :
complexe z(2,-3);
cout << "z = " << z << "\n";
Affichage : z = (2,-3)
De façon similaire, l'entrée est gérée par l'instruction cin et l'opérateur >> qui signifie "à partir de".
int a;
cin >> a; // entrée de a au clavier

Références :
Langage C et Langage C++, Cours de Michel DUBUIT, 1997, CIRIL, Nancy.
Le langage C++, Bjarne STROUSTRUP, Addison-Wesley.
Exercices en langage C++, Claude DELANNOY, Eyrolles.

22
Exercices d'application

1 - Utilisation de l'éditeur et du compilateur.


Ecrire un programme affichant un message à l’écran dans une fenêtre MS-DOS.

2 - Boucles.
Ecrire un programme affichant tous les entiers de 1 à n (n sera demandé par le programme) puis afficher la somme
de ces n entiers (ne pas utiliser un tableau).

3 - Surcharge de procédure (fonction).


Ecrire un programme calculant la distance entre un point dans le plan (x,y) et l’origine en utilisant une procédure
(fonction) que vous appellerez : distance. Une fois que ce programme fonctionne, ajouter une procédure qui a le
même nom et qui calcule la distance entre deux points quelconques dans le plan. Ce programme ne peut fonctionner
qu’en C++ (extension des fichiers en .cpp) mais pas en C (extension en .c). Ne pas oublier les prototypes.

4 - Tableaux.
Ecrire un programme qui vous demande d’entrer des notes entières au clavier. Entrer 99 signifie que la liste est
terminée. Stockez ces notes dans un tableau puis calculez et affichez la moyenne.
- Pointeurs.
Reprendre le même programme en utilisant un pointeur pour manipuler les données du tableau.

5 - Passage d’un tableau.


Ecrire un programme lisant 10 notes au clavier (ne pas utiliser l’instruction new), puis modifier ces notes dans une
procédure (fonction) qui retranche une constante à ces notes. Cet exercice permet d’étudier le passage d’un tableau
en paramètres dans une fonction. Pensez qu’une note négative ne doit pas exister.

6 - Passage d’une variable.


Ecrire un programme passant une variable à une fonction par valeur, par adresse et par référence. Afficher la valeur
de la variable avant et après l’appel des trois fonctions..

7 - Classe.
Ecrire une classe d’objets : homme, permettant de créer, de ‘détruire’, de faire vieillir, grandir, déplacer ,… un ou
plusieurs hommes en même temps. A vous d’imaginer et d’écrire ….

Rappel : Faire 3 fichiers :


- Un fichier .h qui contient la déclaration de la classe (dans Visual C++, quand vous choisissez dans le menu File,
l’option New avec le signet Files, choisir C/C++ Header File au lieu de C++ Source File et vérifiez que la case Add
to project n’est pas cochée).
- Un fichier .cpp qui contient la description des procédures, avec en en-tête :
#include votre fichier.h
- Un fichier .cpp qui contient le programme principal avec en en-tête :
# include votre fichier.h

8 - Classe.
a - Construire une classe nommée : etudiant. Un étudiant sera défini par son âge et sa filière (codée à l’aide d’un
entier : 1=1ère année, 2=2ème année, 3=licence , …). La classe devra contenir un constructeur avec des paramètres par
défaut et un destructeur. Ecrire un programme testant cette question.

b - Ajouter à la classe etudiant des méthodes permettant de connaître l’âge et la filière de l’étudiant. Ajouter en
private une méthode permettant de vieillir l’étudiant d’un an et en public deux autres permettant de le faire passer
dans l’année supérieure ou de le faire redoubler et utilisant la méthode vieillir. Ecrire un programme testant cette
question.

c - Ajouter à la définition de l’étudiant la liste de ses 10 notes sous forme d’un tableau de flottants. N’oubliez rien :
le destructeur, la remise à zéro des notes pour le passage dans la filière supérieure , … Ecrire des méthodes
manipulant ce tableau (entrée de notes, sortie de notes, modification, …) dont une au moins aura en paramètre un
tableau de flottants et qui permettra de remplir le tableau de notes depuis un tableau du programme principal. Ecrire
un programme testant cette question.

d -Ajouter une autre méthode de passage à l’année supérieure en testant si la moyenne est supérieure à 10. Ecrire un
programme testant cette question.

23
e -Améliorer cette classe en ajoutant d’autres méthodes de votre choix …..

9 - Fonction amie.
a - Construire une classe nommée : point. Un point sera défini par deux coordonnées réelles. La classe devra
contenir un constructeur avec des paramètres par défaut et un destructeur.
Ecrire une méthode appelée : idem qui admet un point en paramètre et qui compare si le point courant est le même
que celui fourni en paramètre. Ecrire un programme testant cette question.

b - Ajouter à la classe point une méthode appelée : dist permettant de calculer la distance entre le point et l’origine.
Ecrire une fonction amie de la classe point appelée : meme_point qui fera la même chose que la méthode idem mais
avec la symétrie de l’appel en plus.
Ecrire une fonction amie de la classe point appelée : distance calculant al distance entre deux points. Ecrire un
programme testant cette question.

c - Construire une classe nommée : cercle. Un cercle est défini par le centre (un point de la classe précédente) et le
rayon. Ajouter des fonctions amies de la classe cercle qui comparent si le centre est le même, si le cercle est le
même, qui calcule la distance entre deux centres de deux cercles et si un cercle est inscrit dans un autre. Ecrire un
programme testant cette question.

d - Améliorer ces classes en ajoutant d’autres méthodes de votre choix …..

10 - Redéfinition des opérateurs.


a- Ecrire une classe nommée : vecteur où un vecteur est défini par ses 3 coordonnées x,y et z. Redéfinir les
opérateurs d’addition, de soustraction, de multiplication (produit scalaire) et d’autres opérateurs à votre convenance.
Ecrire un programme testant cette question.

b- Ecrire une classe nommée : complexe que vous utiliserez pour calculer l’impédance complexe dans un circuit
RLC série ou parallèle. Ecrire un programme testant cette question.

11 - Héritage de classe.
a- Ecrire une classe nommée particule ayant en private la position x d’une particule et sa masse m. En plus d’un ou
plusieurs constructeurs, faire une méthode qui déplace la particule sous l’action d’une force constante F passée en
paramètre. Pour cela, utiliser la loi du mouvement :
F 2
x= t +x 0
m
où x0 est la position précédente de la particule et t le temps. Ecrire un programme testant cette question.

b- Ecrire une classe particule_chargee (sans accent) qui hérite de la classe particule et qui ajoute comme donnée la
charge q de la particule. Ecrire une méthode permettant de retourner le rapport q/m (sans modifier la structure de la
classe particule). Ecrire un programme testant cette question.

c- Même question que précédemment en mettant la position et la masse de la particule non pas en private mais en
protected. Ecrire un programme testant cette question.

d- Ajouter des méthodes de votre choix dans la classe de base et la classe dérivée.

24

Vous aimerez peut-être aussi