55
Structures de données IFT-2000 Abder Alikacem Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Embed Size (px)

Citation preview

Page 2: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Plan

L’héritage public protected private

Construction des objets Destruction des objets Liaison dynamique Classe abstraite Héritage multiple Résumé et synthèse

Page 3: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Programmation orienté objet

1 classe = 1 module

Parties privée et publique des classes

Interface de la classe = type abstrait + généricité (templates)

Héritage

Modularité

Encapsulation

Abstraction

Extensibilité

Page 4: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Pourquoi Hériter ?

Relier des objets entre eux (famille)

Factoriser des traitements (Réutilisabilité)Représenter le centre de la figure (généralisation)

IDENTIFICATION DES OBJETSUn cercle (rayon) ne « ressemble » pas à un rectangle (diagonale)

Faciliter l ’extension l’application (Extensibilité)On traite les ellipses

Page 5: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Comment Hériter ?

GESTION D’UNE

HIERARCHIE DE CLASSES

FactorisationToute figure géométrique a un centre

Spécialisation

(un objet est un cas particulier d ’un autre objet)

Un carré est un cas particulier de rectangle

Enrichissement (un objet a des propriétés propres)Un triangle rectangle comprend le calcul de

l’hypoténuse

Page 6: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Relation d’héritage

La classe D hérite de la classe M

MClasse mère

DClasse dérivée

Héritage simple :Un unique ascendant direct

Page 7: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

L’héritage

class X: <mode> Y {

…}

publicprotectedprivate

Mode

Syntaxe Mode Ancètre Dérivée

Private Private Inaccessible Protected Private Public Private

Protected Private Inaccessible

Protected Protected Public Protected

Public Private Inaccessible Protected Protected Public Public

Page 8: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Héritage « public »

L’héritage

Les classes dérivées héritent de la classe mère en se spécialisant Les membres public de la classe mère deviennent des membres public des classes dérivées. Les classes dérivées peuvent avoir des membres supplémentaires. (enrichissement)

Héritage public Relation : « est une sorte de »

Page 9: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

L’héritage « public »

class M

{public :void f(void);

void g(void);

private:...

};

class D:

{public :

Méthodes redéfinies : void f(void);

Méthodes supplémentaires :

void h(void);

private: Caractéristiques supplémentaires };

public M

Une instance W de la classe D a accès àla section public des classes D et M

Page 10: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

L’héritage « public »

class M

{public :...

protected :

private:

};

class D:

{public :

...

private:

Caractéristiques supplémentaires

};

public M

Pour la classe D : les membres de la section protected de la classe mère M sont accessibles par ses fonctions membres et fonctions amies

Pour la classe M : les membres de la section protected se comportent comme s’ils étaient placés dans sa section private.

Page 11: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

L’héritage « public »

class M{public :

protected:

private :

};

class D :{public :

protected:

private :

};

public M

Partie inaccessiblehéritée

Page 12: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

L’héritage « public »

class M

{public :...

protected :

private:

};

class D:

{public :

...

private:

Caractéristiques supplémentaires

};

public M

(ex: fonction main) accès aux sections public des classes M et D

Vision utilisateur

accès aux sections public et protected de la classe M

Classe D

Page 13: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

L’héritage « public »

class M

{public :...

protected :

private:

};

class D:

{public :

...

private:

Caractéristiques supplémentaires

};

public M

Attention : l ’utilisation du qualificateur protected est contraire au principe d ’encapsulation.Si des modifications sont apportées à la section protected de la classe M alors toutes les classes dérivées qui utilisent l ’accès direct à cette section sont susceptibles de subir des modifications.

Page 14: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

class X{public: int x1;protected: int x2;private: int x3;};

X x;

cout << x.x1 << endl;cout << x.x2 << endl; //NONcout << x.x3 << endl; //NON

