Vous êtes sur la page 1sur 45

04/12/2023

Informatique 5: Programmation
Orientée objet en Langage C++
Filière: SMI
Semestre: 5
Année universitaire: 2022-2023

Majid BEN YAKHLEF

B.M Cours C++ 1

1
04/12/2023

Contenu

 Généralités
 Classe et Objets
 L’encapsulation
 L’héritage
 Le polymorphisme

B.M Cours C++ 3

Historique du langage C++

• 3ème langage le plus utilisé au monde pour les applications Android et le 2eme pour
l’intelligence artificielle après Python (classements 2022,
https://fr.yeeply.com/blog/langages-programmation-plus-utilises-developpeurs-2022/)
• JVM(hotspot) et une partie du noyau de Google Chrome écrits en C++
• Première version développée par Bjarne Stroustrup de Bell Labs AT&T en 1980
Appelé à l’origine « Langage C avec classes »
• Devenu une norme ANSI/ISO C++ en juillet 1998 (C++98 - ISO/IEC 14882) – mise à
jour en 2003 (C++03)
- ANSI : American National Standard Institute
- ISO : International Standard Organization

B.M Cours C++ 4

2
04/12/2023

Qu’est-ce que le C++ ?


• D’après Bjarne Stroustrup, conception du langage C++ pour :
• Être meilleur en C,
• Permettre la programmation orientée-objet
• Compatibilité C/C++ :
• C++ = sur-ensemble de C,
• C++  ajout en particulier de l’orienté-objet (classes, héritage, polymorphisme),
• Cohabitation possible du procédural et de l‘orienté-objet en C++
• Différences C++/Java :
• C++ : langage compilé / Java : langage interprété par la JVM
• C++ : pas de machine virtuelle et pas de classe de base / java.lang.object
• C++ : "plus proche de la machine" (gestion de la mémoire)

B.M Cours C++ 5

Gestion de la mémoire :
• Java :
• Création des objets par allocation dynamique (new)
• Accès aux objets par références
• Destruction automatique des objets par le ramasse miettes
• C++ :
• Allocation des objets en mémoire statique (variables globales), dans la pile (variables
automatiques) ou dans le tas (allocation dynamique),
• Accès direct aux objets ou par pointeur ou par référence
• Libération de la mémoire à la charge du programmeur dans le cas de l'allocation
dynamique
• Autres possibilités offertes par le C++ :
Variables globales, compilation conditionnelle (préprocesseur), pointeurs, surcharge des
opérateurs, patrons de classe template et héritage multiple.

B.M Cours C++ 6

3
04/12/2023

1- Introduction
- Caractéristiques du langage C++
Apparu au début des années 90, le langage C++ est actuellement l’un des plus utilisés
dans le monde, aussi bien pour les applications scientifiques que pour le développement
des logiciels
C++ =langage C (Structuré) +POO (orientée objet)+(gestion des exceptions) .
Le C++ est une surcouche de C, avec quelques incompatibilités de syntaxe
Un programme C est la plupart du temps un programme C++.

Domaines d’utilisation du langage c++:


• La plupart des applications graphiques : création de programmes en 3D, par exemple
• Le traitement de texte
• Les jeux vidéos
• La mise en place d'outils financiers
• La création de certains programmes militaires.

B.M Cours C++ 7

- Déclaration des Variables:


En C++, il n’est plus nécessaire de regrouper les déclarations en début de fonction ou en début de
bloc.
Il devient aussi possible d’employer des expressions dans des initialisations

Exemples:
int n ;
….
n=… ;
….
int q=2*n-1 ;
….
for (int i=0 ;i<n ;i++) // en C: int i; for (i=0 ;i<n ;i++)…

- Initialisation à la mode objet :


int i(0) ; // int i=0; en C
long j(123456789); // long j= 123456789; en C

B.M Cours C++ 8

4
04/12/2023

Entrées / Sorties standard


Puisque C++ est une extension du langage C, la majorité des programmes valides en C sont aussi des
programmes en C++ valides mais pas tous.
C++ fournie des instructions d'entrée-sortie plus simples que celles du C qui sont définies
C++ offre des bibliothèques alternatives plus conviviales. Pour les fonctions d’entrés/sorties, il offre
<iostream>.
cin : flot lié à l’entrée standard, par défaut le clavier. Il correspond au fichier prédéfini stdin du langage C.
cout : est un flot de sortie prédéfini associé à la sortie standard (stdout du C).
Deux opérateurs sont définis :
>>Cet opérateur extrait une variable ou une expression du flot d’entrée
<<Cet opérateur envoie une variable ou une expression sur le flot de sortie
Ces opérateurs agissent sur tous les types prédéfinis. Il n’est pas nécessaire, comme c’était le cas avec les
fonctions du C, de préciser les types des variables (les codes formats).
#include <iostream>
int main(){
int n=3;
for(int i=0;i<n;i++)
std::cout<<"Hello World "<<i+1<<std::endl;
return 0;}

B.M Cours C++ 9

Syntaxe:
- cout<<expression1 <<expression2<<…..<<expressionN;
affiche sur l’écran les valeurs des différentes expressions. Les expressions peuvent être des chaines de
caractères ou bien des variables

- cin>>var1 >>var2 >>…..>>varn


lit sur le flot cin les informations de l’un des types prédéfinis: char, short, int, long, float, double , ou char*
Le caractère fin de ligne peut être inséré par le manipulateur endl, prédéfini dans le fichier <iostream>.
Exemple:
#include <iostream>
int main() {
std::cout << "Hello World" << std::endl;
}

Remarque :
Toute la bibliothèque standard C++ est définie dans son propre espace de nom, le namespace std. Ainsi, il est
possible de faire appel directement à tous les éléments issus de la bibliothèque <iostream> sans utiliser le
préfixe std::

#include <iostream>
using namespace std ;
int main() {
cout << "Hello World" << sendl;
}

B.M Cours C++ 10

5
04/12/2023

Espaces de noms
• Utilisation d’espaces de noms (namespace) lors de l’utilisation de nombreuses bibliothèques pour
éviter les conflits de noms.
• Espace de noms : association d’un nom à un ensemble de variable, types ou fonctions
Ex. Si la fonction MaFonction() est définie dans l’espace de noms MonEspace, l’appel
de la fonction se fait par:
MonEspace::MaFonction()
• Pour être parfaitement correct :
std::cin
std::cout :: opérateur de résolution de portée
std::endl
• Pour éviter l’appel explicite à un espace de noms : using
using std::cout ; // pour une fonction spécifique
using namespace std; // pour toutes les fonctions

Exemple:
#include <iostream>
using std::cout;
using std::endl;
int main() { // si on veut utiliser cin par exemple, il faudra écrire std::cin
cout << "coucou" << endl;
}

B.M Cours C++ 11

2- Les particularités du c++ par rapport au langage C


a-Types
• Type booléen: ce type est défini par le mots clé bool. Une variable de ce type
sert à représenter une information vraie ou fausse.

• Types dérivés
En C++, on définit comme en C des structures. Mais, dans la déclaration d’objets
de ces types dérivés, les mots clés struct, ne sont plus nécessaires ;

Exemple :
struct assure{ … } ;

main() {
const int n=50 ;
Float x=23,44;
assure a[n] ; //en C struct assure a[n] ;
}

B.M Cours C++ 12

6
04/12/2023

Tableau des types de données en langage C++ :


Le type d’une donnée détermine, La taille mémoire (sizeof()), les opérations légales et les
bornes des valeurs qu’il va prendre.
Type de Signification Taille (en octets) Plage de valeurs acceptée
donnée
char Caractère 1 -128 à 127
Caractère non
unsigned char 1 0 à 255
signé
short int Entier court 2 -32 768 à 32 767
unsigned short Entier court non
2 0 à 65 535
int signé
2 (sur processeur 16 bits) -32 768 à 32 767
int Entier
4 (sur processeur 32 bits) -2 147 483 648 à 2 147 483 647
2 (sur processeur 16 bits) 0 à 65 535
unsigned int Entier non signé
4 (sur processeur 32 bits) 0 à 4 294 967 295
long int Entier long 4 -2 147 483 648 à 2 147 483 647
unsigned long Entier long non
4 0 à 4 294 967 295
int signé
float Flottant (réel) 4 -3.4*10-38 à 3.4*1038
double Flottant double 8 -1.7*10-308 à 1.7*10308
Flottant double
long double 10 -3.4*10-4932 à 3.4*104932
long

Prend deux valeurs : 'true' et 'false' mais une


Même taille que le conversion implicite (valant 0 ou 1) est faite par le
bool Booléen type int, parfois 1 sur compilateur lorsque l'on affecte un entier (en
quelques compilateurs réalité toute autre valeur que 0 est considérée
comme égale à True).

