Anda di halaman 1dari 19

C++

1 Principes
Objet : propriétés + méthodes
Encapsulation : les actions sur les propriétés se font au travers des méthodes
Message : on dit que l’on envoie un message à un objet lorsque l’on utilise l’une de ses méthodes.
Classe : correspond au type dans les langages classiques. Les objets sont des instances d’une classe
Héritage : possibilité de définir une classe à partir d’une ou plusieurs autres classes
Polymorphisme : possibilité pour un objet d’une classe héritée de prendre la place d’un objet d’une
classe mère

Avantages par rapport aux autres langages :

Modularité : on peut réutiliser des classes. Chaque classe peut être compilée et testée séparément
Sécurité : on peut mettre à disposition des classes en prenant soin de protéger les données sensibles
Extensibilité : grâce à la possibilité d’utiliser des objets de classes prédéfinies et de surdéfinir les
opérateurs, on étend le langage à la manipulation d’objets nouveaux.

2 Modifications par rapport au C

2.1 Déclarations
Elles peuvent se faire à tout instant. Ceci est indispensable en C++ dans la mesure où un objet est crée
lors de sa déclaration et qu’une méthode particulière appelée constructeur est automatiquement lancée lors de la
création d’un objet.

2.2 Surdéfinition
On peut définir plusieurs fois la même fonction si on peut les différencier par les paramètres (type et/ou nombre).
void sosie (int);
void sosie (float);
int n=5 ; float f;
sosie (n); // appelle la première fct
sosie (f); // appelle la seconde fct

2.3 Commentaires
Ils sont introduits par // et se terminent avec la ligne. /* et */ fonctionnent comme en C.

2.4 Clavier / écran

On utilise des flots sous la forme :


#include <iostream>
std::cout<<‘’ valeur de x : ‘’<<x<<‘’ voilà !’’<<endl;
std::cin>>n>>p // saisie de n puis de p

std::cout<<x sortie de x selon son type


std::cout<<hex<<x sortie de x en hexa
std::cout<<dec<<x sortie de x en décimal
std::cout<<oct<<x sortie de x en octal

std::cin>>x lecture d'un entier dans x


std::cin>>chaine lecture d'une chaîne de caractères
la lecture par cin s’arrête sur espace \t \n \r (retour chariot)

C++ M. DALMAU, IUT de BAYONNE


1
Remarque : si l'on met en début du fichier .cpp la directive suivante :
use namespace std;
On n'a plus besoin de mettre std:: devant cin et cout.

3 Classes

3.1 Déclaration
Entête de la classe placée en général dans un fichier .h ou .hpp qui sera inclus dans tout fichier utilisant cette
classe :

class Point; // nom de la classe


{
private : // parties cachées non accessibles de l’extérieur
int x;
int y;
public : // parties visibles de l’extérieur
void placer(int,int);
void deplacer(int,int);
protected : // partie visible seulement dans les classes dérivées
int fct(int);
};

Définition de la classe placée en général dans un fichier .C ou .cpp :

#include ‘’Point.h’’ // insertion du fichier d’en-tête


void Point::placer(int a, int b)
{ corps de la méthode }
void Point::deplacer(int a, int b)
{ corps de la méthode }
int Point::fct(int x)
{ corps de la méthode }

3.2 Utilisation

3.2.1 Utilisation directe


#include ‘Point.h’’ // insertion du fichier d’en-tête

int main(char ** argv, int argc) {


Point a; // création d’une instance d’objet point appelé a
a.placer(4,5); // appel d’une méthode de a
Point b; // création d’une instance d’objet point appelé b
b=a; // affectation d’un objet à un autre
// par contre a.x=0 est impossible car x est privé de même a.fct(3) est impossible car fct est protégé
}

3.2.2 Utilisation avec des pointeurs


new et delete sont utilisés pour allouer et libérer la mémoire associée à un pointeur :

int *ptr; char *str;


ptr = new int; str = new char[100]; // en C on aurait eu : str = (char *) malloc(100);
delete ptr; delete []str; // pour désallouer la mémoire

On peut alors écrire :


#include ‘’ Point.h’’ // insertion du fichier d’en-tête

C++ M. DALMAU, IUT de BAYONNE


2
int main(char ** argv, int argc) {
Point *ptr; // déclaration d’un pointeur vers des objets de classe point
ptr = new Point; // création d’une instance d’objet de classe point pointée par ptr
ptr -> placer(2,5); // appel d’une méthode de l’objet pointé par ptr
Point a // déclaration d’un objet de classe point
a=*ptr; // affectation d’un objet à un autre
delete ptr; // destruction de l’objet pointé par ptr
}

EXEMPLE OBJET CHAINE DE CARACTERES

On va le réaliser avec un tableau de caractères (limité à 255 caractères) et le doter des méthodes suivantes :
affiche qui va afficher la chaîne de caractères
longueur qui retournera la longueur de la chaîne
car qui permettra de retrouver un caractère de rang donné dans la chaîne
majusc qui met en majuscule la première lettre de la chaîne
init_chaine qui place un contenu dans la chaîne

FICHIER CHAINE.HPP
class Chaine // chaîne de caractères avec tableau
{
protected:
char mot[255]; // tableau de caractères accessible dans les classes dérivées
private:
int lg; // longueur de la chaîne inaccessible
public:
void init_chaine(char *); // initialisation du contenu
void affiche(); // affichage de la chaîne
int longueur(); // retourne la longueur de la chaîne
char car(int); // retourne le caractère placé dans la position donnée en paramètre
void majusc(); // met la première lettre de la chaîne en majuscule
};

FICHIER CHAINE.CPP
#include <iostream> // pour utiliser cout
#include <string.h> // pour utiliser strlen ...
#include <ctype.h> // pour utiliser toupper

#include ‘’Chaine.hpp’’ // fichier entête de classe

