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