• Aucun résultat trouvé

Requalification des qualifications d'accès dans les classes dérivées

12. L'HÉRITAGE EN LANGAGE C++

12.4 QUALIFICATION DE L'HÉRITAGE

12.4.5 Requalification des qualifications d'accès dans les classes dérivées

class Derivee : public Base {int Derivee_b;

public:

Derivee() : Derivee_b(0) {...} // 2 constructeurs de la classe dérivée Derivee(int i, int j): Base(i), Derivee_b(j) {...}

// la partie héritée est anonyme. On utilise donc son nom de type pour l'adresser.

};

12.4.4 Transtypage selon la qualification de l'héritage

Héritage qualifié public

 La classe dérivée peut être considérée comme sa classe de base si et seulement si l'héritage est qualifié public.

 Toutes les propriétés des objets accessibles de la classe de base s'appliquent aux objets qui en sont dérivés dans la classe fille.

Corollaire

Quand l'héritage de la classe de base est qualifiée public, il est licite d'effectuer un transtypage implicite d'un objet de la classe dérivée vers la classe de base.

Héritage qualifié privé ou protégé

 Quand l'héritage est qualifié private ou protected, la classe dérivée peut être considérée comme

"presque pareille mais pas tout à fait identique à sa classe de base".

 Toutes les propriétés des objets de la classe de base pouvant ne pas s'appliquer à ceux de la classe dérivée, un transtypage implicite de la classe dérivée vers la classe de base ou réciproquement est interdit.

12.4.5 Requalification des qualifications d'accès dans les classes dérivées

Position du problème

Quand l’héritage de la classe de base est qualifié private ou protected, le développeur de la classe dérivée peut souhaiter rendre public certaines données membres dérivées de la classe de base. Deux solutions :

 redéfinir une fonction similaire dans la classe dérivée appelant la méthode correspondante de la classe de base voulue,

requalifier l'accès aux objets concernés.

Exemple class list { // ...

146

public:void add(int);

void remove(int);

void print();

};

class linkedlist : private list { // héritage qualifié privé

protected: list::remove; // la méthode (private) remove requalifiée protected public: list::add; // la méthode (private) add requalifiée public

}; // la méthode print reste qualifiée private

class list public :

add(), remove(), print();

Héritage qualifié private

linkedlist

public : add() //requalifiée protected : remove // requalifiée private : print() // défaut

Limites à la requalification des qualifications d'accès

La requalification des qualifications d'accès ne peut pas être utilisé pour :

 élargir les droits définis dans la classe de base : private vers protected ou protected vers public,

 restreindre les droits définis dans la classe de base en cas de dérivation public.

Conclusion

 La requalification des droits permet de modifier les qualifications d'accès de certains membres des effets d'une dérivation qualifiée private ou protected.

 La dispense ne porte que sur l'identificateur.

 Il est interdit de requalifier les fonctions et opérateurs surchargés.

Exercices : analyser les programmes suivants

#include <iostream.h>

#include <string.h>

#include <stdlib.h>

const int NbMaxCarac = 25;

class Produit {// version simplifiée pour l'introduction de l'héritage private:

char nom[NbMaxCarac+1];

float prix;

void fixeNom (const char * Texte);

147

public:

Produit (char * Nom, float Prix) // constructeur de la classe Produit {fixeNom(Nom); prix = Prix;}

void AfficheToi()

{cout << "Produit " << nom <<"\tprix: " << prix << endl;}

}; // fin de la définition de la classe Produit void Produit::fixeNom (const char * Texte) {strncpy (nom, Texte, NbMaxCarac);

nom[NbMaxCarac] = '\0';

} // void fixeNom (const char * Texte) class ProduitPerissable : public Produit

{private: int nombreDeJours; // durée de conservation public:

ProduitPerissable (char * Nom, int Duree, float Prix) : Produit (Nom, Prix)

// Le constructeur de la classe ProduitPerissable dérive de celui de la classe Produit // pour les champs Nom, Prix

{nombreDeJours = Duree;}

}; // fin de la définition de la classe ProduitPerissable int main()

{ Produit P1("SAVON",7.5);

P1.AfficheToi();

ProduitPerissable P2("YAOURT", 15, 12.5);

P2.AfficheToi(); // P2 est affiché comme un Produit return 1;

} // fin de main // résultat

Produit SAVON prix: 7.5 Produit YAOURT prix: 12.5

Exercice 2

#include <iostream.h>

#include <string.h>

#include <stdlib.h>

const int NbMaxCarac = 25;