void Chaine::init_chaine(char *motini) { // initialisation du contenu


lg = strlen(motini);
strcpy(mot , motini);
}

void Chaine::affiche() {
std::cout<<mot; // affichage de la chaîne
}

int Chaine::longueur() {
return lg; // c’est tout
}

char Chaine::car(int rang) { // retourne le caractère placé dans la position donnée en paramètre ou le dernier
if (rang < lg) return mot[rang];
else return mot[lg-1];
}

C++ M. DALMAU, IUT de BAYONNE


3
void Chaine::majusc() { // met le 1er car de la chaîne en majuscule
if ((mot[0] >= ‘a’) && (mot[0] <= ‘z’)) mot[0] = toupper(mot[0]);
}

3.3 Méthodes et fonctions

Syntaxe d’écriture d’une fonction :

en C en C++

int f (a,b) int f (int a, char b)


int a; {
char b; corps de la fonction
{ corps de la fonction }
}

Toute fonction doit être déclarée en C++. Cette déclaration se fait par un prototype de la forme :
int f (int , char);
Pour une méthode la syntaxe est la même en préfixant le nom de la fonction par celui de la classe à laquelle elle
appartient.

3.3.1 Référence
3.3.1.1 Le passage de paramètre par référence se fait par :
void echange (int & , int &); // déclaration de prototype

echange (a,b); // appel de la fonction ( a et b sont des entiers )

void echange (int &x, int &y) { // écriture de la fonction


int z;
z=x; x=y; y=z; // on n’a plus a manipuler des pointeurs comme en C
}

1°) Notation : Elle est notée par un nom de type ou de classe suivi du symbole &.

ATTENTION il ne faut pas confondre ce symbole & avec celui utilisé pour obtenir une adresse ainsi :
int & x veut dire que x est une référence à un entier
tandis que a = &x veut dire que a reçoit l’adresse de x

2°) Utilisation : En paramètre pour que la fonction ou la méthode puisse accéder au paramètre (passage par
adresse dans d’autres langages)

3.3.1.2 En retour : la fonction ou la méthode retourne une référence à une variable. Cette fonction ou méthode
pourra donc prendre place partout où l’on pourrait mettre une variable. On pourra avec une fonction f définie par
: int & f(char) écrire f(‘q’) = 0 qui mettra donc à 0 la variable à laquelle f fait référence en retour.

ATTENTION : on ne peut faire référence qu’à quelque chose qui existe. Ainsi une fonction g écrite comme suit :
int & g(int x) {
int z;
z=x+1;
return z;
}
n’a aucun sens puisque la valeur retournée par g est une référence à z qui est locale à g et n’existe donc plus dès
que g est terminée !

3.3.2 Valeurs par défaut de paramètres


fct (int, int=12) // par défaut le second paramètre sera 12
fct (int, int &=n) // par défaut le second paramètre sera n (passé par référence)

C++ M. DALMAU, IUT de BAYONNE


4
fct (int, int *=&n) // par défaut le second paramètre sera l’adresse de n
Attention les paramètres par défaut doivent toujours être les derniers de la liste.

4 Construction et destruction d’objets

4.1 Constructeur
C’est une méthode appelée lors de la création de l’objet. Elle porte le même nom que la classe.
Point (int, int); // prototype du constructeur

Point:: Point (int a, int b) { // le constructeur lui même


x=a; y=b;
}

Dans ce cas, lorsque les objets sont crées, le constructeur est appelé. Il faut faire : Point a(1,3);

On peut, bien entendu, doter le constructeur de valeurs de paramètres par défaut.


par exemple : Point (int=0, int=0);
Permettra de déclarer un objet b par : Point b; qui sera équivalent à Point b(0,0);
De même, Point c(4); sera équivalent à Point c(4,0);

ATTENTION : le constructeur doit être public. Il sera appelé à chaque création d’objet sauf si cette création est
faite à partir d’un autre objet par : Point a=b; dans ce cas il faudra prévoir un constructeur spécial (constructeur
par recopie).

Appel : Le constructeur sera appelé lors de chaque création d’un objet nouveau c’est à dire lors d’une déclaration
ou d’une utilisation de new sur un pointeur vers un objet.

EXEMPLE OBJET CHAINE DE CARACTERES

Ajout d’un constructeur

FICHIER CHAINE.HPP

// On ajoute l’en-tête du constructeur


public :
Chaine (char *); // constructeur avec initialisation du contenu

FICHIER CHAINE.CPP

// On ajoute le corps du constructeur


Chaine::Chaine (char *motini) { // constructeur avec initialisation
init_chaine(motini);
}

4.2 Destructeur
C’est une méthode appelée lors de la destruction de l’objet. Elle porte le même nom que la classe,
précédé du symbole ~
~Point(); // prototype du destructeur

Point::~Point() // le destructeur lui même


{ corps du destructeur }

Le destructeur est en général utilisé si certaines actions du constructeur doivent être annulées (affichages,
ouverture de fichiers, allocation dynamique de mémoire, etc.).
Il sera appelé à chaque destruction d’objet même si le constructeur ne l’a pas été.

C++ M. DALMAU, IUT de BAYONNE


5
Appel : Le destructeur sera appelé lors de chaque destruction d’un objet c’est à dire en sortie de bloc ou de
fonction ainsi qu’en fin de programme. Il sera aussi appelé lors de l’utilisation de delete sur un pointeur vers un
objet.

4.3 Construction et destruction d’objets allouant dynamiquement de la mémoire


Lorsqu’un objet est doté d’un constructeur qui alloue de la mémoire et l’initialise on ne pourra pas faire
d’affectation d’un objet à un autre car on n’aurait que la recopie du pointeur vers la même zone et non vers une
zone copie. Il faudra dans ce cas redéfinir l’opérateur d’affectation (=) (voir plus loin).

EXEMPLE OBJET CHAINE DE CARACTERES