B.M Cours C++ 13

Les conversions de type


Le langage C++ autorise les conversions de type entre variables de type char, int, float, double: Exemple:
int main() {
char c=0x56,d=25,e; int i=0x1230, j; float r=678.9,s;
j = c; cout<<"char to int :"<<j<<endl; // j vaut 86 sans dégradation
j = r; cout<<"float to int :"<<j<<endl;// j vaut 678 avec dégradation
s = d; cout<<"char to float :"<<s<<endl;// s vaut 25.0 sans dégradation
e = i; cout<<"int to char :"<<e<<endl; // e vaut 4 conversion avec dégradation
return 0;
}
Une conversion de type float --> int (float--> char) ou char est dite dégradante Une conversion de type int ou char --
> float (char-->double) est dite non dégradante

Remarque:
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) { return (u*f); }
int 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
return 0;
}

B.M Cours C++ 14

7
04/12/2023

Exercice d’application :
Ecrire la fonction float developpementExp(float x,int n) qui
𝑛
calcule et renvoie le résultat.
𝑥𝑖
𝑖!
𝑖=0
Ecrire la fonction principale et mettre en œuvre la fonction précédente en utilisant les propriétés de conversion de
type.

B.M Cours C++ 15

b- Fonctions
- Arguments par défaut:

Une valeur fournie dans une déclaration de fonction est automatiquement affectée
par le compilateur si la fonction appelante ne fournit pas de valeur pour
l’argument.

Exemple :
int sum(int x, int y, int z = 0, int w = 0) { //les deux attributs z et w ont comme valeur par
défaut zéro
return (x + y + z * w);
}
int main() {
cout << sum(10, 15) << endl; // affiche: 25
cout << sum(10, 15, 25) << endl; // affiche: 25
cout << sum(10, 15, 25, 3) << endl; // affiche: 100
return 0;
} B.M Cours C++ 16

8
04/12/2023