// Dans cet exemple, la classe dérivée redéfinit la fonction membre AfficheToi class Produit {// version simplifiée pour l'introduction de l'héritage

private:

char nom[NbMaxCarac+1];

float prix;

void fixeNom (const char * Texte);

148

public:

Produit (char * Nom, float Prix) {fixeNom(Nom); prix = Prix;}

void AfficheToi()

{cout << "Produit " << nom <<"\tprix: " << prix << endl;}

}; // fin de la définition de la classe Produit void Produit::fixeNom (const char * Texte) {strncpy (nom, Texte, NbMaxCarac);

nom[NbMaxCarac] = '\0';

}

class ProduitPerissable : public Produit { private:

int nombreDeJours; // durée de conservation public:

ProduitPerissable (char * Nom, int Duree, float Prix): Produit (Nom, Prix) {nombreDeJours = Duree;}

void AfficheToi()

{// on redéfinit la fonction membre AfficheToi

Produit::AfficheToi(); // la fonction membre de la classe de base reste utilisable cout << "\tvalidité: " << nombreDeJours << " jours" << endl ;

}

}; // fin de la définition de la classe ProduitPerissable int main()

{ Produit P1("SAVON",7.5);

P1.AfficheToi();

ProduitPerissable P2("YAOURT", 15, 12.5);

P2.AfficheToi(); // P2 a un comportement d'affichage propre à sa classe P2.Produit::AfficheToi(); // P2 peut toujours avoir un comportement de Produit return 1;

} // fin de main // résultat

Produit SAVON prix: 7.5 Produit YAOURT prix: 12.5

validité: 15 jours

Produit YAOURT prix: 12.5

Exercice 3

// Dans cet exemple, la classe dérivée redéfinit la fonction membre AfficheToi

#include <iostream.h>

#include <string.h>

149

#include <stdlib.h>

const int NbMaxCarac = 25;

class Produit { // version simplifiée pour l'introduction de l'héritage protected:

char nom[NbMaxCarac+1];

float prix;

void fixeNom (const char * Texte);

public:

Produit (char * Nom, float Prix) {fixeNom(Nom); prix = Prix;}

void AfficheToi()

{cout << "Produit " << nom <<"\tprix: " << prix << endl;}

}; // fin de la définition de la classe Produit void Produit::fixeNom (const char * Texte) {strncpy (nom, Texte, NbMaxCarac);

nom[NbMaxCarac] = '\0';

}

class ProduitPerissable : private Produit {

private: int nombreDeJours; // durée de conservation public:

ProduitPerissable (char * Nom, int Duree, float Prix) : Produit (Nom, Prix) {nombreDeJours = Duree;}

void AfficheToi() // redéfinition de la fonction membre AfficheToi

{Produit::AfficheToi(); // la fonction membre de la classe de base reste utilisable cout << "\tvalidité: " << nombreDeJours << " jours" << endl ;

}

void PrixEtDuree()

{cout << prix <<"F, " << nombreDeJours << " jours" << endl ;}

}; // fin de la définition de la classe ProduitPerissable int main()

{Produit P1("SAVON",7.5);

P1.AfficheToi();

ProduitPerissable P2("YAOURT", 15, 12.5);

P2.AfficheToi(); // P2 a un comportement d'affichage propre à sa classe P2.PrixEtDuree();

return 1;

150

} // fin de main // résultat

Produit SAVON prix: 7.5 Produit YAOURT prix: 12.5

validité: 15 jours 12.5F, 15 jours

Exercice 4

#include <iostream.h>

class mere1 {int m1;

public:

mere1(){}

mere1(int i) {cout << "constructeur mère 1 "<< endl; m1=i;}

void affiche() {cout<< "m1=" << m1 << endl;}

};

class mere2 {int m2;

public:

mere2(){}

mere2(int i2) {m2=i2;}

void affiche() {cout<< "m2=" << m2<< endl;}

};

class fille : mere1, mere2 {public :

fille(){}

fille(int i1,int i2): mere1(i1),mere2(i2) {cout << "constructeur fille" << endl;}

void affiche() {mere1::affiche(); mere2::affiche();}

};

class petitefille : fille {public:

petitefille(int i1,int i2): fille (i1,i2) {cout << "constructeur petitefille" << endl;}

public : fille::affiche;

};

int main() {fille f(2,3);

f.affiche();

petitefille pf(4,5) ;

151

pf.affiche();

}

// résultat

constructeur mère 1 constructeur fille m1=2

m2=3

constructeur mère 1 constructeur fille constructeur petitefille m1=4

m2=5