Modification de la réalisation en utilisant un pointeur sur des caractères au lieu d’un tableau.
Il va falloir faire de l’allocation dynamique de mémoire dans le constructeur et ajouter un destructeur pour libérer
cette mémoire

FICHIER CHAINE.HPP
class Chaine // chaîne de caractères avec pointeur et allocation dynamique de mémoire
{
protected:
char *ptr; // pointeur vers la chaîne
private:
int lg; // longueur de la chaîne
public:
Chaine (char *); // constructeur avec initialisation du contenu et réservation de mémoire
~chaine(); // destructeur pour libérer la place allouée
void init_chaine(char *); // modification du contenu dans la chaîne
void affiche(); // affichage de la chaîne
int longueur(); // retourne la longueur de la chaîne
char car(int); // retourne le caractère placé dans la position donnée en paramètre
void majusc(); // met la première lettre de la chaîne en majuscule
};

FICHIER CHAINE.CPP
#include <iostream> // pour utiliser cout
#include <string.h> // pour utiliser strlen ...
#include <ctype.h> // pour utiliser toupper

#include ‘’Chaine.hpp’’ // fichier entête de classe

Chaine::Chaine char *motini) { // constructeur avec initialisation de la chaîne


ptr = new char[strlen(motini)+1]; // allocation de mémoire (+1 pour \0)
lg = strlen(motini); // longueur de la chaîne créée
strcpy(ptr , motini);
}

Chaine::~Chaine () { // destructeur
delete [] ptr; // libération de la mémoire
// remarque : avec certains compilateurs C++ il faudra écrire : delete [lg+1] ptr;
}

void Chaine::init_chaine(char *motini) {


delete [] ptr; // libération de la mémoire
ptr = new char[strlen(motini)+1]; // allocation de mémoire (+1 pour \0)
lg = strlen(motini); // longueur de la chaîne créée
strcpy(ptr , motini);
}

C++ M. DALMAU, IUT de BAYONNE


6
void Chaine::affiche() {
std::cout<<ptr; // affichage de la chaîne
}

int Chaine::longueur() {
return lg; // c’est tout
}

char Chaine::car(int rang) { // retourne le caractère placé dans la position donnée en paramètre ou le dernier
if (rang < lg) return *(ptr + rang);
else return *(ptr + lg - 1);
}

void Chaine::majusc() { // met le 1er car de la chaîne en majuscule


if ((*ptr >= ‘a’) && (*ptr <= ‘z’)) *ptr = toupper(*ptr);
}

5 Surdéfinition de méthodes
On peut donner le même nom à plusieurs méthodes à condition qu’elles diffèrent par les paramètres :
Point::Point (); // constructeur sans paramètre
Point::Point (int,int); // constructeur à 2 paramètres

ATTENTION : Il faut éviter les ambiguïtés comme par exemple :


Point::Point (int=0,int=0); // constructeur à 2 paramètres avec valeurs par défaut
et Point::Point (); // constructeur sans paramètre
Dans une telle situation une instruction comme Point a; devient ambiguë puisque on peut utiliser le constructeur
sans paramètres ou l’autre avec les valeurs par défaut (0 et 0).

EXEMPLE OBJET CHAINE DE CARACTERES

Addition d’un constructeur permettant d’initialiser la chaîne avec un caractère répété

Dans CHAINE.HPP on ajoute :

Chaine(int = 0, char=‘ ‘); // constructeur avec initialisation par un caractère répété

Dans CHAINE.CPP on ajoute :

Chaine::Chaine (int longueur, char c) { // constructeur avec initialisation par un caractère répété
lg=longueur;
ptr = new char[lg+1];
for (int i=0; i < lg; i++) { *(ptr+i) = c; }
*(ptr+lg) = ‘\0’; // marqueur de fin
}

Ainsi Chaine ch1(‘’bonjour ’’); // crée une chaîne de 7 caractères contenant le mot ‘bonjour’
Chaine ch2(22,’*’); // crée une chaîne de 22 caractères *
Chaine ch3; // crée une chaîne vide

6 Objets utilisés en paramètre ou en retour


Comme toute fonction, une méthode peut recevoir en paramètre un objet de sa classe ou d’une autre :
int Expl::fct1(Point &x) // passage par référence
int Expl::fct2(Expl x) // passage par valeur

C++ M. DALMAU, IUT de BAYONNE


7
Comme toute fonction, une méthode peut retourner un objet de sa classe ou d’une autre :
Point & Expl::fct() // par référence
Expl Expl::fct2() // par valeur

EXEMPLE OBJET CHAINE DE CARACTERES

Création d’une méthode ajoute pour coller une chaîne à la fin.

Dans CHAINE.HPP on ajoute :


void ajoute(Chaine &); // concatène une chaîne à la fin
// (le paramètre est passé par référence pour des raisons que nous verrons plus tard)

Dans CHAINE.CPP on ajoute :


void Chaine::ajoute(Chaine &plus) { //concaténation à la fin de la chaîne
char *ancien;
ancien = ptr; // garder un pointeur sur l’ancienne zone de mémoire
int ancienne_lg = lg; // conserver l’ancienne longueur;
lg = ancienne_lg + plus.longueur(); // calcul de la nouvelle longueur
ptr = new char[lg+1]; // allocation de mémoire pour la nouvelle chaîne
for (int i=0; i < ancienne_lg; i++) *(ptr+i) = *(ancien+i); // recopie de l’ancienne chaîne
for (i=0; i < plus.longueur(); i++)
*(ptr+ ancienne_lg +i) = plus.car(i); // ajout de la chaîne passée en paramètre
*(ptr+lg) = ‘\0’; // marqueur de fin
delete [] ancien; // libération de l’ancienne zone;
}

7 Adresse d’un objet


Le pointeur this accessible dans une méthode pointe toujours sur l’objet dont on a appelé cette méthode.

8 Constructeur par recopie