c- Surcharge de fonctions :
• La surcharge de fonctions est une fonctionnalité qui permet de définir, dans le même
programme, deux fonctions ou plus avec le même nom mais elles diffèrent par le type ou le
nombre des paramètres et aussi par le type de passage d’argument (par valeur , par référence
• La surcharge de fonctions peut être considérée comme le polymorphisme en C++.
Exemple 1:
#include <iostream>
using namespace std;
void afficher(int i) { cout << " passage par valeur de type int :" << i << endl; }
void afficher(int &a) { cout << " passage par référence de type int :" << a << endl; }
void afficher(char *c) { cout << " La valeur est de type char* :" << c << endl; }
int main( ) {
char s[12];
afficher(5);
afficher(33);
afficher(s);
return 0;
}

B.M Cours C++ 17

Exemple 2:
#include <iostream>
using namespace std;
void essai(float x,char c,int n=0){
cout<<"Fonction N°1: x = "<<x<<" c = "<<c<<" n = "<<n<<"\n";}
void essai(float x,int n){
cout<<"Fonction N°2: x = "<<x<<" n = "<<n<<"\n";}
int main(){
char l='z';int u=4;float y = 2.0;
essai(y,l,u); // fonction N°1
essai(y,l); // fonction N°1
essai(y,u); // fonction N°2
essai(u,u); // fonction N°2
essai(u,l); // fonction N°1
//essai(y,y); rejet par le complateur
essai(y,y,u); // fonction N°1
return 0;
}

B.M Cours C++ 18

9
04/12/2023

d-Gestion dynamique de la mémoire


• En plus des fonctions d’allocation de la mémoire déjà définies en C (malloc et free,…), le C++ fournit
d’autres fonctions pour allouer et libérer d’une manière dynamique la mémoire :
et delete: permettent, respectivement, d’allouer et désallouer la mémoire pour une variable
new[] et delete[]: permettent, respectivement, d’allouer et de désallouer tout un tableau d’espace
mémoire
Exemple :
#include <iostream>
#include <new>
using namespace std;
int main (int argc, char** argv) {
int * p1 = new int; // pointeur sur un entire
int *tp= new int(3);
*p1 = 1; // ecrit 1 dans la zone mémoire allouée
*tp=2;
*(tp+1)=22;
*(tp+2)=222;
cout << *p1 << endl; // lit et affiche le contenu de la zone mémoire allouée
for(int i=0;i<3;i++) cout << *(tp+i) <<“ ,“;
delete p1; // libère la zone mémoire allouée
delete tp;
return 0;
}

B.M Cours C++ 19

Remarques:
• Des précautions doivent être prises lors de l’utilisation de delete.
• Lorsque qu’un pointeur ptr a été alloué par new, on écrira alors delete ptr pour le libérer.
• delete ne doit pas être utilisé pour des pointeurs déjà détruits.
• delete ne doit pas être utilisé pour des pointeurs obtenus autrement que par l’utilisation de new.
• Une fois un pointeur détruit, on doit évidement arrêter de l’utiliser.

fuite de mémoire:
Chaque allocation avec "new" doit impérativement être libérée (détruite) avec "delete" sous peine de créer une
fuite de mémoire.
La fuite de mémoire est une zone mémoire qui a été allouée dans le tas par un programme qui a omis de la
désallouer avant de se terminer.
Cela rend la zone inaccessible à toute application (y compris le système d’exploitation) jusqu’au redémarrage du
système.
Si ce phénomène se produit trop fréquemment la mémoire se remplit de fuites et le système finit par tomber
faute de mémoire.

Ce problème est évité en Java en introduisant le mécanisme de "ramasse-miettes" (Garbage Collector)

B.M Cours C++ 20

10
04/12/2023

Exercice
Ecrire le programme suivant (correcte en C et en C++) en utilisant les nouvelles possibilités
d’entrées/sorties de C++ (en évitant l’utilisation des fonctions printf, scanf et malloc) :

#include<stdio.h>
int main(){
int n,i; float s,*b;
printf("Entrer un entier \n ");
scanf("%d ",&n);
b=(float *)malloc(sizeof(float)*5);
for(int i=0;i<n;i++){
scanf("%f",b+i);
s+=*(b+i);}
printf("la somme des nombres est: %f \n",s);
for(int i=0;i<n;i++)
printf(", %f",*(b+i));
free(b);
return 0;
}
B.M Cours C++ 21

Cas d’échec d’allocation


Le C++ standard contient plusieurs classes d’exception intégrées. Le plus couramment
utilisé est bad_alloc, qui est lancé si une erreur se produit lors de la tentative
d’allocation de mémoire avec new.

• choisir entre le renvoi d’un pointeur de valeur nulle


Ou:
• L’interruption de l’exécution du programme et le déclenchement d’une exception
bad_alloc. (comportement du gestionnaire installé par défaut).

B.M Cours C++ 22

11
04/12/2023

Utilisation du mot-clé statique (static)


Nous pouvons utiliser un mot-clé statique avec :
- Variables statiques : Variables dans une fonction, Variables dans une classe

- Membres statiques de la classe : objets de classe et fonctions dans une classe


Remarques:
• Il est impossible d'initialiser les données d'une classe(static) dans le constructeur de la classe.
• le constructeur n'initialise que les données des nouveaux objets.
• La définition des données membres statiques suit les mêmes règles que la définition des variables globales (déclarées
externes).

Variables statiques
Variables statiques dans une fonction doivent être initialisées à l'intérieur des fonctions membres et leur portée est réduite à
celle du bloc dans lequel elles ont été déclarées.
Exemple:
using namespace std;
void compteur(){
static int count = 0;
cout << count << ", ";
count++;
}
int main() {
for (int i=0; i<5; i++)
compteur();
return 0;
}
Résultat: 0, 1, 2, 3, 4, 5, 6, 7,

B.M Cours C++ 23

Notions de base de Programmation Orientée Objet :


Classes, Constructeurs et destructeurs d’objets, Propriétés des
méthodes

B.M Cours C++ 24

12
04/12/2023

Concept de classe et Objet

Etudiants Classe: déclare des propriétés communes a un


CodeEtud: int ensemble d'objets. Elle définie des attributs:
Nom: String variables représentant l‘état des objets, et des
Prenom: String méthodes définissant leurs comportements.
Filière: String
…….
ChagerFilière()
ChangerAdresse()
……

Objet 1 Objet 2 Objet n


…. Objet=Instance de
Z332 E213 Z123
. classe
Alami Youssefi Rachidi
Dont les attributs ont
Rachid Mouna Reda
une valeur.
SMA SMI SMA

B.M Cours C++ 25

Définition: rappel
Classe :
• Regroupement de données (attributs ou champs) et de méthodes (fonctions
membres)
• Extension des structures (struct) avec différents niveaux de visibilité (protected,
private et public)

En programmation orientée-objet pure : encapsulation des données et accès unique des


données à travers les méthodes

B.M Cours C++ 26

13
04/12/2023

Notion de classe en C++: interface:


En C++, la programmation d’une classe se fait en trois phases : Déclaration, Définition, Utilisation
(D.D.U).

- Déclaration :
c’est la partie interface de la classe(définition abstraite). Elle se fait dans un fichier dont le nom se
termine par .h. Ce fichier se présente de la façon suivante :
class Maclasse {
private:
déclarations des données et le prototype des fonctions-membres privées
protected:
déclarations des données et le prototype des fonctions-membres visibles en interne
et par les objets des classes dérivées
public:
déclarations des données et le prototype des fonctions-membres publiques
};
class Ellipse {
Vision private :
float m_cX, m_cY;
Exemple: interne float m_a, m_b;

Vision public :
externe void deplace(float dx, float dy);
void zoom(float z);
float surface();
};

B.M Cours C++ 27

- Définition :
c’est la partie implémentation de la classe( définition du code complet des différentes fonctions-
membres de de la classe). Elle se fait dans un fichier dont le nom se termine par .cpp
Exemple:

Déclaration de la classe Ellipse Définition de la classe Ellipse


class Ellipse { void Ellipse::deplace(float dx, float dy){
protected : m_cX += dx;
float m_cX, m_cY; m_cY += dy;
float m_a, m_b; }
public : void Ellipse ::zoom(float z) {
void deplace(float dx, float m_a *= z;
dy); m_b *= z;
void zoom(float z); }
float surface(); float Ellipse ::surface(){
}; return 3.14 * m_a * m_b / 4.;
}
• Visibilité des membres :
– public : membres accessibles à tous
– private : membres accessibles à partir de la classe ; accès impossible par l’extérieur
– protected : membres accessibles à partir de la classe et des classes dérivées ; accès
impossible par l’extérieur
B.M Cours C++ 28

14
04/12/2023

- Utilisation :
elle se fait dans un fichier dont le nom se termine par .cpp dans le quel on crée les objets de type classe et
faire l’appel au différentes fonctions.

<nom-classe> Obja, Objb[ ] ;


Obja et Objb sont deux objets de classe «nom-classe», c’est-à-dire des variables de type «nom-classe».
Obja une variable simple et Objb un tableau d’objet de type « nom-classe »

Exemple:
Ecllipse a, b[ ];

On peut accéder à n’importe quel membre public (donnée ou fonction) d’une classe en utilisant
l’opérateur (.)

syntaxe: a.nom-fonction (arguments);

Exemple:

B.M Cours C++ 29

Exemple:
//Déclaration
class points {
protected :
float x, y;
public :
points(float z);
void affichage(float d);
void affichage();
};
//Définition
void points::affichage(float d){ std::cout<<"la surface de l'ellipse est: "<<d;}
void points::affichage(){ std::cout<<" x= "<<x<<" y= "<<y<<endl; }
points::points(float a){ x= a; y= a;}

//Utilisation
int main() {
points *e=new points(3);
points *ee[3];
for( int i=0;i<3;i++) ee[i]=new points((float)i);
for( int i=0;i<3;i++) ee[i]->affichage();
delete e;
delete ee[3];
return 0;
}

B.M Cours C++ 30

15
04/12/2023

Structure d’un programme en C++ :


Les programmes en C++ seront généralement composés par (Figure ci-dessous):
– un fichier .h contenant la déclaration de la classe (structure interne de la classe)
– un fichier .h contenant sa définition,
– un fichier .cpp contenant le traitement principal. Ce dernier fichier contient la fonction
main, et c’est par cette fonction que commence l’exécution du programme.
Classe1.h classe2.h
……….
class classe1 { class classe2 {
………. ………. <------ Déclaration
}; };
defClasse1.h defclasse2.h
……….
#include "classe1.h" #include "classe2.h" <------ Définition
……………….. ………………..

Main.cpp
#include "defclasse1.h"
#include "defclasse2.h"
Void main() { <------ Utilisation
………………..
}

B.M Cours C++ 31

Remarque :
la directive d’inclusion #include permet d’inclure un fichier de déclarations dans un autre fichier:
#include <fichier_standard> fichier avec le compilateur C++,
#include "untel.h" , s’il s’agit d’un fichier écrit par nous-mêmes.

Par convention, les noms des classes commencent par une majuscule, les données membres par _ ou
m_, les fonctions membres par une minuscule.

B.M Cours C++ 32

16
04/12/2023

Constructeurs et destructeurs d’objets


Quand un objet est instancié à partir d’une classe, une fonction appelée constructeur associé à
cette classe est automatiquement exécutée.
Si aucun constructeur n’est ajouté explicitement, le constructeur par défaut est implicitement et
automatiquement appelé. (permet la création et l’initialisation de l’objet par: Zéro pour les float,
double et int . Par le caractère nulle pour les caractères et par false pour les booleans)

• Constructeurs
• De même nom que le nom de la classe
• Définition de l'initialisation d'une instance de la classe
• Appelé implicitement à toute création d'instance de la classe
• Méthode non typée, pouvant être surchargée
• Elle peut recevoir zéro, un ou plusieurs arguments

• Destructeur
• De même nom que la classe mais précédé d'un tilde (~)
• Définition de la désinitialisation d'une instance de la classe
• Appelé implicitement à toute disparition d'instance de la classe
• Méthode non typée et sans paramètre
• Ne pouvant pas être surchargé

B.M Cours C++ 33

Déclaration et définition d’un constructeur


Un constructeur de la classe points pourrait se déclarer explicitement dans la même classe par :
class points {
private :
float x, y;
public :
points(float z,float a);
points(float z);
void affichage(float d);
void affichage();
};
Et être défini en dehors de la classe par :
void points::affichage(float d){ std::cout<<"la surface de l'ellipse est: "<<d;}
void points::affichage(){ std::cout<<" x= "<<x<<" y= "<<y<<endl; }
points::points(float a, float b){ x= a; y= b; }
points::points(float a){ x= a; y= a; }

L’instanciation prend la forme :


int main() {
points pp(2);
points p(11,44);
pp.affichage();
p.affichage();
return 0;
} B.M Cours C++ 34

17
04/12/2023

Constructeur avec arguments par défaut


public :
points(float z=19, float a=32);
Dans ce cas on peut déclarer dans la fonction utilisatrice :
point a(5.5 , -2.) ; un point de coordonnées 5.5 et -2. est créé
point b; un point de coordonnées 0. et 0. est créé
point c(3.) ; un point de coordonnées 3. et 0. est créé

Exemple à tester:
class points {
private : float x;
public :
float y;
points(float z=19,float a=32);
void affichage(float d);
void affichage();
void setx(float z);
};
void points::setx(float z){x=z;}
void points::affichage(float d){ std::cout<<"la surface de l'ellipse est: "<<d;}
void points::affichage(){ std::cout<<"x= "<<x<<" y= "<<y<<endl; }
points::points(float a, float b){ x= a; y= b; }
int main() { points p1; points p(11);
points pp(32,21);
p1.affichage();
p.y=500; p.setx(222); p.affichage();
pp.affichage(); return 0;
}
B.M Cours C++ 35

Exercice :
Ajouter à l’exemple précédent, les deux méthodes suivantes:
- La méthode distance(points p) qui permet de calculer la distance entre deux points
- La méthode deplacer(float dx=0,float dy=0) pour déplacer un point selon l’axe des x et/ou des y.
- Ecrire la fonction principale main

B.M Cours C++ 36

18
04/12/2023

Constructeur de recopie

De la même manière que l'affectation (par défaut), le constructeur de recopie par défaut effectue la
copie membre à membre de la source vers la destination.
Il est appelé dans trois situations:
- Création d'un nouvel objet initialisé comme étant une copie d'un objet existant:
points p(2, 5);
Points pc(p); // création de l'objet pc image à l’objet p
- Ou bien
Points pc=p; // création de l'objet pc une copie de p.
- Ou bien
Points pc; // création de l'objet.
pc=p;

B.M Cours C++ 37

#include <iostream>
#include <math.h>
using namespace std;
class points {
private :
float x, y;
public :
points(float z);
points();
void affichage(string s);
float distance(points p);
void deplacer(float dx, float dy);
};
void points::affichage(string s){ std::cout<<s<<"x= "<<x<<" y= "<<y<<endl; }
points::points(float a){ x= a; y= a; }
float points::distance(points a){ return sqrt((a.x-x)*(a.x-x)+(a.y-y)*(a.y-y));}
void points::deplacer(float dx=0, float dy=0){ x=x+dx; y=y+dy;}
points::points(){}
int main() {
points p(2); p.affichage("p ");
points pc1(p);
points pc2; pc2=p;
pc2.deplacer(2,11);
points pc3=p;
p.deplacer(3,33);
p.affichage("p après modification "); pc1.affichage("pc1 "); pc2.affichage("pc2 "); pc3.affichage("pc3 ");
return 0;
}

B.M Cours C++ 38

19
04/12/2023

Destructeurs

Le destructeur est une fonction membre systématiquement exécutée «à la fin de la vie » d’un
objet statique, automatique, ou dynamique. On ne peut pas passer de paramètres par le
destructeur.

Exemple:
Un destructeur de la classe points pourrait se déclarer par :
public:
~points ( ) ;

Et se défini en dehors de la classe par :


points : : ~points( ) { . . . }

B.M Cours C++ 39

Exemple :
#include <iostream>
#include <math.h>
using namespace std;
class points {
private : float x, y;
public :
points(float z);
points();
~points();
void affichage(string s);
void deplacer(float dx, float dy);
};
points::~points(){cout<<"destriction des objets x= "<<x<<" y= "<<y<<endl; }
void points::affichage(string s){ std::cout<<s<<"x= "<<x<<" y= "<<y<<endl; }
points::points(float a){ x= a; y= a; }
void points::deplacer(float dx=0, float dy=0){ x=x+dx; y=y+dy;}
points::points(){}
int main() {
points p(2); p.affichage("p ");
points pc1(p);
points pc2; pc2=p;
pc2.deplacer(2,11);
points pc3=p;
p.deplacer(3,33);
p.affichage("p après modification "); pc1.affichage("pc1 "); pc2.affichage("pc2 "); pc3.affichage("pc3 ");
return 0;
}

B.M Cours C++ 40

20
04/12/2023

Classe canonique

On appelle une classe canonique toute classe qui contient au moins les éléments suivants :
- Au moins un constructeur régulier
- Un constructeur de recopie
- Un destructeur
- Un opérateur d'affectation
class point{ // membres privés
public: point(…); // un constructeur régulier
point(const point&); //un constructeur de recopie
~point(); // un destructeur
Point &operator=(const point&); // opérateur d'affectation
};

B.M Cours C++ 41

• L’opérateur this
Une méthode reçoit toujours implicitement en argument l’adresse de l’objet de sa
classe qui l’a appelée.
Ainsi, pour : pt.affiche() ;
L’adresse de pt est transmise en argument à la fonction affiche. Dans la fonction,
le pointeur sur l’objet qui l’a appelée est désigné par le mot clé this
Exemple pour la classe point déjà définie, les coordonnées de l’objet qui fera
l’appel sont:
x et y ou this->x et this->y
class points {
Exemple d’utilisation pour la classe point
private :
float x, y;
public :
points(float a, float b=2){ x= a; y= b; }
void affichage(string s);
void copier( points p){ this->x+=p.x; this->y+=p.y; }

};
void points::affichage(string s){ cout<<s<<"x= "<<this->x<<" y= "<<this->y<<endl; }
int main() {
points p(2,3); p.affichage("p ");
points pp(4,3); pp.copier(p); pp.affichage("copie ");
return 0;
} B.M Cours C++ 42

21
04/12/2023

Surcharge des fonctions d’une classe

Une méthode peut être surchargée comme toute fonction ordinaire en C++.
Dans la surcharge de fonction, la fonction est redéfinie en utilisant différents types
d’arguments ou un nombre différent d’arguments.
Ce n'est que par ces différences que le compilateur peut différencier les fonctions.
L'avantage de la surcharge de fonctions est qu'elle augmente la lisibilité du
programme car il n'est pas nécessaire d'utiliser des noms différents pour la même
action.

B.M Cours C++ 43

Exemple 1 :
Supposons que nous voulions créer une seule fonction moyenne, pouvant gérer la moyenne de 2
nombres, 3 nombres de types différents, nous ne pouvons le faire qu'en utilisant la surcharge de
la fonction

class Utilitaire {
public:
static float moyenne(int a,int b);
static float moyenne(float a,float b);
static float moyenne(int a,int b,int c);
};
float Utilitaire::moyenne(int a,int b){
return (a+b)/2.0;
}
float Utilitaire::moyenne(float a, float b){
return (a+b)/2;
}
float Utilitaire::moyenne(int a, int b, int c){
return(a+b+c)/3.0;
}
int main() {
cout << "Moyenne (3,4) = " << Utilitaire::moyenne(3, 4) << endl;
cout << "Moyenne (3,4,6) = " << Utilitaire::moyenne(3, 4, 6) << endl;
cout << "Moyenne (6.4,1.25) = " << Utilitaire::moyenne(6.4f, 1.25f) << endl;
return 0;
}

B.M Cours C++ 44

22
04/12/2023

Exercice 1 :
Créer une classe vecteur3d pour représenter un vecteur dans l’espace caractérisé par
ses coordonnées x, y et z,
La classe comporte :
- un constructeur d’initialisation d’un vecteur
- Un destructeur qui affiche un message après la suppression de chaque objet.
- une méthode d’affichage d’un vecteur
- Une méthode qui retourne la norme d’un vecteur (float NormeVect())
- Une méthode qui retourne la somme de deux vecteurs (vecteur3d SommeVect(
vecteur3d v))
- Ajouter une méthode de classe qui effectue elle aussi la somme deux vecteurs.

Écrire un programme principal de test qui crée deux vecteurs, les afficher, calculer et
afficher la norme d’un vecteur, calcule et affiche la somme deux vecteurs.

B.M Cours C++ 45

Fonctions Amies
Déclaration d’amitié
Il peut arriver qu’une fonction n’appartient pas à une classe ait besoin d’accéder à des
données de cette classe. Une façon de procéder serait de déclarer ces données
publiques, mais cela est contradictoire avec la notion de classe, dans la mesure où
l’un des intérêts de l’utilisation des classes est justement de protéger les données.

La solution adoptée par C++ consiste a permettre au concepteur d’une classe de


déclarer que certaines fonctions extérieures à la classe sont des amies de cette classe
et sont donc autorisées à ce titre à accéder au données privés de la classe.

B.M Cours C++ 46

23
04/12/2023

- Fonction externe amie d’une classe


La déclaration d’amitié est introduite dans la classe par :
friend type nom-fonction(arguments) ;
La fonction est une fonction externe standard.
Remarque: La fonction main ne doit pas déclarer la fonction externe coïncide car celle-ci
est déclarée dans la classe point.
Exemple: fonction amie d’une classe
#include <iostream>
using namespace std;
class point {
int x,y;
friend void exemple (point&);
public:
point(int x=0, int y=1){
x=x; y=y;
}
};
void exemple (point& a) { // accès direct à i qui est membre données privées.
cout <<"le point ("<< a.x<<","<<a.y<<")"<<endl;
}
int main() {
point y;
exemple(y);
return 0;
}
B.M Cours C++ 47

Exercice :
Soit une classe point qui comporte comme membres donnés les coordonnées du point
dans le plan, et comme membres fonctions le constructeur et une fonction affiche..
Ajouter une fonction externe amie de la classe point, qui reçoit deux arguments de type
point et renvoie un boolean qui vaut true si les deux points coïncident et false si non.
Ecrire un programme principal d’essai

B.M Cours C++ 48

24
04/12/2023

- Fonction membre d’une classe, amie d’une autre classe


Exemple:
using namespace std;
class point; // déclaration de la classe point, le compilateur sait que la classe point existe.
class B {
public:
void exemple (point&);
};
// définition de la classe point
class point {
float x,y;
friend void B::exemple (point&);
public: // constructeur qui initialise x et y.
point(float a=100, float b=2){x=a; y=b;}
};
void B::exemple (point &p) { cout <<"le point ("<< p.x<<"," <<p.y<<")"<< endl; }
int main() {
point p(3); B y;
y.exemple(p); // en sortie: point (3,2)
return 0;
}

B.M Cours C++ 49

Surdéfinition des Opérateurs


• Le langage C++ autorise l’utilisateur à étendre la signification d’opérateurs tels que l’addition
(+), la soustraction (-), la multiplication (*), la division (/), le ET logique (&) etc... celui-ci
s’applique à un objet non standard.
• Pour cela on associe à cet opérateur une fonction qui décrit l’action spécifique à réaliser
lorsque l’opérateur s’applique à cet objet on dit qu’on a surdéfini cet opérateur.
• La fonction associé à l’opérateur peut être soit une fonction indépendante, amie de la classe
qui définie l’objet auquel s’applique l’opérateur, soit une fonction membre de la classe.
• Le nom de la fonction est le symbole standard, précédé du mot clé operator.

Exemple :
Redéfinition de l’opérateur + : Le nom de la
la fonction est déclaré par : fonction
type operator + (arguments) {
……..
}

B.M Cours C++ 50

25
04/12/2023

exemple:
Opérateur d'affectation =

Chaque classe possède un opérateur d'affectation par défaut.


L'affectation est superficielle comme la copie et consiste en une affectation (de
surface) membre à membre.
Ceci pose les mêmes problèmes que ceux posés par le constructeur de recopie par
défaut (voir les précédents paragraphes).

