Académique Documents
Professionnel Documents
Culture Documents
ORIENTÉE OBJET:
HÉRITAGE
LAWSON Latevi Sena
PLAN
○ Introduction
○ Les différents spécificateurs
○ Héritage simple
○ Utilisation des membres de la classe de base
dans une classe dérivée
○ Redéfinition des données membres
○ Redéfinition et surdéfinition de fonctions
membres
○ Héritage multiple
○ Classes virtuelles
○ Fonctions virtuelles
○ Classes abstraites
●
INTRODUCTION
● Caractéristiques (suite)
○ Les membres privés de la classe Base sont
inaccessibles à la fois aux fonctions membres et aux
fonctions amies de la classe Derivee ainsi qu’aux
utilisateurs de cette classe Derivee.
○ En cas d’une nouvelle dérivation, tous les membres
de la classe Base conservent dans la classe Derivee
le statut qu’ils avaient dans la classe Base.
#include <iostream>
HÉRITAGE AVEC SPÉCIFICATEUR PUBLIC
using namespace std;
class BaseClass {
public:
int public_data;
protected:
int protected_data; int main() {
private: DerivedClass d;
int private_data; d.public_data = 10;
}; d.printData();
return 0;
class DerivedClass : public BaseClass { }
public:
void printData() {
cout << public_data << endl;
cout << protected_data << endl;
// cout << private_data << endl; // Error,
private_data is not accessible
}
};
HÉRITAGE AVEC SPÉCIFICATEUR PUBLIC
Tableau récapitulatif des caractéristiques
HÉRITAGE AVEC SPÉCIFICATEUR PRIVATE
● Syntaxe :
class Derivee : private Base{ . . . } ;
Syntaxe :
class Derivee : protected Base{ . . . } ;
● La dérivation protégée se trouve entre la dérivation de spécificateur public et celle de spécificateur private.
● l'héritage avec le spécificateur protected signifie que les membres publics et protégés de la classe de
base sont hérités comme des membres protégés dans la classe dérivée.
● Les membres privés de la classe de base ne sont pas directement accessibles dans la classe dérivée.
#include <iostream>
using namespace std;
HÉRITAGE AVEC SPÉCIFICATEUR PROTECTED
class BaseClass {
public:
int public_data;
protected:
int protected_data;
private: int main() {
int private_data; DerivedClass d;
}; // d.public_data = 10; // Error,
public_data is not accessible
class DerivedClass : protected BaseClass { d.printData();
public: return 0;
void printData() { }
cout << public_data << endl;
cout << protected_data << endl;
// cout << private_data << endl; // Error,
private_data is not accessible
}
};
HÉRITAGE AVEC SPÉCIFICATEUR PROTECTED
HÉRITAGE SIMPLE
On parle de l’héritage simple lorsque la
La classe pointcol ainsi définie, nous pouvons déclarer des objets de type pointcol de manière usuelle :
pointcol p, q ;
Chaque objet de type pointcol peut alors faire appel :
aux méthodes publiques de pointcol (ici colore) ;
aux méthodes publiques de la classe de base point (ici initialise, deplace et affiche).
HÉRITAGE SIMPLE
Exemple de fonction main
main() {
pointcol p ;
p.initialise (10,20) ;
p.colore (5) ;
p.affiche () ;
p.deplace (2,4) ;
p.affiche () ;
}
UTILISATION DES MEMBRES DE LA CLASSE BASE DANS LA CLASSE DÉRIVÉE
En C++, les membres de la classe de base peuvent être utilisés dans la classe dérivée. Cependant, l'accès à ces membres
dépend du spécificateur de visibilité utilisé lors de l'héritage.
Lorsque la classe dérivée hérite de la classe de base avec le spécificateur public, les membres publics et protégés de la
classe de base peuvent être directement accessibles depuis la classe dérivée.
Lorsque la classe dérivée hérite de la classe de base avec le spécificateur private, les membres publics et protégés de la
classe de base ne peuvent être accédés que par les fonctions membres de la classe de base.
Lorsque la classe dérivée hérite de la classe de base avec le spécificateur protected, les membres publics et protégés de la
classe de base peuvent être accédés par les fonctions membres de la classe dérivée, mais ne peuvent pas être accédés
directement.
UTILISATION DES MEMBRES DE LA CLASSE BASE DANS LA CLASSE DÉRIVÉE
En C++, la redéfinition des membres d'une classe dérivée consiste à définir une nouvelle
version d'un membre hérité d'une classe de base dans la classe dérivée. Cela permet de
personnaliser le comportement du membre dans la classe dérivée en fonction de ses
besoins spécifiques. La redéfinition est effectuée en utilisant le même nom de membre que
dans la classe de base, avec une nouvelle implémentation.
Il est important de noter que la redéfinition n'affecte pas la définition originale dans la
classe de base. Les objets de la classe de base continuent d'utiliser la définition originale,
tandis que les objets de la classe dérivée utilisent la définition redéfinie. La redéfinition
peut également inclure un appel à la version originale du membre en utilisant la syntaxe
suivante : ClassName::memberName(arguments).
REDÉFINITION
#include <iostream>
DES MEMBRES D' UNE CLASSE DÉRIVÉE
using namespace std;
class Shape {
public:
virtual void draw() { int main() {
cout << "Dessin d'une forme Shape *shape = new Shape();
générale" << endl; Circle *circle = new Circle();
}
}; shape->draw();
circle->draw();
class Circle : public Shape {
public: return 0;
void draw() { }
cout << "Dessin d'un cercle" << endl;
}
};
REDÉFINITION DES MEMBRES D' UNE CLASSE DÉRIVÉE
Redéfinition
des fonctions membres
d’une classe dérivée
Dansle dernier exemple de classe pointcol,
nous disposions à la fois :
🞆 dans point, d’une fonction membre nommée affiche ;
🞆 dans pointcol, d’une fonction membre nommée affichec.
main()
{
pointcol p ;
p.initialise (10,20,5) ;
p.affiche () ;
p.point::affiche () ; // pour forcer l’appel de affiche de point
p.deplace (2,4) ;
p.affiche () ;
p.colore (2) ;
p.affiche () ;
}
REDÉFINITION DES MEMBRES D' UNE CLASSE DÉRIVÉE
Ce que nous avons dit à propos de la redéfinition des fonctions membres s’applique tout aussi
bien aux membres données.
La surdéfinition, également appelée surcharge, se produit lorsqu'une classe définit plusieurs méthodes portant le même
nom, mais avec des signatures de méthode différentes. Cela permet à une classe d'avoir plusieurs méthodes portant le
même nom, mais avec des fonctionnalités différentes en fonction des arguments différents fournis.
REDEFINITION ET SURDEFINITION.
La redéfinition et la surdéfinition sont des concepts clés en programmation orientée
objet.
La surdéfinition est un mécanisme qui permet à une classe dérivée d'ajouter de nouveaux
comportements à une méthode héritée sans la redéfinir. La surdéfinition est réalisée en
déclarant une nouvelle méthode avec le même nom que la méthode héritée, mais avec
des arguments différents.
REDEFINITION ET SURDEFINITION.
#include <iostream>
class Vector {
public:
int main() {
int x, y;
Vector a(1, 2), b(3, 4);
Vector c = a + b;
Vector(int x = 0, int y = 0) : x(x), y(y)
{}
std::cout << c.x << " " << c.y << std::endl;
return 0;
Vector operator+(const Vector &v)
}
const {
return Vector(x + v.x, y + v.y);
}
};
REDEFINITION ET SURDEFINITION.
Il va de soi que lorsqu’une fonction est redéfinie dans une
classe dérivée, elle masque une fonction de même
signature de la classe de base.
Mais les choses ne sont pas aussi simples dans le cas de
l’héritage.
Lorsqu’une fonction membre est définie dans une classe,
elle masque toutes les fonctions membres de même nom
de la classe de base (et des classes ascendantes).
Autrement dit, la recherche d’une fonction (surdéfinie ou non)
se fait dans une seule portée, soit celle de la classe
concernée, soit celle de la classe de base.
REDEFINITION ET SURDEFINITION.
Exemple 1 :
class A
{
public :
void f(int n) {cout<<« 1"<<endl; }
void f(char c) {cout<<« 2"<<endl; } // f est surdéfinie dans A } ;
class B : public A
{
public :
void f(float x) {cout<<"3"<<endl; } // on ajoute une troisième définition dans B } ;
main()
{
int n =2; char c='A' ; A a ; B b ;
a.f(n) ; // appelle A::f(int) (règles habituelles)
a.f(c) ; // appelle A::f(char) (règles habituelles)
b.f(n) ; // appelle B::f(float) (alors que peut-être A:f(int) conviendrait) b.f(c) ; // appelle B::f(float) (alors que peut-être
A:f(char) conviendrait)
}
REDEFINITION ET SURDEFINITION.
Exemple 2 :
class A
{
public :
void f(int n) { ..... } // f est surdéfinie void f(char
c) { ..... } // dans A
};
class B : public A
{
public :
void f(int n) { ..... } // on redéfinit f(int) dans B } ;
main()
{
int n=8 ; char c ='A'; B b ;
b.f(n) ; // appelle B::f(int)
b.f(c) ; // appelle B::f(int)
}
REDEFINITION ET SURDEFINITION.
Exemple 3 :
class A //Solution correcte main()
{
public : {
void f(int n) { ..... } int n ; char c ; B b ; b.A::f(n) ;
void f(char c) { ..... }
}; b.A::f(c) ;
class B : public A }
{
public :
void f(int, int) { ..... }
};
main()
{
int n=4 ; char c ='D'; B b ; b.f(n) ; // erreur de compilation b.f(c) ; // erreur de compilation
}
HÉRITAGE MULTIPLE
HÉRITAGE MULTIPLE 2
class point class coul
Exemple
{{
int x, y ; short couleur ; public : public :
point (...) {...} coul (...) {...} ~point () {...} ~coul ()
{...} affiche () {...} affiche () {...} } ; } ;
Nous pouvons définir une classe pointcoul héritant de ces deux classes en
la déclarant ainsi :
class pointcoul : public point, public coul
{ ... } ;
HÉRITAGE MULTIPLE 3
#include <iostream>
using namespace std ;
class point
{ int x, y ;
public :
point (int abs, int ord)
{ cout << "++ Constr. point \n" ; x=abs ; y=ord ; }
~point () { cout << "-- Destr. point \n" ; }
void affiche ()
{ cout << "Coordonnees : " << x << " " << y << "\n" ; }
};
class coul
{ short couleur ;
public :
coul (int cl)
{ cout << "++ Constr. coul \n" ; couleur = cl ; }
~coul () { cout << "-- Destr. coul \n" ; }
void affiche ()
{ cout << "Couleur : " << couleur << "\n" ; }
};
HÉRITAGE MULTIPLE 4
class pointcoul : public point, public coul
{ public :
pointcoul (int, int, int) ;
~pointcoul () { cout << "---- Destr. pointcoul \n" ; }
void affiche ()
{ point::affiche () ; coul::affiche () ;
}
};
pointcoul::pointcoul (int abs, int ord, int cl) : point (abs, ord), coul (cl)
{ cout << "++++ Constr. pointcoul \n" ;
}
main()
{ pointcoul p(3,9,2) ;
cout << "------------\n" ;
p.affiche () ; // appel de affiche de pointcoul
cout << "------------\n" ;
p.point::affiche () ; // on force l’appel de affiche de point cout << "------------\n" ;
p.coul::affiche () ; // on force l’appel de affiche de coul cout << "------------\n" ;
}
CLASSE VIRTUELLE
Exemple
#include <iostream>
using namespace std;
class A
{
public :
void f(int n) {cout<<"f de A"<<endl;}
};
class B : public A
{
public :
void f(int n) {cout<<"f de B"<<endl;}
};
main()
{
int x ;
A * a;
cin>>x;
if (x==1) a=new A;
else a=new B;
a->f(2); // Quelle est la méthode appelée?
}//Conséquence de la ligature statique i.e fonction déterminée au moment de la compilation.
FONCTION VIRTUELLE
Ainsi de façon générale, on peut avoir besoin de déclarer
explicitement une méthode comme polymorphe. Ceci se
fait :
dans la déclaration de la classe de base, en préfixant la
méthode avec le mot clé virtual. On parle alors de méthode
virtuelle.
//Solution de l’exemple précédent
class A
{
public :
virtual void f(int n) {cout<<"f de A"<<endl;}//f doit être redéfinie dans les classes filles } ;
Ici, il y aura une ligature dynamique. C’est-à-dire que la fonction f qui sera appelée, ne sera déterminée qu’au
moment de l’exécution et tiendra donc compte du vrai type de l’objet sur lequel elle est appelée.
FONCTION VIRTUELLE
Ainsi, si une méthode d’une classe de base
est virtuelle, alors, en cas d’appel de cette
méthode sur un objet d’une classe dérivée,
Sila classe dérivée a implémenté la
méthode, c’est celle-ci qui sera exécutée.
Si la classe dérivée n’a pas implémenté la
méthode, c’est la méthode de la classe de
base qui sera exécutée.
FONCTION VIRTUELLE
Quelques règles
Peuvent être virtual
🞆 Les fonctions membres non statiques.
🞆 Les destructeurs.
Lorsqu'une classe définit une méthode virtuelle, le destructeur
(s'il est défini) doit être obligatoirement virtuel
◉ sinonon risque de n'appeler que le destructeur de la classe mère
alors qu'il s'agit d'un objet de la classe fille.
Ne peuvent pas être virtual
🞆 Les données membres.
🞆 Les constructeurs.
Un constructeur ne peut pas être virtuel et ne peut pas appeler
de méthode virtuelle.
CLASSE ABSTRAITE
Une classe abstraite n'existe que pour être héritée.
Une classe est dite abstraite si elle contient au
moins une fonction virtuelle pure.
Ainsi pour rendre par exemple la classe A de l’exemple
précédent abstraite, on aura :
class A
{
public :
virtual void f(int n)=0;//f est une fonction virtuelle pure. Ainsi, f doit être définie //dans les classes
filles
};
CLASSE ABSTRAITE
Créer une classe ordinateur dérivant publiquement des classes moniteur et carte_mere et qui contient :
les données membres : nom (chaînes de caractères), hd (int), lecteur (float)
unconstructeur initialisant les données membres
unefonction montrer_ordinateur qui affiche les informations sur l’ordinateur et appelle les fonctions
montrer_moniteur et montrer_carte.
Créer un programme principal qui crée un objet ordinateur et qui affiche les informations sur cet objet.
Remplacer les fonctions montrer_moniteur, montrer-carte et montrer_ordinateur par 3 fonctions appelées montrer. Faire
les modifications nécessaires au bon fonctionnement du programme.