Il s’agit d’un constructeur d’objet permettant de créer un objet par recopie d’un autre. Il sera de la forme:
Expl::Expl(Expl &v) // copie v dans l’objet créé

L’existence d’un tel constructeur évitera le problème soulevé par : Expl b=a; qui fait une copie de a dans le
nouvel objet b sans tenir compte des zones de mémoire pointées dans a (on ne recopie que les pointeurs et non
les zones pointées). Il faudra écrire ce constructeur de façon a ce qu’il prenne en charge la recopie correcte de a
dans b.

Appel : Le constructeur par recopie sera automatiquement appelé lorsqu’un objet nouveau sera déclaré avec
comme valeur initiale celle d’un autre objet ( Point b=a; ). Il le sera également lors de tout passage de paramètre
par valeur pour créer la copie du paramètre. Il sera également utilisé lors d'un retour par valeur pour créer l'objet
retourné.

REMARQUE : Un constructeur par recopie est nécessaire pour tout objet utilisant de l’allocation dynamique de
mémoire dès lors que l’on désire pouvoir passer un tel objet en paramètre par valeur à des fonctions. En effet, un
passage par valeur consiste en la création d’un nouvel objet par recopie du paramètre. En l’absence de
constructeur approprié la recopie de fait simplement par copie des membres y compris des pointeurs.

C++ M. DALMAU, IUT de BAYONNE


8
EXEMPLE OBJET CHAINE DE CARACTERES

Addition d ’un constructeur par recopie permettant de passer les chaînes en paramètre par valeur à des fonctions

Dans CHAINE.HPP on ajoute :


Chaine(Chaine &); // constructeur par recopie

Dans CHAINE.CPP on ajoute :


Chaine:: Chaine (Chaine &acopier) {
lg = acopier.longueur(); // récupération de la longueur de la chaîne modèle
ptr = new char[lg+1]; // allocation de la mémoire nécessaire
strcpy (ptr, acopier.ptr); // copie de la chaîne modèle
}

9 Constructeur d’un objet contenant d’autres objets


Lorsqu’un objet en contient d’autres se pose le problème des constructeurs pour ces objets qui devraient être
appelés lors de la création de l’objet qui les contient. Le constructeur de l’objet a qui contient les objets b et c
devra appeler les constructeurs de b et de c en leur passant les bons paramètres :
class A {
Point b;
Expl c;
...
Le constructeur de la classe a s’écrira alors :
A::A(int x, int y, int z, char u, int w): b(x,y), c(u) // le constructeur de b est appelé avec x et y
// tandis que celui de c est appelé avec u
{ corps du constructeur de a utilisant w }

10 Fonction amie
Il s’agit d’une méthode d’une classe ou d’une fonction indépendante pouvant accéder à des membres d’une autre
classe ou de plusieurs. Par exemple pour créer des opérations entre objets de classes différentes (produit de
vecteur par matrice).
On la déclare dans la classe à laquelle elle doit pouvoir accéder par : friend int fct(int, Expl); s’il s’agit d’une
fonction indépendante ou par : friend int Point::fct(int, Expl); s’il s’agit d’une méthode (ici de Point). Dans ce
cas il faut que la classe Point soit compilée en premier.
Si toutes les méthodes d’une classe A sont amies d’une autre classe B on pourra déclarer dans B : friend class A;

EXEMPLE OBJET CHAINE DE CARACTERES

Création d’une fonction permettant de remplacer dans une chaîne un caractère par le caractère de même rang pris
dans pris dans une autre chaîne

Il faut pouvoir modifier les caractères de la chaîne ce qui n’est pas possible car le membre ‘ptr’ est privé. Deux
solutions sont possibles :
On crée une méthode de la classe Chaine
On crée une fonction amie de la classe Chaine

Si l’on choisit la première solution on utilisera cette méthode par : machaine.modifie(rang , modele)
Tandis que si l’on choisit la seconde on écrira : modifie (machaine, rang, modele)

Pour traiter cet exemple nous choisirons de définir une fonction amie.

Dans CHAINE.HPP on ajoute :


friend int modifie(Chaine &, int, Chaine); // fonction amie de modification d’un caractère, retourne 0 si la
// modification a eu lieu

C++ M. DALMAU, IUT de BAYONNE


9
Et on écrit la fonction modifie que l’on peut placer, par exemple, dans le programme principal:

int modifie(Chaine &ch, int rang, Chaine modele) {


int retour;
if ((rang > ch.longueur()) | | (rang > modele.longueur())) retour = -1;
else {
retour = 0;
*(ch.ptr + rang) = *(modele.ptr + rang); // on bénéficie de l’accès privilégié à ptr
}
return retour;
}

ATTENTION : La fonction modifie reçoit un paramètre de classe Chaine par valeur (le dernier) cela peut
fonctionner parce qu’on a défini un constructeur par recopie à la classe Chaine. En l’absence de constructeur par
recopie le fonctionnement aurait été le suivant:
Lors de l’appel de la fonction, une copie du paramètre est faite. Cette copie possède un membre ptr égal
à celui de l’original
A la fin de la fonction cette copie est détruite par le destructeur que nous avons défini par conséquent la
mémoire pointée par le membre ptr de la copie est libérée. Or cette mémoire est aussi celle de l’original qui se
voit ainsi privé de sa zone de mémoire !

On aurait pu, bien entendu, contourner ce problème en passant toujours les paramètres de classe Chaine par
référence et l’entête de la fonction amie deviendrait : friend int modifie(Chaine &, int, Chaine &);
C’est ce que l’on avait fait lors de l’écriture de la méthode ajoute à laquelle on avait passé un paramètre de classe
Chaine par référence alors qu’il n’était pas modifié par la méthode.

11 Surdéfinition d’opérateur
On peut surdéfinir les opérateurs (+ - = < etc.).

11.1 Surdéfinition
1°) Avec une fonction externe
Si l’on veut surdéfinir + pour une classe Complexe on fera :
friend Complexe operator + (Complexe &,Complexe &); // dans la classe complexe
et Complexe operator + (Complexe & a, Complexe & b)
{ corps de l’opérateur } // fonction indépendante
c=a+b; sera interprété par C++ comme c=operator + (a,b);