Un opérateur d'affectation sert donc à l'affectation dans une expression et, retourne
une référence. La signature de cet opérateur est comme suit :
objy& operator=(objx)
Ceci est équivalent d'écrire :
y=x ou bien y.operator=(x)

B.M Cours C++ 51

Exemple:
using namespace std;
class points {
private :

public : float x, y;
points(float a, float b=2){ x= a; y= b; }

void affichage(string s);


void operator+=(const points p){ x+=p.x; y+=p.y; }
int operator==(const points p){
if( x==p.x && y==p.y)
return 0;
else return 1;
}
void affichage(string s){ std::cout<<s<<"x= "<<x<<" y= "<<y<<endl; }
};

points::points(float a)
int main() {
points p(2);
p.affichage("p ");
points pp(3); pp+=p;
pp.affichage("pp ");
int i= pp==p;
if (i==0) cout <<"les deux points sont confondus ";
else cout <<" les deux points ne sont pas confondus";
return 0;
}

B.M Cours C++ 52

26
04/12/2023

Règles concernant la surdéfinition des opérateurs


• Seuls les opérateurs standards peuvent être surdéfinis

• Tous les opérateurs peuvent être surdéfinis sauf l’opérateur ∙

• les règles de priorité et d’associativité sont les mêmes que pour les opérateurs
standards