class Y : public X {public:

Y() { x1 = 0; //public x2 = 0; //protected

x3 = 0; //NON }

};

Y y;

cout << y.x1 << endl;cout << y.x2 << endl; //NONcout << y.x3 << endl; //NON

Résumé

L’héritage « public »

Page 15: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

class Y : protected X {public:

Y() { x1 = 0; //protected x2 = 0; //protected

x3 = 0; //NON }

};

Y y;

cout << y.x1 << endl; //NONcout << y.x2 << endl; //NONcout << y.x3 << endl; //NON

Cas de l’héritage « protected »

class X{public: int x1;protected: int x2;private: int x3;};

X x;

cout << x.x1 << endl;cout << x.x2 << endl; //NONcout << x.x3 << endl; //NON

L’héritage

Page 16: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

L’héritage « private »

La classe D hérite de la classe M

MClasse mère

DClasse dérivée

Héritage privé : La classe D restreint les fonctionnalités de M • Les membres public de la classe mère et protégés de la classe mère deviennent des membres privés des classes dérivées. • Les classes dérivées peuvent avoir des membres supplémentaires.

Héritage privé

Page 17: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

L’héritage « private »

class M{public :

protected:

private :

};

class D :{public :

protected:

private :

};

private M

Partie inaccessiblehéritée

Page 18: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Exemple

L’héritage « private>

class Tableau{public:

Tableau (void); // ConstructeurTableau (const tableau&); //const. par //copie

Tableau& operator=(const tableau&); int& operator [ ](int);~Tableau (void); // Destructeur

private :int * T;int nb; // nombre d’elements

};

class Pile:private Tableau

{public:

Pile (int n); // Constructeur

void empiler (int) ;

int depiler (void);

int ValSommet (void);

bool vide (void);

~Pile (void); // destructeur

private :

int sommet;

};

Page 19: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Suite… Utilisation d’une pile

L’héritage « private>

int main()

{ Pile p(10);

p.empiler(3);

p [2] = 9;

return 0;

}

Vision utilisateurclass Pile: private Tableau

{public:

Pile (int n);// Constructeur

void empiler (int) ;

int depiler (void);

int valSommet (void);

bool estVide (void);

. . .

};

illégal

Page 20: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Suite… Implémentation

L’héritage « private>

Pile::Pile (int n) {sommet = -1;}

void Pile::empiler (int e)

{sommet += 1;

(*this) [sommet]=e;}

void Pile::depiler (void) {sommet -= 1;}

int Pile::valSommet (void){return (*this) [sommet];}

bool Pile::estVide (void) {return sommet= = -1;}

Page 21: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Résumé

L’héritage « private »

class Y : private X {public:

Y() { x1 = 0; //private x2 = 0; //private

x3 = 0; //NON }

};

Y y;

cout << y.x1 << endl; //NONcout << y.x2 << endl; //NONcout << y.x3 << endl; //NON

class X{public: int x1;protected: int x2;private: int x3;};

X x;

cout << x.x1 << endl;cout << x.x2 << endl; //NONcout << x.x3 << endl; //NON

Page 22: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

L’héritage et le contrôle d’accès

Une classe dérivée dans sa déclaration spécifie de quelle(s) classe(s) elle hérite mais précise aussi le contrôle d'accès des membres hérités : • dans tous les cas, ne peut être accessible dans la classe

dérivée que la partie publique ou protégée de la classe de base

• si l'héritage est public, les membres publics et protégés de la classe de base sont respectivement publics et protégés dans la classe dérivée

• si l'héritage est privé, les membres publics et protégés de la classe de base sont privés dans la classe dérivée

• si l'héritage est protégé, les membres publics et protégés sont protégés dans la classe dérivée.

on peut déclarer une classe dérivée comme friend dans la classe de base, permettant ainsi l'accès à tous les membres de la classe de base.

par défaut, l'héritage est privé pour une class et public pour une struct

Page 23: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Les constructeurs

L’héritage

Lors de la création d ’une instance d ’une classe dérivée son constructeur et tous les constructeurs de ses classes parentes sont activés.

Comme un objet d'une classe dérivée est un objet de la classe de base (classe mère) plus quelque chose, pour construire un objet de la classe dérivée il faut au préalable construire la partie de l'objet correspondant à la classe de base.

Page 24: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Construction des objets

class X{public: int x1;

void a() {…}protected: int x2;private: int x3;};

class Y : public X {public: int x1; //redéfini

int y; //nouveauvoid a() {…} // redéfinivoid b() {…} // nouveauint a() {…} // nouveau

};

L’héritage

Page 25: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Construction des objets

class X{public:

void a() {…} };

class Y : public X {public:

void a() {…} // redéfinivoid b() {

X::a(); // autre classe

a(); //local}

};

Si on veut utiliser une fonction de la classe ancêtre alors qu’elle a étéredéfinie dans la classe dérivée, il faut utiliser l’opérateur de portée « :: »

L’héritage

Page 26: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Construction des objets

class X{public:

X() {cout << ‘x’;} };

class Y : public X {public:

Y() { cout << ‘y’;}};

Lors de la construction d’un objet des constructeurs de toute la hiérarchiedes classes sont appelées dans l’ordre de la hiérarchie « top-down »: les constructeurs sont activés de la racine de l’arbre d’héritage vers les classesdérivées. Activation : d’un constructeur par défaut (qui doit exister) ou bienappel à un constructeur explicite.

class Z : public Y {public:

Z() { cout << ‘z’;}};

int main() { Z z; cout << endl;}

L’héritage

Page 27: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Construction des objets

class X{public:

int i;X(int n) { i = n;}

};

class Y : public X {public:

int j; Y(int n): X(n) { j = n;}

};

S’il n’y a pas de constructeur par défaut spécifié par le programmeur, il faut alors une séquence d’initialisation!!!

class Z : public Y {public:

int k;Z(int n): Y(n) { k = n;}

};

L’héritage

Page 28: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Destruction des objets

class X{public:

~X() { cout << ‘X’;} };

class Y : public X {public:

~Y() {cout << ‘Y’;}};

Lors de la destruction d’un objet, les destructeurs de toute la hiérarchiedes classes sont appelées dans L’ordre de la hiérarchie « bottom-up » : lesdestructeurs sont activés de la classe dérivée vesr la racine de l’arbred’héritage.

class Z : public Y {public:

~Z() {cout << ‘Z’;}

};

int main() { Z z; cout << endl;}

L’héritage

Page 29: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Fonctions surchargées

L’héritage

class M{public :void f(void);void g(void);private :

. . .Protected :};

class D1:

{public :

void f(void);

void h(void);

private:

Caractéristiques supplémentaires

};

class D2:

{public :

void f(void);

void k(void);

private:

Caractéristiques supplémentaires

};

public M public M

Page 30: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Fonctions surchargées (liaison statique)

L’héritage

class M{public :void f(void);void g(void);private :

. . .Protected :}; D1 w1;

D2 w2;

w1.f( );

w2.g( );

Vision utilisateur

class D1:

{public :

void f(void);

void h(void);...};

public M class D2:

{public :

void f(void);

void k(void);

…};

public M

Liaison statique

Comment dans une hiérarchie par héritage, le compilateur sélectionne la méthode polymorphe à exécuter parmi les surcharges incluses dans la hiérarchie de classes ?

Page 31: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Fonctions surchargées. Liaison statique

L’héritage

Résolution de la surcharge par liaison statique

D1 w1;

D2 w2;

w1.f( );

w2.g( );

Vision utilisateurClasse M

ClasseD1

ClasseD2

Le type de W1 est D1, par conséquent le compilateur regarde si la méthode f est dans la classe D1. Si oui, celle-ci est exécutée.Si non, il la recherche dans la première classe ascendante, etc...

Page 32: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Compatibilité de type

L’héritage

class M

{ . . .

};

class D:

{ . . .

};

M* ptrM;D d;

ptrM=&d;

D* ptrD;

M m;

ptrD=&m;

On dit que le type statique(déclaré) de *ptrM est M.On dit que le type dynamique (réel) de *ptrM est D.L’objet pointé par ptrM reste de type D.

Vision utilisateur

public M

Page 33: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Liaison statique des fonctions

L’héritage

class figure

{ public :

void tracer (void) { } //action vide

};

class rectangle:

{ public :

void tracer (void);//rectangle IC est tracé

};

public figure

figure* Ptr;

Ptr = new rectangle();Ptr -> tracer( );

Vision utilisateur

Le type statique de *Ptrest figure. Par conséquent, l’instruction Ptr->tracer( ) active la méthode tracer de la classe figure.

=> Action vide

Page 34: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Polymorphisme

L’héritage

La liaison dynamique est un mécanisme distinct (bien qu'étroitement lié) de l'héritage. C'est le fait qu'un nom de fonction membre d'une classe de base (classe mère) peut être associé à une fonction membre d'une classe dérivée.

Ce mécanisme est essentiel dans la POO. Il permet de reléguer la réalisation d'une fonction membre à un descendant. Le polymorphisme : grâce à la liaison dynamique, un même nom de fonction pourra correspondre à des réalisations différentes suivant les classes dérivées.

Le polymorphisme offre la possibilité d’associer à une méthode un code différent selon l’objet auquel elle appartient.

Exemples : f ou tracer pour les formes géométriques

Page 35: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Liaison dynamique

class X{public:

virtual void a() { cout << ‘X’ << endl;}

};

class Y : public X {public:

virtual void a() { cout << ‘Y’ << endl;}

};

C’est la possibilité donc de ne lier qu’au moment de l’exécution la méthodeà invoquer (pas possible pour les constructeurs).

X x;Y y;

x.a();y.a();x = y;x.a();//?

X *x = new X();Y *y = new Y();

X->a();Y->a();x = y;X->a();//?

L’héritage

Page 36: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Liaison dynamique. Fonctions virtuelles

L’héritage

class figure

{ public :

void tracer (void) { } //action vide

};

class rectangle : public figure

{ public :

void tracer (void);

// instance courante est tracée

};

figure* Ptr;

Ptr = new rectangle( );Ptr -> tracer( );

Vision utilisateur

La fonction tracer est virtuelle.Par conséquent, l’instruction Ptr->tracer( ); active la méthode associée au type dynamique de *ptr.

=>Tracé du rectangle

virtual

virtual

Page 37: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Fonctions virtuelles

L’héritage

Lors de la redéfinition d’une fonction virtuelleLes fonctions virtuelles doivent avoir la même liste de

paramètres.Les types de retour sont égaux ou sont des pointeurs

compatibles.

L’exécution des fonctions virtuelles s’appuie sur une indirection (table de pointeurs de fonctions virtuelles).

Page 38: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Fonctions virtuelles

L’héritage

Classes dérivées Tout comme une fonction ordinaire une fonction virtuelle sert

de fonction par défaut dans les classes dérivées.

Une fonction virtuelle redéfinie dans une classe dérivée reste virtuelle dans la classe dérivée même si cela n’est pas spécifié.

Page 39: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Liaison dynamique

class X{public:

void a() { < cout << ‘X’ << endl;}

};

class Y : public X {public:

void a() { cout << ‘Y’ << endl;}

};

Que se passe-t-il sans « virtual » ?

X *x = new X();Y *y = new Y();

X->a();Y->a();x = y;X->a();//?

L’héritage

Page 40: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Classe abstraite

L’héritage

Une classe abstraite est une classe

qui ne peut pas être instanciée.

Exemple : l’instanciation de la classe figure n’a pas de sens.

class figure

{ public :

void tracer(void) ;

};

Une classe abstraite est une classe qui contient au moins une méthode virtuelle pure, ou qui n'a pas redéfinit une

méthode virtuelle pure.

virtual =0//méthode virtuelle pure

Une méthode virtuelle pure est une méthode virtuelle dont le corps est explicitement non donné, on précise un =0 a la fin du prototype d'une telle méthode.

Page 41: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Méthode virtuelle pure

L’héritage

Une classe abstraite est une classe dont aucun objet de ce type ne peut être créé. Ainsi l'abstraction de la classe se propagera dans les classes dérivées tant que la(les) méthode(s) virtuelle(s) pure(s) n'auront pas été redéfinie(s). Cela est relativement pratique dans le cas d'une classe définissant un concept général, et non une classe en elle même.

Lorsqu'une classe définit une méthode virtuelle, le destructeur (s'il est défini) doit être obligatoirement virtuel (sinon on risque de n'appeler que le destructeur de la classe mère alors qu'il s'agit d'un objet de la classe fille).

Attention !! Un constructeur ne peut pas être virtuel et il ne peut pas appeler de méthode virtuelle.

Page 42: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Classe abstraite

class X{public:

virtual void a() = 0;virtual void b() = 0;…

};

class Y : public X {public:

virtual void a() { cout << ‘a’ << endl;}virtual void b() { cout << ‘b’ << endl;}

};

Classe abstraire

Classe non abstrairevirtual est facultatif

L’héritage

Page 43: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Utilisation d’une classe abstraite

L’héritage

class figure

{ public :

virtual void tracer (void)=0;

//fonction virtuelle pure

};

figure F;

figure* Ptr;

Ptr = new figure;

Vision utilisateur

//illégal

//illégal

// légal

Page 44: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Héritage multipleclass X{public:

int i; X(int n) { i = n;}void a() {…};

};class Y {public:

int i;Y(int n) { i=n;}void a() {…}

};

class Z {public:

int j;Z(int n) { j=n;}void b() {…}

};

class T: public X, public Y, public Z {public:

int i; //redéfinition de i!!T(): X(0), Y(0), Z(0) { i =0;}void c() {

j +=1;i +=1;b(); //pas d’ambiguité//a(); //ambiguitéX::a();Y::a();

}};

L’héritage

Page 45: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Héritage multipleclass X{public:

int i; X(int n) { i = n;}void a() {…};

};class Y: public X {public:

int j;Y(int n) { j=n;}void b() {…}

};

class Z: public X {public:

int k;Z(int n) { k=n;}void c() {…}

};

class T: public Y, public Z {public:

int l; T(): X(0), Y(0), Z(0) { l = 0;}void d() {

j +=1;k +=1;l +=1;//i +=1; //ambiguitéY::i +=1;Z::i +=1;//a(); //ambiguitéY::a();Z::a();

}};

L’héritage

Page 46: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Héritage multipleclass X{public:

int i; X(int n) { i = n;}void a() {…};

};class Y: virtual public X {public:

int j;Y(int n) { j=n;}void b() {…}

};

class Z: virtual public X {public:

int k;Z(int n) { k=n;}void c() {…}

};

class T: virtual public Y, virtual public Z {public:

int l; T(): X(0), Y(0), Z(0) { l = 0;}void d() {

j +=1;k +=1;l +=1;i +=1; a();

}};

L’héritage

Page 47: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Résumé et synthèse

Héritage

Une classe B peut dériver d’une classe mère A : tout objet de type B hérite alors des attributs et fonctions membres d’un objet parent. En C++, l’héritage peut être multiple : une classe fille peut avoir plusieurs classes mères.

Règles d’héritage

Constructeursjamais hérités

Méthodeshéritéespeuvent être redéfinies (overriding) :la nouvelle méthode remplace celle de la superclasse! ne pas confondre surcharge et redéfinition !

Variableshéritéespeuvent être surajoutées (shadowing) :la nouvelle variable cache celle de la superclasse! à éviter : source de confusions !

Page 48: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Accès à la classe mère

Comme pour les membres, une classe mère A peut être dérivée de manière public, protected ou private :

class X: public A { ... } ; // X est un sous-type de A.class Y: protected A { ... } ; // Héritage d’implémentation: Y et Zclass Z: private A { ... } ; // restreignent l’interface de A.

– X: public A : tous les membres publics et protégés de A peuvent être utilisés par n’importe quelle fonction manipulant un X. C’est la dérivation la plus commune : “X est un A”. Tout objet de type X* peut être converti en A*.

– Y: protected A : les membres publics et protégés de A ne peuvent être utilisés que par les fonctions membres et amies de Y ou des classes YY qui dérivent de Y. Seules ces fonctions peuvent convertir un objet de type Y* en A*.

– Z: private A : les membres publics et protégés de A ne peuvent être utilisés que par les fonctions membres et amies de Z. Seules ces fonctions peuvent convertir un objet de type Y* en A*.

Résumé et synthèse

Page 49: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Règles d’héritage

Constructeursjamais hérités

Méthodeshéritéespeuvent être redéfinies (overriding) :la nouvelle méthode remplace celle de la superclasse! ne pas confondre surcharge et redéfinition !

Variableshéritéespeuvent être surajoutées (shadowing) :la nouvelle variable cache celle de la superclasse! à éviter : source de confusions !

Résumé et synthèse

Page 50: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Fonctions membres virtuelles

Une classe dérivée peut remplacer les fonctions membres de sa classe mère. En C++, on parle de membre virtuel : virtual.

class A {public:

int zero() { return 0 ; }virtual int un() { return 1 ; }

};

class B: public A {public:

int zero() { return 1 ; }int un() { return 0 ; }

};

int main() {A a ;B b ;A &ref_A = a ;ref_A.zero() ; // retourne 0ref_A.un() ; // retourne 1

A *pt_A ; pt_A = &b ; // possible car la dérivation est publique. pt_A->zero() ; // retourne 0: la fonction est prise dans A car // pt_A est un pointeur sur un objet de type A et zero n’est pas //virtuelle. pt_A->un() ; // retourne 0: la fonction est virtuelle et prise // dans B car pt_A pointe en fait sur un B. pt_A = &a ; pt_A->zero() ; // retourne 0. pt_A->un() ; // retourne 1. return 0;}

Résumé et synthèse

Page 51: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Polymorphisme par sous-typage

L’idée est de partir d’un type et de le modifier. Par exemple, en C++ on peut créer une classe de base, puis faire des classes dérivées.

class Forme { public: virtual float Aire() = 0; };

class Carre : public Forme {public: Carre(int a){ m_cote = a;}

virtual float Aire() { return m_cote*m_cote; }private: float m_cote;};

class Cercle : public Forme {public: Cercle(int r){ m_rayon = r;}

virtual float Aire() { return 3.1415926535*m_rayon*m_rayon; }private: float m_rayon;};

Résumé et synthèse

Page 52: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Polymorphisme par sous-typage

Grâce aux fonctions virtuelles, on peut faire un algorithme en n’utilisant que la classe de base qui va automatiquement appeler les fonctions des classes dérivées:

float AireTotale(Forme** tabl, int nb) {float s=0;for(int i = 0; i<nb; ++i) {s+= tabl[i]->Aire(); // par la table des fonctions virtuelle}return s;

}...Forme* tableau[3] = {new Carre(2), new Cercle(1), new Carre(2)};cout << AireTotale(tableau,3); // on aura 11.1416

En proposant d’utiliser un même nom de méthode pour plusieurs types d’objets différents, le polymorphisme permet une programmation beaucoup plus générique. Le développeur n’a pas à savoir, lorsqu’il programme une méthode, le type précis de l’objet sur lequel la méthode va s’appliquer. Il lui suffit de savoir que cet objet implémentera la méthode.

Résumé et synthèse

Page 53: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Construction de l’objet parent

Les constructeurs d’une classe mère ne sont pas hérités. Lors de la construction d’un objet d’une classe dérivé, il est possible de construire l’objet parent en appelant le constructeur de la classe mère. C’est la seule façon de construire les attributs hérités.

class A {private:

int a ;public:

A( int n ) { a = n ; }};

class B: public A {public:

B( int n ) : A(n) { /*...*/ }};

Résumé et synthèse

Page 54: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Fonctions virtuelles pures

Une classe mère peut définir une fonction membre sans en donner d’implémentation: cette implémentation est laissée aux classes filles. On parle alors de fonction virtuelle pure.

class A {public:

virtual void f (int i) = 0 ; // f est virtuelle pure.};

class B: public A {public:

void f ( int i) { /* Implémentation de f */ }};

Une classe dont un membre au moins est virtuel pur est dite abstraite ; on ne peut Créer d’objets de cette classe (seulement des pointeurs peuvent être manipulés).Une classe dont tous les membres sont virtuels purs sert à définir une interface.

Résumé et synthèse

Page 55: Structures de données IFT-2000 Abder Alikacem L’héritage en C++ Département d’informatique et de génie logiciel Édition Septembre 2009

Héritage multiple

Une classe peut hériter de plusieurs classes. La gestion des ambiguïtés se fait explicitement en utilisant :: ou en indiquant les classe mères moins prioritaires par virtual. Dans le cas d’une telle dérivation virtuelle, les attributs hérités d’une même classe mère virtuelle suivant deux branches d’héritage distinctes ne sont pas dupliqués. Le constructeur d’une classe mère virtuelle est appelé une seule fois lors de la construction d’un objet dérivé (il n’y a qu’un objet de la classe mère).class A {

public:int a;// ...

};class B: public virtual A { // ... };class C: public virtual A { // ... };class D: public virtual B, public virtual C {// L’objet n’a qu’un objet parent de type A (donc un seul attribut a)}

Résumé et synthèse