2°) Avec une méthode de la classe


On peut aussi surdéfinir un opérateur comme méthode d’une classe. Dans ce cas, la classe complexe contient une
méthode : Complexe operator + (Complexe &)
et c=a+b; sera interprété par C++ comme c = a.operator + (b);

REMARQUE : la surdéfinition de = permettra d’éviter les problèmes d’affection d’objets contenant une partie
dynamique. Toutefois l’existence d’un tel opérateur n’évite pas le constructeur par recopie lorsque celui ci fait
une allocation dynamique de mémoire (qui ne doit être, en général, faite que lors de la création de l’objet et non
à chaque affectation)

Les opérateurs que l’on peut redéfinir :


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

C++ M. DALMAU, IUT de BAYONNE


10
11.2 Valeur en retour pour un opérateur surdéfini
Selon le type d’opérateur la valeur en retour pourra être soit une valeur soit une référence. La règle consiste
simplement à choisir une référence lorsque la variable ou l'objet en retour existait avant l’appel de l’opérateur et
une valeur lorsque l’opérateur a créé cette variable ou cet objet. Ainsi :
L’opérateur = modifie l’objet auquel il appartient et retourne une référence à cet objet (return *this)
L’opérateur + crée un nouvel objet somme des paramètres et retourne la valeur de cet objet
L’opérateur [ ] extrait un objet dans celui auquel il appartient et retourne une référence à cet objet. Ceci permet
d’écrire obj[n]=x qui n’aurait aucun sens si l’opérateur [] retournait une valeur.

EXEMPLE OBJET CHAINE DE CARACTERES

Il va être nécessaire de surdéfinir l’opérateur =

En effet si l’on exécute le programme suivant :


Chaine a(‘’bonjour’’);
a.affiche();
Chaine b;
b=a;
b.affiche();
Chaine c=a;
c.affiche();
a.majusc();
b.affiche();
c.affiche();

On obtient le résultat suivant :


bonjour // résultat de a.affiche() : a est construit avec une valeur initiale
bonjour // résultat de b.affiche() : l’affectation b=a semble marcher
bonjour // résultat de c.affiche() : c est construit par le constructeur par recopie
Bonjour // résultat de a.affiche() : a a été modifiée
Bonjour // résultat de b.affiche() : b a subi la modification de a
bonjour // résultat de c.affiche() : c ne l’a pas subie car il constitue une copie de a

L’affectation b=a n’a pas recopié le contenu de a dans b mais seulement le pointeur et toute modification sur a
(majusc) est visible sur b (dernier affichage de b).

En revanche, le constructeur par recopie utilisé pour créer c a évité ce problème.

Dans CHAINE.HPP on ajoute :


Chaine & operator = (Chaine &); // surdéfinition de =

Dans CHAINE.CPP on ajoute :


Chaine & Chaine::operator = (Chaine &ch)
{
if (this != &ch) {
delete []ptr; // libérer la place actuellement utilisée par l’objet à gauche de =
lg = ch.longueur(); // mise à jour de la taille à partir de celle ch
ptr = new char [lg+1]; // allocation de la place nécessaire
for (int i=0; i <= lg; i++) {
*(ptr + i) = ch.car(i);
}
}
return *this;
}

C++ M. DALMAU, IUT de BAYONNE


11
12 L’Héritage
L’Héritage permet de définir de nouvelles classes à partir d’une ou plusieurs classes existantes. La nouvelle
classe ainsi définie hérite des membres et des méthodes de sa(ses) classe(s) mère(s) et y ajoute ses propres
membres et méthodes.
Un objet d’une classe B héritière de la classe A est aussi un objet de classe A et peut remplacer à tout instant un
objet de classe A. En effet, un objet de classe B est au moins capable de se comporter comme un objet de classe
A (il peut en général faire même plus).
Grâce à la surdéfinition, certaines méthodes de A peuvent être redéfinies dans B. Il conviendra que ces
surdéfinitions conservent la sémantique des méthodes initiales de façon à ce que le comportement d’un objet de
classe B utilisé en lieu et place d’un objet de classe A reste cohérent.

12.1 Définition d’une classe dérivée


class Nouvelle : public Ancienne
ou class Nouvelle : private Ancienne

La classe Nouvelle hérite de la classe Ancienne. Si l’on a utilisé le terme public la partie publique de Ancienne
l’est aussi dans Nouvelle alors que si l’on a utilisé private la partie publique de Ancienne est accessible par le
concepteur de Nouvelle mais pas par les utilisateurs.
La conception de Nouvelle peut utiliser tout ce qui est public et protected dans Ancienne. Elle n’autorise pas les
accès aux membres ou méthodes privées de Ancienne.
L’utilisateur d’un objet de la classe Nouvelle pourra utiliser les méthodes publiques de Ancienne et celles de
Nouvelle.
Si des méthodes de Nouvelle ont le même nom que certaines existant dans Ancienne, elles viennent les cacher
(surcharge).

12.2 Constructeur, destructeur


Si Nouvelle a un constructeur, il sera exécuté après celui de Ancienne à chaque création d’un objet de la classe
Nouvelle. Si Nouvelle a un destructeur, il sera exécuté avant celui de Ancienne à chaque destruction d’un objet
de la classe Nouvelle.
La transmission d’informations entre constructeurs peut se faire par :
Nouvelle(int x, int y, char u):Ancienne(x,y);

EXEMPLE OBJET CHAINE DE CARACTERES

Création d’une nouvelle classe : Chaine-coloree permettant d’avoir une chaîne de caractères à laquelle sont
associées deux couleurs (fond et texte).