• Les opérateurs new, delete, [ ], ( ), -> ne peuvent pas être surdéfinis par des
fonctions externes, mais uniquement par des fonctions membres.

B.M Cours C++ 53

- Surcharge de l'opérateur d'indexation []


Telle quelle, la classe String se présente à l'utilisateur sous une forme totalement déconnectée
de l'utilisation habituelle (i.e. suite contiguë de caractères).

On veut maintenant donner à l'utilisateur la possibilité d'accéder au i-ième caractère de


toute String; ceci suppose donc qu'il y ait un minimum de vérifications (non-débordement).

1.Effectuer la surcharge de l'opérateur d'indexation ([]), alias operator[], dont la signature est :

char& operator[] (int i);


Remarquer que l'opérateur retourne une référence à un caractère, ce qui permet l'accès en
lecture comme en écriture.
2.Après avoir ajouté cette déclaration dans ``str.h'', écrivez la définition correspondante dans
``str.cc'', et testez votre travail dans ``teststr.cc'' sur la portion de code 4 :

... { String s5("ello"); cout << s5 << endl; ... cout << s5 << endl; } cout << "fin de code 4\n"; // ...
Avez-vous bien pensé à vérifier les débordements ?

B.M Cours C++ 54

27
04/12/2023

Opérateur d’indexation [ ]

• Il n’est pas possible d’accéder directement depuis une fonction utilisatrice à un élément d’un
tableau déclaré privé dans une classe (ne sont pas accessibles directement). Sans définition
une fonction avec un nouveau nom.
• La solution c’est de surdéfinir l’opérateur d’indexation [ ].
• La fonction de surdéfinition doit recevoir en argument le rang de l’élément. Elle renvoie sa
valeur.
• Si l’on veut pouvoir faire figurer l’élément à gauche d’un signe=, il faut utiliser la transmission
par référence pour l’argument de retour.
• On ne peut pas ici avoir recours à une fonction externe avec déclaration d’amitié.
Exemple:
class Tableau{
int * a ;
int nmax ;
public :
…};

B.M Cours C++ 55

Exemple:
using namespace std;
class Vecteur {
private:
int n;
int *a;
public:
void affiche(){
cout<<" liste "<<endl;
for (int i = 0; i < n; i++) cout<<" "<<a[i];
}
Vecteur(int t, int val) {n=t; a=new int [n];
for (int i=0; i<n;i++) a[i] = val;
}
int& operator[](int i) { return a[i];}
};

int main() {
const int N = 4;
Vecteur u(N, 7);
Vecteur v(N, 5);
for (int i = 0; i < N; i++)
v[i] += u[i];
v.affiche();
return 0;
}
B.M Cours C++ 56

28
04/12/2023

Exercice :

Donner un programme complet pour la classe vecteur ci- dessus,


en la dotant d’un constructeur, d’un destructeur, d’une fonction
de remplissage, d’une fonction d’affichage et de la fonction de
surdéfinition de [].
La fonction utilisatrice double les éléments de rang impair.

B.M Cours C++ 57

B.M Cours C++ 58

29
04/12/2023

Allocation dynamique

Lorsque les membres données d’une classe sont des pointeurs, le constructeur est
utilisé pour l’allocation dynamique de mémoire sur ce pointeur.
Pour certaines applications, on n’est pas capable de définir la taille d’un tableau au
moment de la compilation (exemple : tableau de mesures). La taille effective est fonction
d’un contexte d’éxécution. En conséquence, une allocation dynamique s’impose.
Les éléments du tableau seront accessibles via un pointeur qui sera une donnée
membre privée. Le destructeur est utilisé pour libérer la place. Il est obligatoire et doit
être pris en charge par le programmeur.

B.M Cours C++ 59

Exemple:
class tableau {
float *tab; int n;
public: // constructeur qui initialise x et y.
tableau(int m);
void lecture();
void affiche();
};
tableau::tableau(int m){
tab=new float[m]; n=m;
}
void tableau::affiche(){
cout<<"les éléments du tableau sont :"<<endl;
for(int i=0;i<n;i++)
cout<<" "<<tab[i];
}
void tableau::lecture(){
cout<<"entrer les éléments du tableau :"<<endl;
for(int i=0;i<n;i++)
cin>>tab[i];
}
int main() {
tableau pt(4);
pt.lecture();
pt.affiche();
return 0; B.M Cours C++ 60
}

30
04/12/2023

Refaire l’exercice Exercice 1 :


Créer une classe vect3d pour représenter un vecteur dans l’espace caractérisés par ses
coordonnées x, y et z :
Et comporte un constructeur et une méthode d’affichage

- Ajouter une méthode d’instance permettant de tester si deux vecteurs coïncident


-Ajouter une méthode qui retourne 0 si les vecteurs sont linéaires et 1 si ils sont perpendiculaires
et -1 sinon.
Soit 𝑢=(a,b) et 𝑣=(c,d).
- Deux vecteurs sont orthogonaux si et seulement si :
𝑢⋅𝑣=0
⇒ ac+bd=0
- linéaires si : il existe k tel que 𝑢 = k𝑣
Écrire un programme principal de test qui crée deux vecteurs les affichent et fait appel aux
différentes fonctions.
B.M Cours C++ 61

Exercice2
Créer une classe Etudiant permettant de représenter un étudiant caractérisé par des attributs
privés qui sont : nom, prénom et un tableau de dynamique de notes.
La classe comporte un constructeur qui accepte en argument le nombre de notes et qui permet
de lire au clavier le nom, prénom et les notes ,
• le destructeur si nécessaire
• une méthode affiche() pour afficher les différents attributs
• Une méthode qui parmi deux étudiants, affiche celui ayant la moyenne la plus grande
• Ecrire par ailleurs, un petit programme (main) de test

B.M Cours C++ 62

31
04/12/2023

Variables statiques dans une classe :


Les variables statiques d'une classe sont partagées par les objets. Il ne peut pas y avoir plusieurs
copies des mêmes variables statiques pour différents objets.
C'est également pour cette raison que les variables statiques ne peuvent pas être initialisées à l'aide
de constructeurs.

using namespace std;


class variablestatic{
public:
static int i;
variablestatic(){}
};
int variablestatic::i=0;
int main() {
variablestatic obj1;
variablestatic obj2;
cout << variablestatic::i<<endl;
obj1.i =2;
cout << obj1.i<<endl;
obj2.i = 3;
cout <<obj2.i<<endl;
return 0;
}

B.M Cours C++ 63

Fonctions membres static d’une classe :


Les fonctions membres statique () appartiennent à la classe, c'est-à-dire à tous les objets.
Les fonctions membres ne pourront accéder qu'aux données statiques de l'objet .

Exemple:
class Entier {
public:
static int i;
static int get_value(void);
static void affiche(int a);
};
int Entier::i=3;
int Entier::get_value(void) { return i; }
void Entier::affiche(int a){ cout<<"la valeur est "<<i<<endl;}
int main(void) { // Appelle la fonction statique get_value :
int rs=Entier::get_value();
Remarque:
Entier::affiche(rs);
Entier E1,E2; - Le lieu naturel de la définition des variables membre statiques est le
E1.i++; fichier .cpp qui contient la définition des fonctions membre, et non le
Entier::affiche(E1.i); fichier .h définissant la classe elle-même.
E2.i=-1; - La définition d’une méthode statique se fait sans mentionner le mot
Entier::affiche(E2.i); static
return 0; - l’initialisation des variables static se font sans le mot static,
} nomdelaclasse::variablestatic=3333;

B.M Cours C++ 64

32
04/12/2023

Exercice:
Réaliser une classe nommée entier dont les membres données sont :
L’entier
Le compteur d’objets construits (variable statique entière)
Les fonctions membres sont :
Le constructeur, le destructeur, une fonction d’affichage et une fonction statique qui fournit le
nombre d’objets construits.

B.M Cours C++ 65

Héritage
La notion d’héritage est fondamentale en programmation orienté objet. Il s’agit de créer de
nouvelles classes, de nouveaux types, en se basant sur des classes déjà existantes.

L’héritage est en effet la définition d’une nouvelle classe, dite classe dérivée, à partir d’une classe
existante dite classe de base. Cette nouvelle classe hérite les membres non privés de la classe de
base (attributs et méthodes).

L’héritage permet :
• la réutilisation du code déjà écrit
• l’ajout de nouvelles fonctionnalités
• la modification d’un comportement existant (redéfinition)

Une classe peut hériter d’une classe qui peut elle-même hériter d’une autre etc...

Il existe donc une conversion implicite d’une classe fille vers un type de la classe parente.

B.M Cours C++ 66

33
04/12/2023

Héritage Simple
Tout se qui se trouve dans une classe A, et qui n’est pas privée se trouve également dans ses
classes dérivées.

Syntaxe de création d’une classe dérivée:

class B : <public / protected / private > A {


// définition des membres supplémentaires (données ou fonctions)

};
Avec la classe A est supposée déjà crée

Exemple :
Un étudiant est une personne, et a donc un nom (et un prénom, ...). De plus, il a un numéro
CNE.

B.M Cours C++ 67

Exemple 1:

à partir de la classe point que nous avons déjà utilisée (classe de base), nous voulons créer une autre classe
(classe dérivée) en ajoutant un symbole identifiant le point, qui sera une suite de un ou plusieurs
caractères. Nous appelons la classe dérivée Cercle.

La déclaration des membres donnés de la classe dérivée s’écrit :

class Cercle : public point {


int ry ;
Public :
// … fonctions membres propres à la classe dérivée
};

Syntaxe de définition d’un constructeur d’une sous classe


ConstructeurSousClass(liste agument ): ConstructeurSupperClass( arguments){
………
}

Remarque: La classe dérivée Cercle a accès à tous les membres de la classe point qui ne sont pas privées.

B.M Cours C++ 68

34
04/12/2023

Exemple 2:
à partir de la classe point que nous avons déjà utilisée (classe de base), Créer une classe cercle (classe dérivée) en ajoutant
un rayon.
using namespace std;
class points{
private: float x,y;
public: points(float a=0, float b=0){ x=a; y=b; }
void afficher(){ cout<<"le point ("<<x<<","<<y<<") "; }
};
class cercle: public points{
private: float ry;
public: cercle(float r=0,float x=0,float y=0) : points(x,y){ ry=r; }
void afficher(){
cout<<"le cercle de centre ";
points::afficher();
cout<<" et de rayon "<<ry<<endl;
}
};
int main(){
cercle c(3,2,1);
c.afficher();
} B.M Cours C++ 69