Nous allons doter cette nouvelle classe d’une méthode permettant de choisir les deux couleurs et d’un
constructeur permettant d’initialiser une chaîne et ses couleurs.
Il faudra aussi surcharger la méthode d’affichage pour tenir compte des couleurs.

FICHIER CHAINECL.HPP
#include ‘’Chaine.hpp’’

class Chaine_coloree:public Chaine // classe dérivée de la classe Chaine


{
private:
Couleur couleur_fond;
Couleur couleur_texte;
public:
void choix_couleurs(Couleur, Couleur); // modifie les couleurs du fond et du texte
chaine_coloree(char *, Couleur, Couleur); // constructeur avec init chaîne et couleurs
void affiche();
};

C++ M. DALMAU, IUT de BAYONNE


12
FICHIER CHAINECL.CPP
#include <iostream>
#include ‘’chainecl.hpp’’

void Chaine_coloree::choix_couleurs(Couleur fond, Couleur texte)


{
couleur_fond = fond;
couleur_texte = texte;
}

Chaine_coloree::Chaine_coloree(char *chaineini, Couleur fond, Couleur texte):Chaine(chaineini)


// constructeur faisant appel à celui de Chaine
{
choix_couleurs(fond,texte);
}

void Chaine_coloree::affiche()
{
std::cout<<‘’<couleur_fond = ‘’;
std::cout<< couleur_fond.rouge()<<","<<couleur_fond.vert()<<","<<couleur_fond.bleu()
std::cout <<" ; couleur_texte = ";
std::cout<< couleur_texte.rouge()<<","<<couleur_texte.vert()<<","<<couleur_texte.bleu()
std::cout<<‘’>‘’; // indiquer les couleurs
Chaine::affiche(); // afficher la chaîne
}

On peut maintenant tester le fonctionnement de cette nouvelle classe en faisant :


Couleur cl1(30000,5000,0);
Couleur cl2(60000,25000,9990);
Chaine_coloree c(‘’bonjour’’,cl1,cl2);
c.affiche();
c.majusc(); // appel d’une méthode héritée
c.choix_couleurs(cl2,cl1); // appel d’une méthode nouvelle
c.affiche(); // appel de la méthode surchargée

qui donnera les affichages suivants :


<couleur_fond = 30000,5000,0 ; couleur_texte = 60000,25000,9990> bonjour
<couleur_fond = 60000,25000,9990 ; couleur_texte = 30000,5000,0> Bonjour

13.3 Remarque concernant le problème des inclusions multiples d’un fichier :

Lorsque l’on crée une classe dérivée, on doit inclure dans son fichier d’en-tête celui de la classe mère. Ceci peut
poser le problème suivant :
Classe1 et Classe2 sont deux classes dérivées de la classe ClasseMere. Le fichier d’en-tête de Classe1, appelé
Classe1.hpp contient la ligne #include ‘’ClasseMere.hpp’’. De même le fichier d’en-tête de Classe2, appelé
Cclasse2.hpp contient la ligne #include ‘’ClasseMere.hpp’’. Si un programme doit utiliser des objets de la classe
Classe1 et des objets de la classe Classe2, il devra contenir les lignes :
#include ‘’Classe1.hpp’’
et #include ‘’Classe2.hpp’’

Lors de la compilation, on aura donc deux fois l’inclusion de ClasseMere.hpp (une fois à cause de Classe1.hpp et
l’autre à cause de Classe2.hpp) ce qui causera des erreurs de double définition. Pour éviter ceci, on utilisera dans
le fichier ClasseMere.hpp, une directive de compilation conditionnelle de la façon suivante :
#ifndef CLASSEMERE
#define CLASSEMERE
mettre ici le contenu du fichier ClasseMere.hpp tel qu’il était jusque là

C++ M. DALMAU, IUT de BAYONNE


13
#endif
;
Lors de la première inclusion de ClasseMere.hpp, la constante CLASSEMERE n’est pas définie et le compilateur
prend en compte le define qui suit ainsi que tout le reste du fichier. Lors de la deuxième inclusion de
ClasseMere.hpp, la constante CLASSEMERE est définie (puisqu’elle l’a été lors de la première inclusion) et le
compilateur saute jusqu’au ; qui suit la directive endif.

12.4 Héritage multiple


Une classe peut hériter de plusieurs autres. Elle contient tout ce qu’il y avait dans chacune des classes
mères plus ce que l’on rajoutera à la nouvelle.
Pour créer une classe ptc qui hérite des classes pt et coul on écrira :
class Ptc : public Pt, public Coul

Problème de duplication : si B hérite de A, C hérite de A et D hérite de B et C, on retrouvera dans D deux fois le


contenu de A ce qui peut ne pas être souhaitable. Il faudra alors faire :
class B public virtual A
class C public virtual A
class D public B, public C

EXEMPLE OBJET CHAINE DE CARACTERES

Héritage multiple

Nous allons définir une nouvelle classe : style qui permettra de gérer le style du texte (police et aspect)

FICHIER STYLE.HPP
class Style
{
private :
char police; // une lettre pour définir la police
int aspect; // un code pour chaque combinaison des attributs (gras, souligné ...)
public:
Style(char, int); // constructeur avec initialisations
void choix_style(char, int); // modification du style
void affiche(); // affichage du style seul
};

FICHIER STYLE.CPP
#include <iostream>
#include ‘’Style.hpp ’’

void Style::choix_style(char p, int a)


{
police = p; aspect = a;
}

Style::Style(char p, int a)
{
choix_style(p,a);
}

void Style::affiche()
{
std::cout<<‘’[‘’<<police<<‘’ , ‘’<<aspect<<‘’] ’’;
}

C++ M. DALMAU, IUT de BAYONNE


14
On peut maintenant définir une classe Chaine_style par dérivation de Chaine_coloree et de style :