Notion de redéfinition

Il ne faut pas mélanger la redéfinition et la surdéfinition :


• Une surdéfinition ou surcharge (overloading) permet d’utiliser plusieurs méthodes qui
portent le même nom au sein d’une même classe avec une signature différente.

• Une redéfinition (overriding) permet de fournir une nouvelle définition d’une méthode
d’une classe ascendante pour la remplacer. Elle doit avoir une signature rigoureusement
identique à la méthode parente.

Un objet garde toujours la capacité de pouvoir redéfinir une méthode afin de la réécrire ou de la
compléter.

B.M Cours C++ 70

35
04/12/2023

Remarques: constructeurs et destructeurs

• Comme une instance de cercles(classe dérivée) est avant tout une instance de points(classe de
base), dans le constructeur de cercles, on crée explicitement l’instance points dans
l’initialisation.
• Le constructeur de points(classe de base) est appelé avant le constructeur de cercles(classe
dérivée).
• les destructeurs sont appelés dans l’ordre inverse (de la clase dérivée à la classe de base)

B.M Cours C++ 71

Appel d’une fonction de base depuis une fonction membre

Une fonction de la classe dérivée peut appeler n’importe quelle fonction (protected, public) de la classe de
base, en utilisant l’opérateur de résolution de portée ::
Nom_classe::nom_fonction(arguments)
Exemple: On prévoit dans la classe dérivée Cercles une fonction d’affichage appelée afficher() qui appelle la
fonction afficher() de la classe points pour afficher le centre et le rayon d’un cercle.
- Cas fonction porte le même nom que la classe de base:
void Cercles::afficher(){
cout<<"le cercle de centre ";
points::afficher();
cout<<" et de rayon "<<ry<<endl;
}

B.M Cours C++ 72

36
04/12/2023

Exemple cas général:


#include <math.h>
using namespace std;
class points{
private: float x,y;
public: points(float a=0, float b=0){ x=a; y=b; }
void afficher(){ cout<<"le point ("<<x<<","<<y<<") "; }
float distance(points b){
float d=sqrt((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y));
return d;
}
};
class cercle: public points{
private: float ry;
public: cercle(float r=0,float x=0,float y=0):points(x,y){ ry=r; }
void afficher(){
cout<<"le cercle de centre ";
points::afficher();
cout<<" et de rayon "<<ry<<endl;
}
};
int main(){
cercle c(3,2,1); points p(4,4); c.afficher();
cout<<"la distance entre le centre du cercle et le point";
p.afficher();
cout<<" est "<<c.distance(p);
B.M Cours C++ 73
}

Types d’héritage:

Mode dérivation Statut dans la classe Statut dans la classe


de base de dérivée
public public
public
protected protected
private inaccessible
public protected
protected
protected protected
private inaccessible
public private
private protected private
private inaccessible

Remarque : Les constructeurs, le destructeur, de même que l’opérateur = de la


classe de base ne sont pas hérités dans la classe dérivée.

B.M Cours C++ 74

37
04/12/2023

Conversion automatique:
Si B hérite de A, alors toutes les instances de B sont aussi des instances de A, et il est donc possible de faire :
A a; B b;
a=b; // affectation acceptée
b=a; // affectation n’est pas acceptée, erreur

Exemple:
class Etudiants : public Personnes{
}
Personnes pers;
Etudiants etud;
pers=etud;

B.M Cours C++ 75

Exercice : (à faire en TP)

Réaliser une classe vecteur d’entiers dont les membres données sont le nombre d’éléments du
vecteur et un pointeur d’entiers.
avec toujours pour fonctions membres
- le constructeur qui reçoit la taille du vecteur qui permet de créer et remplir ce vecteur au
clavier
-Le destructeur (Afficher les adresses des différents objets crées et détruits)
- Une fonction de surdéfinition de [ ]
- Une fonction d’affichage
- La fonction de surdéfinition de l’afféctation
Ecrire un programme principal de test.

B.M Cours C++ 76

38
04/12/2023

Redéfinition d’une fonction de la classe de base

Une classe dérivée peut avoir une fonction membre de même nom que la classe de base et redéfinir
celle-ci.
Toujours la fonction de la classe dérivée fera appel à la fonction de la classe de base en utilisant
l’opérateur de résolution de portée :: et pourra compléter l’action de celle-ci.
Ainsi, au lieu de créer une fonction affichec membre de la classe dérivée, il est préférable de redéfinir
avec le même nom la fonction affiche de la classe point.

B.M Cours C++ 77

Affectation par pointeur


On peut affecter un pointeur sur un objet dérivé à un pointeur sur un objet de base. L’inverse est possible à condition d’utiliser l’opérateur
de cast.
Mais Attention, si par la suite on applique une fonction à l’objet pointé par ce pointeur, c’est la fonction définie dans la classe dérivée qui
s’applique, comme le montre l’exemple ci-dessous :
class point { private: float abs; float ord;
public : point ( float x=0., float y=0.){ abs=x; ord=y;}
void virtual affiche ( ) { cout <<" coordonnees:" <<abs<< " " <<ord << endl; }
};
class pointcar: public point { private: char *sy;
public: pointcar ( float x=0., float y=0., char* c="*" ): point(x,y){
cout <<" passage dans constructeur de pointcar"<<endl; sy= c;}
void affiche();
};
void pointcar::affiche(){ point::affiche();
cout<<"identificateur: "<<sy<<endl;
}
main ( ) {
point x(-0.5,3.), *px;
pointcar a(1.5, 2,"A"),*pa;
px=&x;
pa=&a; // Autorisé.
px=pa;// Autorisé. Les données et les méthodes de la classe fille ne sont plus accessibles avec ce pointeur : *px est un objet de la classe mère.
//pa=&x; // ILLÉGAL : il faut faire un transtypage (cast)
pa=(pointcar *) &x;// Cette fois, c'est légal, mais DANGEREUX !, En effet, les méthodes de la classe filles
// ne sont pas définies, puisque m est une classe mère.
pa->affiche ( ); a.affiche ( );
return 0;
}
B.M Cours C++ 78

39
04/12/2023

Appel d’une fonction de base par un objet dérivé


Une fonction de base peut être appelée par un objet d’une classe dérivée. En effet, il y a conversion implicite de l’objet dérivé
dans le type de base.
• Typage statique des objets
Les règles de compatibilité entre une classe de base et une classe dérivée permettent d’affecter à un pointeur sur un objet de
base la valeur d’un pointeur sur un objet dérivée.
Toutefois, par défaut, le type des objets pointés en C++, est déterminé à la compilation. C’est ce qu’on appelle le typage
statique.
Par exemple, avec :

class A class B: public A


{ ... { ...
public : public :
void fct(…); void fct(…);
… …
}; };
A *pta;
B *ptb;
pta=ptb // est autorisée.
Néanmoins: pta->fct(…) appelle toujours la fonction fct de la classe A. (pta est toujours considéré comme un pointeur sur A).
Lorsqu’une fonction est appelée, le type d’objet est alors considéré être celui qui est déclaré dans la fonction utilisatrice, et
non pas son type effectif .on dit que le type des objets pointés est déterminé à la compilation.
Il serait intéressant de pouvoir déterminer le type d’un objet à l’exécution. Ceci permettrait d’affecter à un objet pointé son
type effectif et non pas son type déclaré.
Ceci est possible en C++ grâce au mécanisme des fonctions virtuelles. On parle alors du typage dynamique (ou
polymorphisme).
B.M Cours C++ 79

Typage dynamique et fonctions virtuelles

On souhaite que, lorsqu’une fonction d’une classe est appelée, la fonction s’applique à l’objet effectif, et non pas à
l’objet déterminé à la compilation. C’est ce que l’on appelle le polymorphisme.
Pour cela, il suffit de déclarer la fonction virtuelle dans la classe de base.
Par exemple, si l’on a :
class A class B: public A
{ ... { ...
public : public :
virtual void fct(…); void fct(…);
… …
}; };

A *pta;
B *ptb;

Ainsi, si pta=ptb;
pta->fct(…) appelle la fonction fct de la classe B.
• Remarque :
Pour que la liaison dynamique puisse se faire, il faut que la fonction soit appelée par un pointeur et non directement par
l’objet lui-même.

B.M Cours C++ 80

40
04/12/2023

Reprenons le même exemple en donnant l’attribut virtual à la fonction affiche() dans la classe
de base point.

# include < iostream.h>


class point {
private: float abs ; float ord ;
public :
point ( float x=0., float y=0.){
abs=x ; ord=y ;}
void virtual affiche ( ) {
cout <<" coordonnees : " <<abs<< " " <<ord << endl ; }
};
class pointcar : public point {
private: char * sy ;
public:
pointcar ( float x=0., float y=0., char* c=" *" ): point(x,y){
cout <<" passage dans constructeur de pointcar"<<endl;
sy= c ;}
void affiche() ;
};
void pointcar ::affiche(){
point ::affiche() ;
cout<<identificateur<<sy<<endl ;
}
B.M Cours C++ 81

// fonction utilisatrice

main ( ) {
pointcar a(1.5, 2, "A") ;
point x(-0.5,3.) ;
pointcar *b=&a ;
point * y=&x ;
y=b; b->affiche ( ); y->affiche ( );
}
Le résultat est le suivant :
Coordonnées : 1.5 2
Identificateur : A
Coordonnées : 1.5 2
Identificateur : A
Ici, le type effectif de b est point avant affectation, son type devient pointcar
suite à l’affectation y=b.

B.M Cours C++ 82

41
04/12/2023

HERITAGE MULTIPLE
Principe : une classe peut dériver de plusieurs classes.
Dérivation à partir de plusieurs classes
• Déclaration d’une classe dérivée de plusieurs classes
Soient deux classes A et B déclarées par :
class A { class B {
... }; ...};
Pour définir une nouvelle classe C qui dérive de A et B, on la déclare par :
class C : public A, public B{
... } ;
Soit les classes Salaire et Identificateur suivantes :

class Salaire { class Identificateur {


double S ; char* Nom
public : public :
Salaire(double) ; Identificateur(char*) ;
... }; ...};

Nous pouvons créer une classe employé caractérisé par le nom de l’employé et son salaire en la dérivant à partir des
deux classes précédentes.

Syntaxe de déclaration :
class Employé : public Salaire, public Identificateur{
... } ;
B.M Cours C++ 83

Constructeur pour la classe dérivée


Comme pour les dérivations simples, les constructeurs des classes de base sont appelés dans l’ordre où ils sont déclarés
dans la classe dérivée.
Le constructeur de la classe dérivée Employé déclarée ci-dessus peut s’écrire :

Employé : : Employé( double a=0, char * c= " ") : Salaire(a), Identificateur(c) {


cout << " passage dans constructeur de Employé"<<endl ;}

Redéfinition de fonctions définies dans les classes de base


Exemple : Redéfinition de la fonction affiche dans la classe employé : celle-ci n’a rien d’autre à faire que d’appeler
successivement les fonctions affiche des classes Salaire et Identificateur. On peut l’écrire :

void Employé : : affiche ( ) {


Salaire : : affiche ( ) ; Identificateur : : affiche( ) ;}

Exercice
Donnez programme complet de définition et d’utilisation de la classe Employé à partir des classes Salaire et
Identificateur (avec les constructeurs et les fonctions d’affichage)

B.M Cours C++ 84

42
04/12/2023

Désignation des membres données

Si des membres donnés des classes de base accessibles, portent le même nom dans plusieurs classe de base, cela ne pose pas
de problème. Il suffit d’utiliser l’opérateur de résolution de portée : : pour spécifier la classe dans laquelle il faut prendre
l’objet. Ainsi :
A : : x désigne un objet x membre de la classe A
B : : x désigne un objet x membre de la classe B

Exemple:
Donnons aux membres de la classe Salaire et de la classe Identificateur le statut protected et introduisez dans la classe
Employé une fonction coïncide qui renvoie un bool valant true si 2 employés possèdent le même nom et même salaire, et
false sinon. Nous supposons que le nom du membre donné de la classe Salaire est x , et le nom du membre donnée de
Identificateur est aussi x. Ecrire le programme complet.

B.M Cours C++ 85

Classes Virtuelles

Problème de la duplication de données


Il peut arriver qu'une classe dérive de plusieurs classes qui dérivent elles-mêmes d'une même
classe de base. Dans ce cas, les membres de la classe de base vont apparaître plusieurs fois dans
la dernière classe obtenue par dérivation.
Exemple:

On dit que D hérite deux fois de A, les membres donnés seront


dupliqués dans tous les objets de type D.

B.M Cours C++ 86

43
04/12/2023

Déclaration de classes:
class B : public A class C : public A
{ ... }; {...};

class D : public B , public C { . . .} ;

Lorsqu’on crée un objet de type D, Les constructeurs sont appelés dans l'ordre
suivant:

- constructeur de A avec la liste d'arguments passés par B


-constructeur de B avec la liste d'arguments passés par D
-constructeur de A avec la liste d'arguments passés par C
-constructeur de C avec la liste d'arguments passés par D
-constructeur de D

On voit qu'il y a bien construction de deux objets de type A

B.M Cours C++ 87

Solution: Introduire classe virtuelle


Pour les méthodes, cela ne présente pas d'inconvénient majeur,
car les fonctions sont générées à la compilation et leur code est introduit une seule fois à l'édition de liens. Il n'y a
donc pas de duplication. Mais les attributs, eux, sont réellement dupliqués.

Le C++ permet de n'incorporer qu'une seule fois les données. Il suffit pour cela de déclarer dans les classes B et C
que la classe A est virtuelle. On spécifie tout simplement l’attribut virtual dans les déclarations des classes B et
C. On écrira:

class B : public virtual A class C : public virtual A


{ ... }; {...};

class D : public B , public C { . . .} ;

L'attribut virtual n'a pas d'effet sur les classes B et C, mais uniquement sur les descendants éventuels de B et C.

B.M Cours C++ 88

44
04/12/2023

Dans ce cas de classe virtuelle il ya des changements au niveau d’appel de constructeurs


• On évite d'appeler deux fois le constructeur de A, d'abord depuis B, puis depuis C.
• Le C++ traite les choses de la façon suivante:
les classes où une classe est déclarée virtuelle n'appellent pas le constructeur de la classe virtuelle.

Les constructeurs seront déclarés ainsi :


A: :A(arg) {...} pour la classe A
B::B(arg) {...} pour la classe B
C::C(arg) {...} pour la classe C
D::D(arg) : A(arg), B(arg), C(arg) {...} pour la classe D

Ils sont appelés dans l'ordre suivant:


- constructeur de A avec les arguments passés par D
-constructeur de B avec les arguments passés par D
-constructeur de C avec les arguments passés par D
-constructeur de D

B.M Cours C++ 89

Exercice:
• Ecrire une classe étudiant caractérisée des attributs nom, prenom code et d’une moyenne, un constructeur,
• une classe Enseignant caractérisée par le nom, prenom, le nombre d’heure enseignées et un taux horaire. Et comporte
un constructeur
• Certains étudiants peuvent effectuer des enseignements
(vacations). En utilisant l'heritage multiple, Ecrire, une classe
etudiantVacataire heritant de Enseignant et etudiant et comporte un
constructeur.
• Ecrire un programme principal de test

B.M Cours C++ 90

45

Vous aimerez peut-être aussi