FICHIER CHAINEST.HPP
#include ‘’Chaine_coloree.hpp’’
#include ‘’Style.hpp’’

class Chaine_style : public Chaine_coloree, public style // construction par héritage multiple
{
public:
Chaine_style(char *, Couleur, Couleur,char , int); // constructeur avec : chaîne
// initiale, couleurs du fond et du texte, police et aspect
void affiche(); // surcharge de l’affichage
};

FICHIER CHAINEST.CPP
#include ‘’Chainest.hpp’’

Chaine_style::Chaine_style (char *chaineini, Couleur fond, Couleur texte, char police, int aspect):
Chaine_coloree(chaineini,fond,texte), Style(police,aspect)
{
// on n’a rien a ajouter dans ce constructeur puisqu’il fait appel à ceux de Chaine_coloree et de Style en leur
// transmettant les paramètres
}

void Chaine_style_affiche()
{
Style::affiche(); Chaine_coloree::affiche(): // affichage du style puis de la chaîne avec ses couleurs
}

On pourra utiliser ces objets comme suit :


Couleur cl1(30000,5000,0);
Couleur cl2(60000,25000,9990);
Chaine_style ch1(‘’bonjour’’, cl1 , cl2 , ‘t’, 0); // construction de l’objet
ch1.affiche(); // appel de la méthode surdéfinie
ch1. choix_couleurs(cl2,cl1); // appel d’une méthode de Chaine_coloree
ch1.choix_style(‘s’,2); // appel d’une méthode de style
ch1.majusc(); // appel d’une méthode héritée de Chaine par Chaine_coloree
ch1.affiche();

On obtiendra le résultat suivant :


[t , 0] <couleur_fond = 30000,5000,0 ; couleur_texte = 60000,25000,9990> bonjour
[s , 2] <couleur_fond = 60000,25000,9990 ; couleur_texte = 30000,5000,0> Bonjour

12.5 Polymorphisme

Un objet d’une classe dérivée est objet de la classe de base et pas le contraire
Un objet de classe B dérivée de A peut être utilisé partout où un objet de A peut l’être.
avec A *ptra, obja;
B *ptrb, objb;

on peut faire : ptra=ptrb;


et obja=objb;

C++ M. DALMAU, IUT de BAYONNE


15
Lorsque l’on fait ptra=ptrb l’objet pointé par ptra est considéré comme étant de classe A (à cause de la
déclaration de ptra) et on ne peut donc pas utiliser les méthodes propres à B.

Et si une méthode de A a été surchargée dans B laquelle va-t-on utiliser ?

En général c’est la méthode de A qui sera prise car le compilateur ne sait pas au moment de la compilation vers
quoi pointe ptra (il suppose naturellement que c’est vert un objet de classe A puisque ptra a été déclaré comme
ça). Mais on peut modifier ce comportement en déclarant la méthode virtual dans la classe A. Ceci indique au
compilateur que cette méthode peut être redéfinie dans les classes dérivées et qu’il faudra décider au moment de
l’exécution laquelle il faut choisir selon l’objet réellement pointé.
Tout cela ne peut marcher que pour des objets dynamiques. En effet si l’on fait obja = objb; les méthodes
utilisables sont celles de A.
Les méthodes virtuelles sont définies par le prototype :
virtual void Expl::fct(int a, int b);

A quoi sert le polymorphisme ?


Si on définit une classe L qui est une liste d’objets de classe A, on pourra mettre dans cette liste des objets de
n’importe quelle classe à partir du moment où elle est hérité de A. On peut ainsi définir une classe A très générale
(pratiquement vide) que l’on pourra toujours spécialiser. Si les méthodes de A sont ‘virtual’ et redéfinies dans
les classes dérivées, les objets de la liste se comporteront normalement.

EXEMPLE OBJET CHAINE DE CARACTERES

Problème du polymorphisme

Si l’on fait le test suivant :


Chaine *ptr1 = new Chaine(‘’chaine 1’’);
Couleur cl1(30000,5000,0);
Couleur cl2(60000,25000,9990);
Chaine_coloree *ptr2 = new Chaine_coloree(‘’chaine 2’’, cl1 ,cl2);
ptr1 -> affiche();
ptr2 -> affiche();
ptr1 = ptr2;
ptr1 -> choix_couleurs(cl2,cl1);
ptr1 -> affiche();

- On a une erreur de compilation sur la ligne : ptr1 -> choix_couleurs(cl2,cl1); puisque l’objet désigné est de
classe Chaine et ne possède donc pas de méthode choix_couleurs.
- Si on supprime cette ligne et que l’on exécute le programme de test on obtient le résultat suivant :
chaine 1 C’est le résultat de ptr1 -> affiche()
<couleur_fond = 30000,5000,0 ; couleur_texte = 60000,25000,9990> chaine 2
C’est le résultat de ptr2 -> affiche()
chaine 2 C’est le résultat de ptr1 -> affiche()

En effet, le dernier appel de affiche() fait référence à la méthode définie dans Chaine et non dans Chaine_coloree.
Pour éviter ce problème il suffit de modifier le fichier CHAINE.HPP comme suit :
virtual void affiche(); // affichage de la chaîne pouvant être redéfini et choisi dynamiquement

Après cette modification le dernier affiche du test donnera bien :


<couleur_fond = 60000,25000,9990 ; couleur_texte = 30000,5000,0> chaine 2

12.6 Classe abstraite


Une classe contenant une méthode virtuelle pure de la forme :
virtual void fct ( ........ ) =0;
ne peut servir qu’à dériver d’autres classes. Aucun objet de cette classe ne peut être défini. Si on en dérive une
classe dans laquelle on ne redéfinit pas cette méthode, cette classe est à son tour abstraite.

C++ M. DALMAU, IUT de BAYONNE


16
13 Membres communs
On peut faire partager un membre à tous les objets d’une classe en le déclarant static.
class Expl { quant on fait : expl a,b; a et b ont le même n
static int n;
float x
....
}
On peut initialiser une seule fois ce membre par : int Expl::n=0; à la suite de la définition de la classe Expl.
Un tel membre peut être utilisé par exemple pour savoir de combien d’objets de cette classe on dispose si le
constructeur de chaque objet l’incrémente.

14 Fonction statique
C’est une fonction indépendante de l’objet mais liée seulement à la classe. C’est en général une fonction
qui agit sur des membres communs.
static void Expl::fct()
On l’appellera sans désigner d’objet par Expl::fct();

15 Objets ne pouvant pas être modifiés


On les déclare avec const
const Point c; // c ne peut pas être modifié
int Point::fct(const Expl x) // l’objet de classe Expl passé en paramètre ne peut pas être
modifié et seules les méthodes explicitement déclarées avec le mot clé const dans la classe Expl pourront lui être
appliquées ( void methode(....) const )

16 Pointeurs sur des fonctions


Déclaration : int (*ptr) ( char , int ); // pointeur sur une fonction à valeur entière ayant 2 paramètres
char et int
appel : (* ptr) (‘c’,1);
initialisation : ptrf=&fct

17 Pointeurs sur des méthodes


déclaration : int (Point::*ptr) ( char , int ); // pointeur sur méthode de la classe point à valeur entière
ayant 2 paramètres char et int
appel : (obj.* ptr) (‘c’,1);
initialisation : ptrf=&Point::fct

18 Entrées / Sorties Fichiers


inclure <fstream.hpp> et <iostream.hpp> On dispose des classes ifstream, ofstream et fstream.

entrée : ifstream fichier(‘’nom’’ , ios::out);


sortie : ofstream fichier(‘’nom’’ , ios::in);
qque : fstream fichier(‘’nom’’ , ios::in | ios::out);
On les utilise ensuite par fichier<<x ou fichier>>y etc

On peut combiner les modes ios::z par | on dispose de :


ios::in lecture
ios::out écriture
ios::app écriture en fin
ios::ate aller en fin après ouverture
ios::trunc création
ios::nocreate doit exister
ios::noreplace ne doit pas exister
déplacements pour ifstream seekg(dist , ios::lieu);
pour ofstream seekp(dist , ios::lieu);

C++ M. DALMAU, IUT de BAYONNE


17
permet de se déplacer de dist par rapport au point defini par lieu :
ios::beg début
ios::cur point courant
ios::end fin

C++ M. DALMAU, IUT de BAYONNE


18
SOMMAIRE
1 PRINCIPES ............................................................................................................................................................................1

2 MODIFICATIONS PAR RAPPORT AU C.........................................................................................................................1


2.1 DECLARATIONS .......................................................................................................................................................................1
2.2 Surdéfinition .....................................................................................................................................................................1
2.3 COMMENTAIRES ......................................................................................................................................................................1
3 CLASSES................................................................................................................................................................................2
3.1 DECLARATION.........................................................................................................................................................................2
3.2 UTILISATION ...........................................................................................................................................................................2
3.2.1 Utilisation directe ..........................................................................................................................................................2
3.2.2 Utilisation avec des pointeurs........................................................................................................................................2
3.3 METHODES ET FONCTIONS .......................................................................................................................................................4
3.3.1 Référence .......................................................................................................................................................................4
3.3.2 Valeurs par défaut de paramètres..................................................................................................................................4
4 CONSTRUCTION ET DESTRUCTION D’OBJETS.........................................................................................................5
4.1 CONSTRUCTEUR ......................................................................................................................................................................5
4.2 DESTRUCTEUR ........................................................................................................................................................................5
4.3 CONSTRUCTION ET DESTRUCTION D’OBJETS ALLOUANT DYNAMIQUEMENT DE LA MEMOIRE .......................................................6
5 SURDEFINITION DE METHODES ...................................................................................................................................7

6 OBJETS UTILISES EN PARAMETRE OU EN RETOUR...............................................................................................7

7 ADRESSE D’UN OBJET ......................................................................................................................................................8

8 CONSTRUCTEUR PAR RECOPIE ....................................................................................................................................8

9 CONSTRUCTEUR D’UN OBJET CONTENANT D’AUTRES OBJETS ........................................................................9

10 FONCTION AMIE ..............................................................................................................................................................9

11 SURDEFINITION D’OPERATEUR................................................................................................................................10
11.1 SURDEFINITION ...................................................................................................................................................................10
11.2 VALEUR EN RETOUR POUR UN OPERATEUR SURDEFINI ..........................................................................................................11
12 L’HERITAGE ....................................................................................................................................................................12
12.1 DEFINITION D’UNE CLASSE DERIVEE.....................................................................................................................................12
12.2 CONSTRUCTEUR, DESTRUCTEUR ..........................................................................................................................................12
13.3 REMARQUE CONCERNANT LE PROBLEME DES INCLUSIONS MULTIPLES D’UN FICHIER : ............................................................13
12.4 HERITAGE MULTIPLE ...........................................................................................................................................................14
12.5 POLYMORPHISME ................................................................................................................................................................15
12.6 CLASSE ABSTRAITE..............................................................................................................................................................16
13 MEMBRES COMMUNS...................................................................................................................................................17

14 FONCTION STATIQUE...................................................................................................................................................17

15 OBJETS NE POUVANT PAS ETRE MODIFIES ..........................................................................................................17

16 POINTEURS SUR DES FONCTIONS ............................................................................................................................17

17 POINTEURS SUR DES METHODES .............................................................................................................................17

18 ENTREES / SORTIES.......................................................................................................................................................17
18.1 CLAVIER / ECRAN ..................................................................................................................................................................1
18.2 FICHIERS ................................................................................................................................ERREUR ! SIGNET NON DEFINI.

C++ M. DALMAU, IUT de BAYONNE


19

Anda mungkin juga menyukai